Add sign & verify api calls (#1218)

This commit is contained in:
Andrea Maria Piana 2018-09-27 15:07:32 +02:00 committed by GitHub
parent 9e7643dfb0
commit b309718fdc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 164 additions and 14 deletions

View File

@ -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)
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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,