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/personal"
|
||||||
"github.com/status-im/status-go/services/rpcfilters"
|
"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"
|
||||||
|
"github.com/status-im/status-go/services/shhext/chat/crypto"
|
||||||
"github.com/status-im/status-go/signal"
|
"github.com/status-im/status-go/signal"
|
||||||
"github.com/status-im/status-go/transactions"
|
"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 {
|
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)
|
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))
|
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
|
//ValidateNodeConfig validates config for status node
|
||||||
//export ValidateNodeConfig
|
//export ValidateNodeConfig
|
||||||
func ValidateNodeConfig(configJSON *C.char) *C.char {
|
func ValidateNodeConfig(configJSON *C.char) *C.char {
|
||||||
|
|
|
@ -3,14 +3,63 @@ package crypto
|
||||||
import (
|
import (
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
|
"crypto/ecdsa"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
aesNonceLength = 12
|
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) {
|
func EncryptSymmetric(key, plaintext []byte) ([]byte, error) {
|
||||||
block, err := aes.NewCipher(key)
|
block, err := aes.NewCipher(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -2,42 +2,93 @@ package crypto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"github.com/stretchr/testify/assert"
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
func TestVerifySignature(t *testing.T) {
|
||||||
key = "0000000000000000000000000000000000000000000000000000000000000000"
|
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) {
|
func TestSymmetricEncryption(t *testing.T) {
|
||||||
key, err := hex.DecodeString(key)
|
const rawKey = "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
assert.Nil(t, err, "Key should be generated without errors")
|
expectedPlaintext := []byte("test")
|
||||||
|
key, err := hex.DecodeString(rawKey)
|
||||||
|
require.Nil(t, err, "Key should be generated without errors")
|
||||||
|
|
||||||
cyphertext1, err := EncryptSymmetric(key, expectedPlaintext)
|
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)
|
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,
|
t,
|
||||||
32,
|
32,
|
||||||
len(cyphertext1),
|
len(cyphertext1),
|
||||||
"Cyphertext with the correct lenght should be generated")
|
"Cyphertext with the correct lenght should be generated")
|
||||||
|
|
||||||
assert.NotEqualf(
|
require.NotEqualf(
|
||||||
t,
|
t,
|
||||||
cyphertext1,
|
cyphertext1,
|
||||||
cyphertext2,
|
cyphertext2,
|
||||||
"Same plaintext should not be encrypted in the same way")
|
"Same plaintext should not be encrypted in the same way")
|
||||||
|
|
||||||
plaintext, err := DecryptSymmetric(key, cyphertext1)
|
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,
|
t,
|
||||||
expectedPlaintext,
|
expectedPlaintext,
|
||||||
plaintext,
|
plaintext,
|
||||||
|
|
Loading…
Reference in New Issue