Add sign & verify api calls (#1218)
This commit is contained in:
parent
9e7643dfb0
commit
b309718fdc
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/status-im/status-go/services/personal"
|
||||
"github.com/status-im/status-go/services/rpcfilters"
|
||||
"github.com/status-im/status-go/services/shhext/chat"
|
||||
"github.com/status-im/status-go/services/shhext/chat/crypto"
|
||||
"github.com/status-im/status-go/signal"
|
||||
"github.com/status-im/status-go/transactions"
|
||||
)
|
||||
|
@ -420,7 +421,7 @@ func (b *StatusBackend) SelectAccount(address, password string) error {
|
|||
}
|
||||
|
||||
if err := st.InitProtocol(address, password); err != nil {
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -499,3 +500,18 @@ func (b *StatusBackend) ExtractIdentityFromContactCode(contactCode string) (stri
|
|||
|
||||
return chat.ExtractIdentity(bundle)
|
||||
}
|
||||
|
||||
// VerifyGroupMembershipSignatures verifies that the signatures are valid
|
||||
func (b *StatusBackend) VerifyGroupMembershipSignatures(signaturePairs [][3]string) error {
|
||||
return crypto.VerifySignatures(signaturePairs)
|
||||
}
|
||||
|
||||
// SignGroupMembership signs a piece of data containing membership information
|
||||
func (b *StatusBackend) SignGroupMembership(content string) (string, error) {
|
||||
selectedAccount, err := b.AccountManager().SelectedAccount()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return crypto.Sign(content, selectedAccount.AccountKey.PrivateKey)
|
||||
}
|
||||
|
|
|
@ -93,6 +93,40 @@ func ExtractIdentityFromContactCode(bundleString *C.char) *C.char {
|
|||
return C.CString(string(data))
|
||||
}
|
||||
|
||||
// VerifyGroupMembershipSignatures ensure the signature pairs are valid
|
||||
//export VerifyGroupMembershipSignatures
|
||||
func VerifyGroupMembershipSignatures(signaturePairsStr *C.char) *C.char {
|
||||
var signaturePairs [][3]string
|
||||
|
||||
if err := json.Unmarshal([]byte(C.GoString(signaturePairsStr)), &signaturePairs); err != nil {
|
||||
return makeJSONResponse(err)
|
||||
}
|
||||
|
||||
if err := statusBackend.VerifyGroupMembershipSignatures(signaturePairs); err != nil {
|
||||
return makeJSONResponse(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sign signs a string containing group membership information
|
||||
//export SignGroupMembership
|
||||
func SignGroupMembership(content *C.char) *C.char {
|
||||
signature, err := statusBackend.SignGroupMembership(C.GoString(content))
|
||||
if err != nil {
|
||||
return makeJSONResponse(err)
|
||||
}
|
||||
|
||||
data, err := json.Marshal(struct {
|
||||
Signature string `json:"signature"`
|
||||
}{Signature: signature})
|
||||
if err != nil {
|
||||
return makeJSONResponse(err)
|
||||
}
|
||||
|
||||
return C.CString(string(data))
|
||||
}
|
||||
|
||||
//ValidateNodeConfig validates config for status node
|
||||
//export ValidateNodeConfig
|
||||
func ValidateNodeConfig(configJSON *C.char) *C.char {
|
||||
|
|
|
@ -3,14 +3,63 @@ package crypto
|
|||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
const (
|
||||
aesNonceLength = 12
|
||||
)
|
||||
|
||||
// Sign signs the hash of an arbitrary string
|
||||
func Sign(content string, identity *ecdsa.PrivateKey) (string, error) {
|
||||
signature, err := crypto.Sign(crypto.Keccak256([]byte(content)), identity)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return hex.EncodeToString(signature), nil
|
||||
}
|
||||
|
||||
// VerifySignatures verifys tuples of signatures content/hash/public key
|
||||
func VerifySignatures(signaturePairs [][3]string) error {
|
||||
for _, signaturePair := range signaturePairs {
|
||||
content := crypto.Keccak256([]byte(signaturePair[0]))
|
||||
|
||||
signature, err := hex.DecodeString(signaturePair[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
publicKeyBytes, err := hex.DecodeString(signaturePair[2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
publicKey, err := crypto.UnmarshalPubkey(publicKeyBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
recoveredKey, err := crypto.SigToPub(
|
||||
content,
|
||||
signature,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if crypto.PubkeyToAddress(*recoveredKey) != crypto.PubkeyToAddress(*publicKey) {
|
||||
return errors.New("identity key and signature mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func EncryptSymmetric(key, plaintext []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
|
|
|
@ -2,42 +2,93 @@ package crypto
|
|||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"fmt"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
key = "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
)
|
||||
func TestVerifySignature(t *testing.T) {
|
||||
const content1 = "045a8cae84d8d139e887bb927d2b98cee481afae3770e0ee45f2dc19c6545e45921bc6a55ea92b705e45dfbbe47182c7b1d64a080a220d2781577163923d7cbb4b045a8cae84d8d139e887bb927d2b98cee481afae3770e0ee45f2dc19c6545e45921bc6a55ea92b705e45dfbbe47182c7b1d64a080a220d2781577163923d7cbb4b04ca82dd41fa592bf46ecf7e2eddae61013fc95a565b59c49f37f06b1b591ed3bd24e143495f2d1e241e151ab3572ac108d577be349d4b88d3d5a50c481ab35441"
|
||||
const content2 = "045a8cae84d8d139e887bb927d2b98cee481afae3770e0ee45f2dc19c6545e45921bc6a55ea92b705e45dfbbe47182c7b1d64a080a220d2781577163923d7cbb4b045a8cae84d8d139e887bb927d2b98cee481afae3770e0ee45f2dc19c6545e45921bc6a55ea92b705e45dfbbe47182c7b1d64a080a220d2781577163923d7cbb4b04ca82dd41fa592bf46ecf7e2eddae61013fc95a565b59c49f37f06b1b591ed3bd24e143495f2d1e241e151ab3572ac108d577be349d4b88d3d5a50c481ab35440"
|
||||
|
||||
var expectedPlaintext = []byte("test")
|
||||
key1, err := crypto.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
key2, err := crypto.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
signature1, err := Sign(content1, key1)
|
||||
require.NoError(t, err)
|
||||
fmt.Println(signature1)
|
||||
|
||||
signature2, err := Sign(content2, key2)
|
||||
require.NoError(t, err)
|
||||
|
||||
key1String := hex.EncodeToString(crypto.FromECDSAPub(&key1.PublicKey))
|
||||
key2String := hex.EncodeToString(crypto.FromECDSAPub(&key2.PublicKey))
|
||||
|
||||
pair1 := [3]string{content1, signature1, key1String}
|
||||
pair2 := [3]string{content2, signature2, key2String}
|
||||
|
||||
signaturePairs := [][3]string{pair1, pair2}
|
||||
|
||||
err = VerifySignatures(signaturePairs)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test wrong content
|
||||
pair3 := [3]string{content1, signature2, key2String}
|
||||
|
||||
signaturePairs = [][3]string{pair1, pair2, pair3}
|
||||
|
||||
err = VerifySignatures(signaturePairs)
|
||||
require.Error(t, err)
|
||||
|
||||
// Test wrong signature
|
||||
pair3 = [3]string{content1, signature2, key1String}
|
||||
|
||||
signaturePairs = [][3]string{pair1, pair2, pair3}
|
||||
|
||||
err = VerifySignatures(signaturePairs)
|
||||
require.Error(t, err)
|
||||
|
||||
// Test wrong pubkey
|
||||
pair3 = [3]string{content1, signature1, key2String}
|
||||
|
||||
signaturePairs = [][3]string{pair1, pair2, pair3}
|
||||
|
||||
err = VerifySignatures(signaturePairs)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestSymmetricEncryption(t *testing.T) {
|
||||
key, err := hex.DecodeString(key)
|
||||
assert.Nil(t, err, "Key should be generated without errors")
|
||||
const rawKey = "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
expectedPlaintext := []byte("test")
|
||||
key, err := hex.DecodeString(rawKey)
|
||||
require.Nil(t, err, "Key should be generated without errors")
|
||||
|
||||
cyphertext1, err := EncryptSymmetric(key, expectedPlaintext)
|
||||
assert.Nil(t, err, "Cyphertext should be generated without errors")
|
||||
require.Nil(t, err, "Cyphertext should be generated without errors")
|
||||
|
||||
cyphertext2, err := EncryptSymmetric(key, expectedPlaintext)
|
||||
assert.Nil(t, err, "Cyphertext should be generated without errors")
|
||||
require.Nil(t, err, "Cyphertext should be generated without errors")
|
||||
|
||||
assert.Equalf(
|
||||
require.Equalf(
|
||||
t,
|
||||
32,
|
||||
len(cyphertext1),
|
||||
"Cyphertext with the correct lenght should be generated")
|
||||
|
||||
assert.NotEqualf(
|
||||
require.NotEqualf(
|
||||
t,
|
||||
cyphertext1,
|
||||
cyphertext2,
|
||||
"Same plaintext should not be encrypted in the same way")
|
||||
|
||||
plaintext, err := DecryptSymmetric(key, cyphertext1)
|
||||
assert.Nil(t, err, "Cyphertext should be decrypted without errors")
|
||||
require.Nil(t, err, "Cyphertext should be decrypted without errors")
|
||||
|
||||
assert.Equalf(
|
||||
require.Equalf(
|
||||
t,
|
||||
expectedPlaintext,
|
||||
plaintext,
|
||||
|
|
Loading…
Reference in New Issue