Skip to content

Commit

Permalink
remove old we viewingkey format support
Browse files Browse the repository at this point in the history
  • Loading branch information
zkokelj committed Jan 16, 2024
1 parent 16173af commit c86ac89
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 61 deletions.
51 changes: 21 additions & 30 deletions go/common/viewingkey/viewing_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,6 @@ import (
gethcommon "github.com/ethereum/go-ethereum/common"
)

// SignedMsgPrefix is the prefix added when signing the viewing key in MetaMask using the personal_sign
// API. Why is this needed? MetaMask has a security feature whereby if you ask it to sign something that looks like
// a transaction using the personal_sign API, it modifies the data being signed. The goal is to prevent hackers
// from asking a visitor to their website to personal_sign something that is actually a malicious transaction (e.g.
// theft of funds). By adding a prefix, the viewing key bytes no longer looks like a transaction hash, and thus get
// signed as-is.
const SignedMsgPrefix = "vk"

const (
EIP712Domain = "EIP712Domain"
EIP712Type = "Authentication"
Expand All @@ -39,6 +31,7 @@ const (
EIP712DomainNameValue = "Ten"
EIP712DomainVersionValue = "1.0"
UserIDHexLength = 40
TenChainID = 443
)

// EIP712EncryptionTokens is a list of all possible options for Encryption token name
Expand All @@ -60,22 +53,24 @@ type ViewingKey struct {
func GenerateViewingKeyForWallet(wal wallet.Wallet) (*ViewingKey, error) {
// generate an ECDSA key pair to encrypt sensitive communications with the obscuro enclave
vk, err := crypto.GenerateKey()
viewingPrivateKeyECIES := ecies.ImportECDSA(vk)
if err != nil {
return nil, fmt.Errorf("failed to generate viewing key for RPC client: %w", err)
return nil, err
}

// get key in ECIES format
viewingPrivateKeyECIES := ecies.ImportECDSA(vk)

// encode public key as bytes
viewingPubKeyBytes := crypto.CompressPubkey(&vk.PublicKey)

// create encryptionToken and store it in the database with the private key
ecdsaPublicKey := viewingPrivateKeyECIES.PublicKey.ExportECDSA()
compressedPubKey := crypto.CompressPubkey(ecdsaPublicKey)
encToken := CalculateUserID(compressedPubKey)
// sign public key bytes with the wallet's private key
signature, err := mmSignViewingKey(viewingPubKeyBytes, wal.PrivateKey())
signature, err := mmSignViewingKey(hex.EncodeToString(encToken), wal.PrivateKey())
if err != nil {
return nil, err
}

// encode public key as bytes
viewingPubKeyBytes := crypto.CompressPubkey(&vk.PublicKey)

accAddress := wal.Address()
return &ViewingKey{
Account: &accAddress,
Expand All @@ -85,10 +80,10 @@ func GenerateViewingKeyForWallet(wal wallet.Wallet) (*ViewingKey, error) {
}, nil
}

// mmSignViewingKey takes a public key bytes as hex and the private key for a wallet, it simulates the back-and-forth to
// mmSignViewingKey takes an encryptionToken and the private key for a wallet, it simulates the back-and-forth to
// MetaMask and returns the signature bytes to register with the enclave
func mmSignViewingKey(viewingPubKeyBytes []byte, signerKey *ecdsa.PrivateKey) ([]byte, error) {
signature, err := Sign(signerKey, viewingPubKeyBytes)
func mmSignViewingKey(encryptionToken string, signerKey *ecdsa.PrivateKey) ([]byte, error) {
signature, err := Sign(signerKey, encryptionToken)
if err != nil {
return nil, fmt.Errorf("failed to sign viewing key: %w", err)
}
Expand All @@ -111,23 +106,19 @@ func mmSignViewingKey(viewingPubKeyBytes []byte, signerKey *ecdsa.PrivateKey) ([
return outputSig, nil
}

// Sign takes a users Private key and signs the public viewingKey hex
func Sign(userPrivKey *ecdsa.PrivateKey, vkPubKey []byte) ([]byte, error) {
msgToSign := GenerateSignMessage(vkPubKey)
signature, err := crypto.Sign(accounts.TextHash([]byte(msgToSign)), userPrivKey)
// Sign takes a users Private key and signs the encryption token
func Sign(userPrivKey *ecdsa.PrivateKey, encryptionToken string) ([]byte, error) {
messages, err := GenerateAuthenticationEIP712RawDataOptions(encryptionToken, TenChainID)
if err != nil || len(messages) == 0 {
return nil, err
}
signature, err := crypto.Sign(accounts.TextHash(messages[0]), userPrivKey)
if err != nil {
return nil, fmt.Errorf("unable to sign messages - %w", err)
}
return signature, nil
}

// GenerateSignMessage creates the message to be signed
// vkPubKey is expected to be a []byte("0x....") to create the signing message
// todo (@ziga) Remove this method once old WE endpoints are removed
func GenerateSignMessage(vkPubKey []byte) string {
return SignedMsgPrefix + hex.EncodeToString(vkPubKey)
}

// getBytesFromTypedData creates EIP-712 compliant hash from typedData.
// It involves hashing the message with its structure, hashing domain separator,
// and then encoding both hashes with specific EIP-712 bytes to construct the final message format.
Expand Down
19 changes: 2 additions & 17 deletions go/enclave/vkhandler/vk_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"crypto/rand"
"fmt"

"github.com/ethereum/go-ethereum/accounts"
gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ten-protocol/go-ten/go/common/viewingkey"
Expand All @@ -28,28 +27,14 @@ type VKHandler struct {

// New creates a new viewing key handler if signature is valid and was produced by given address
// It receives address, viewing key and a signature over viewing key.
// In order to check signature validity, we need to reproduce a message that was originally signed
// To check the signature validity, we need to reproduce a message that was originally signed
func New(requestedAddr *gethcommon.Address, vkPubKeyBytes, accountSignatureHexBytes []byte, chainID int64) (*VKHandler, error) {
// get userID from viewingKey public key
userID := viewingkey.CalculateUserIDHex(vkPubKeyBytes)

// check if the signature is valid
// TODO: @ziga - after removing old wallet extension signatures we can return if the signature is invalid
isValidSignature, _ := viewingkey.VerifySignatureEIP712(userID, requestedAddr, accountSignatureHexBytes, chainID)

// Old wallet extension message format
// We recover the key based on the signed message and the signature (same as before, but with legacy message format "vk"+<vk>"
// todo (@ziga) remove support of old message format when removing old wallet extension endpoints (#2134)
msgToSignLegacy := viewingkey.GenerateSignMessage(vkPubKeyBytes)
recoveredAccountPublicKeyLegacy, err := crypto.SigToPub(accounts.TextHash([]byte(msgToSignLegacy)), accountSignatureHexBytes)
if err != nil {
return nil, fmt.Errorf("viewing key but could not validate its signature - %w", err)
}
recoveredAccountAddressLegacy := crypto.PubkeyToAddress(*recoveredAccountPublicKeyLegacy)

// is the requested account address the same as the address recovered from the signature
if requestedAddr.Hash() != recoveredAccountAddressLegacy.Hash() &&
!isValidSignature {
if !isValidSignature {
return nil, ErrInvalidAddressSignature
}

Expand Down
5 changes: 0 additions & 5 deletions go/enclave/vkhandler/vk_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package vkhandler
import (
"testing"

"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/stretchr/testify/assert"
Expand All @@ -27,7 +26,6 @@ func TestVKHandler(t *testing.T) {
}
vkPubKeyBytes := crypto.CompressPubkey(ecies.ImportECDSAPublic(&vkPrivKey.PublicKey).ExportECDSA())
userID := viewingkey.CalculateUserIDHex(vkPubKeyBytes)
WEMessageFormatTestHash := accounts.TextHash([]byte(viewingkey.GenerateSignMessage(vkPubKeyBytes)))
EIP712MessageDataOptions, err := viewingkey.GenerateAuthenticationEIP712RawDataOptions(userID, chainID)
if err != nil {
t.Fatalf(err.Error())
Expand All @@ -38,7 +36,6 @@ func TestVKHandler(t *testing.T) {
EIP712MessageFormatTestHash := crypto.Keccak256(EIP712MessageDataOptions[0])

tests := map[string][]byte{
"WEMessageFormatTest": WEMessageFormatTestHash,
"EIP712MessageFormatTest": EIP712MessageFormatTestHash,
}

Expand Down Expand Up @@ -69,15 +66,13 @@ func TestSignAndCheckSignature(t *testing.T) {
}
vkPubKeyBytes := crypto.CompressPubkey(ecies.ImportECDSAPublic(&vkPrivKey.PublicKey).ExportECDSA())
userID := viewingkey.CalculateUserIDHex(vkPubKeyBytes)
WEMessageFormatTestHash := accounts.TextHash([]byte(viewingkey.GenerateSignMessage(vkPubKeyBytes)))
EIP712MessageData, err := viewingkey.GenerateAuthenticationEIP712RawDataOptions(userID, chainID)
if err != nil {
t.Fatalf(err.Error())
}
EIP712MessageFormatTestHash := crypto.Keccak256(EIP712MessageData[0])

tests := map[string][]byte{
"WEMessageFormatTest": WEMessageFormatTestHash,
"EIP712MessageFormatTest": EIP712MessageFormatTestHash,
}

Expand Down
11 changes: 2 additions & 9 deletions tools/walletextension/test/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"testing"
"time"

"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-kit/kit/transport/http/jsonrpc"
"github.com/gorilla/websocket"
Expand Down Expand Up @@ -218,14 +217,8 @@ func generateViewingKey(wallHTTPPort, wallWSPort int, accountAddress string, use

// Signs a viewing key like metamask
func signViewingKey(privateKey *ecdsa.PrivateKey, compressedHexVKBytes []byte) []byte {
// compressedHexVKBytes already has the key in the hex format
// it should be decoded back into raw bytes
viewingKey, err := hex.DecodeString(string(compressedHexVKBytes))
if err != nil {
panic(err)
}
msgToSign := viewingkey.GenerateSignMessage(viewingKey)
signature, err := crypto.Sign(accounts.TextHash([]byte(msgToSign)), privateKey)
encToken := hex.EncodeToString(crypto.Keccak256Hash(compressedHexVKBytes).Bytes()[:20])
signature, err := viewingkey.Sign(privateKey, encToken)
if err != nil {
panic(err)
}
Expand Down

0 comments on commit c86ac89

Please sign in to comment.