Skip to content

Commit

Permalink
crypto/signer/verifier
Browse files Browse the repository at this point in the history
Signed-off-by: Viktor Nosov <[email protected]>
  • Loading branch information
Viktor Nosov committed Jun 25, 2024
1 parent 8cb2d28 commit 1bc6c8c
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 60 deletions.
25 changes: 25 additions & 0 deletions extensions/envelope/crypto/crypto.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package crypto

type (
Crypto interface {
Signer
Hasher
Verifier

GenerateKey() (publicKey, privateKey []byte, err error)
PublicKey(privateKey []byte) ([]byte, error)
}

Signer interface {
Sign(privateKey, hash []byte) ([]byte, error)
}

Hasher interface {
Hash([]byte) []byte
}

Verifier interface {
Verify(publicKey, hash, signature []byte) error
Hasher
}
)
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package envelope_test
package crypto_test

import (
"testing"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

"github.com/hyperledger-labs/cckit/extensions/envelope"
"github.com/hyperledger-labs/cckit/extensions/envelope/crypto"
)

const (
Expand All @@ -13,20 +15,25 @@ const (
Ed25519SignatureLen = 64
)

func TestCrypto(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Crypto suite")
}

var _ = Describe(`Ed25519 crypto`, func() {

crypto := envelope.NewEd25519()
ed25519 := crypto.NewEd25519()

It("Allow to create keys", func() {
publicKey, privateKey, err := crypto.GenerateKey()
publicKey, privateKey, err := ed25519.GenerateKey()
Expect(err).NotTo(HaveOccurred())
Expect(len(publicKey)).To(Equal(Ed25519PublicKeyLen))
Expect(len(privateKey)).To(Equal(Ed25519PrivateKeyLen))
})

It("Allow to create signature", func() {
_, privateKey, _ := crypto.GenerateKey()
sig, err := crypto.Sign(privateKey, []byte(`anything`))
_, privateKey, _ := ed25519.GenerateKey()
sig, err := ed25519.Sign(privateKey, []byte(`anything`))
Expect(err).NotTo(HaveOccurred())
Expect(len(sig)).To(Equal(Ed25519SignatureLen))
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package envelope
package crypto

import (
"crypto/ed25519"
Expand All @@ -8,14 +8,6 @@ import (
"fmt"
)

type Crypto interface {
GenerateKey() (publicKey, privateKey []byte, err error)
Hash([]byte) []byte
Sign(privateKey, hash []byte) ([]byte, error)
Verify(publicKey, hash, signature []byte) error
PublicKey(privateKey []byte) ([]byte, error)
}

func NewEd25519() *Ed25519 {
return &Ed25519{}
}
Expand Down
39 changes: 20 additions & 19 deletions extensions/envelope/envelope_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"google.golang.org/protobuf/types/known/timestamppb"

e "github.com/hyperledger-labs/cckit/extensions/envelope"
"github.com/hyperledger-labs/cckit/extensions/envelope/crypto"
"github.com/hyperledger-labs/cckit/serialize"
)

Expand All @@ -28,23 +29,23 @@ var (

var _ = Describe(`Envelope`, func() {

crypto := e.NewEd25519()
verifier := e.NewVerifier(crypto)
c := crypto.NewEd25519()
verifier := e.NewVerifier(c)

Describe("Verifier", func() {
It("Allow to verify valid signature", func() {
nonce := e.CreateNonce()
publicKey, privateKey, _ := crypto.GenerateKey()
sig, err := e.Sign(crypto, payload, nonce, channel, chaincode, methodInvoke, deadline.String(), privateKey)
publicKey, privateKey, _ := c.GenerateKey()
sig, err := e.Sign(c, payload, nonce, channel, chaincode, methodInvoke, deadline.String(), privateKey)
Expect(err).NotTo(HaveOccurred())
err = verifier.Verify(payload, nonce, channel, chaincode, methodInvoke, deadline.String(), publicKey, sig)
Expect(err).NotTo(HaveOccurred())
})

It("Disallow to verify signature with invalid payload", func() {
nonce := e.CreateNonce()
publicKey, privateKey, _ := crypto.GenerateKey()
sig, _ := e.Sign(crypto, payload, nonce, channel, chaincode, methodInvoke, deadline.String(), privateKey)
publicKey, privateKey, _ := c.GenerateKey()
sig, _ := e.Sign(c, payload, nonce, channel, chaincode, methodInvoke, deadline.String(), privateKey)
invalidPayload := []byte("invalid payload")
err := verifier.Verify(invalidPayload, nonce, channel, chaincode, methodInvoke, deadline.String(), publicKey, sig)
Expect(err).Should(MatchError(e.ErrSignatureCheckFailed))
Expand All @@ -54,7 +55,7 @@ var _ = Describe(`Envelope`, func() {
Describe("Handle base64 envelop", func() {

It("Allow to parse base64 envelop", func() {
_, envelope := createEnvelope(crypto, payload, channel, chaincode, methodInvoke, deadline)
_, envelope := createEnvelope(c, payload, channel, chaincode, methodInvoke, deadline)
jj, _ := json.Marshal(envelope)
b64 := base64.StdEncoding.EncodeToString(jj)
bb, err := e.DecodeEnvelope([]byte(b64))
Expand All @@ -67,13 +68,13 @@ var _ = Describe(`Envelope`, func() {
Describe("Signature verification", func() {

It("Allow to verify valid signature", func() {
serializedEnvelope, _ := createEnvelope(crypto, payload, channel, chaincode, methodInvoke, deadline)
serializedEnvelope, _ := createEnvelope(c, payload, channel, chaincode, methodInvoke, deadline)
resp := NewNewEnvelopCCMock(verifier).Invoke(methodInvoke, payload, serializedEnvelope)
Expect(resp.Status).To(BeNumerically("==", 200))
})

It("Allow to verify valid signature without deadline", func() {
serializedEnvelope, _ := createEnvelope(crypto, payload, channel, chaincode, methodInvoke)
serializedEnvelope, _ := createEnvelope(c, payload, channel, chaincode, methodInvoke)
resp := NewNewEnvelopCCMock(verifier).Invoke(methodInvoke, payload, serializedEnvelope)
Expect(resp.Status).To(BeNumerically("==", 200))
})
Expand All @@ -99,22 +100,22 @@ var _ = Describe(`Envelope`, func() {
})

It("Disallow to verify signature with invalid payload", func() {
serializedEnvelope, _ := createEnvelope(crypto, payload, channel, chaincode, methodInvoke, deadline)
serializedEnvelope, _ := createEnvelope(c, payload, channel, chaincode, methodInvoke, deadline)
invalidPayload := []byte("invalid payload")

resp := NewNewEnvelopCCMock(verifier).Invoke(methodInvoke, invalidPayload, serializedEnvelope)
Expect(resp.Status).To(BeNumerically("==", 500))
})

It("Disallow to verify signature with invalid method", func() {
serializedEnvelope, _ := createEnvelope(crypto, payload, channel, chaincode, "invalid method", deadline)
serializedEnvelope, _ := createEnvelope(c, payload, channel, chaincode, "invalid method", deadline)

resp := NewNewEnvelopCCMock(verifier).Invoke(methodInvoke, payload, serializedEnvelope)
Expect(resp.Status).To(BeNumerically("==", 500))
})

It("Disallow to verify signature with invalid channel", func() {
serializedEnvelope, _ := createEnvelope(crypto, payload, "invalid channel", chaincode, methodInvoke, deadline)
serializedEnvelope, _ := createEnvelope(c, payload, "invalid channel", chaincode, methodInvoke, deadline)

resp := NewNewEnvelopCCMock(verifier).Invoke(methodInvoke, payload, serializedEnvelope)
Expect(resp.Status).To(BeNumerically("==", 500))
Expand All @@ -129,11 +130,11 @@ var _ = Describe(`Envelope`, func() {

Describe("Nonce verification (replay attack)", func() {
It("Disallow to execute tx with the same parameters (nonce, payload, pubkey)", func() {
publicKey, privateKey, _ := crypto.GenerateKey()
publicKey, privateKey, _ := c.GenerateKey()
nonce := "thesamenonce"

hashToSign := crypto.Hash(e.PrepareToHash(payload, nonce, channel, chaincode, methodInvoke, deadline.AsTime().Format(e.TimeLayout), publicKey))
sig, _ := crypto.Sign(privateKey, hashToSign)
hashToSign := c.Hash(e.PrepareToHash(payload, nonce, channel, chaincode, methodInvoke, deadline.AsTime().Format(e.TimeLayout), publicKey))
sig, _ := c.Sign(privateKey, hashToSign)
envelope := &e.Envelope{
PublicKey: base58.Encode([]byte(publicKey)),
Signature: base58.Encode(sig),
Expand All @@ -159,8 +160,8 @@ var _ = Describe(`Envelope`, func() {

})

func createEnvelope(crypto e.Crypto, payload []byte, channel, chaincode, method string, deadline ...*timestamppb.Timestamp) ([]byte, *e.Envelope) {
publicKey, privateKey, _ := e.NewEd25519().GenerateKey()
func createEnvelope(c crypto.Crypto, payload []byte, channel, chaincode, method string, deadline ...*timestamppb.Timestamp) ([]byte, *e.Envelope) {
publicKey, privateKey, _ := crypto.NewEd25519().GenerateKey()
nonce := e.CreateNonce()

envelope := &e.Envelope{
Expand All @@ -176,10 +177,10 @@ func createEnvelope(crypto e.Crypto, payload []byte, channel, chaincode, method
envelope.Deadline = deadline[0]
formatDeadline = envelope.Deadline.AsTime().Format(e.TimeLayout)
}
hashToSign := crypto.Hash(e.PrepareToHash(payload, nonce, channel, chaincode, method, formatDeadline, publicKey))
hashToSign := c.Hash(e.PrepareToHash(payload, nonce, channel, chaincode, method, formatDeadline, publicKey))
envelope.HashToSign = base58.Encode(hashToSign)

sig, _ := crypto.Sign(privateKey, hashToSign)
sig, _ := c.Sign(privateKey, hashToSign)
envelope.Signature = base58.Encode(sig)

serializedEnvelope, _ := serialize.PreferJSONSerializer.ToBytesFrom(envelope)
Expand Down
28 changes: 2 additions & 26 deletions extensions/envelope/signer.go → extensions/envelope/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,11 @@ import (
"time"

"github.com/btcsuite/btcutil/base58"
)

type (
Verifier interface {
Verify(payload []byte, nonce, channel, chaincode, method, deadline string, publicKey []byte, sig []byte) error
}

DefaultVerifier struct {
crypto Crypto
}
"github.com/hyperledger-labs/cckit/extensions/envelope/crypto"
)

func NewVerifier(crypto Crypto) *DefaultVerifier {
return &DefaultVerifier{crypto: crypto}
}

func Sign(crypto Crypto, payload []byte, nonce, channel, chaincode, method, deadline string, privateKey []byte) ([]byte, error) {
func Sign(crypto crypto.Crypto, payload []byte, nonce, channel, chaincode, method, deadline string, privateKey []byte) ([]byte, error) {
pubKey, err := crypto.PublicKey(privateKey)
if err != nil {
return nil, fmt.Errorf(`extract public key: %w`, err)
Expand Down Expand Up @@ -53,15 +41,3 @@ func removeSpacesBetweenCommaAndQuotes(s []byte) []byte {
removed = strings.ReplaceAll(removed, `"}, {"`, `"},{"`)
return []byte(strings.ReplaceAll(removed, `], "`, `],"`))
}

//func (s *DefaultVerifier) Hash(payload []byte, nonce, channel, chaincode, method, deadline string, pubkey []byte) []byte {
// return s.crypto.Hash(PrepareToHash(payload, nonce, channel, chaincode, method, deadline, pubkey))
//}

func (s *DefaultVerifier) Verify(payload []byte, nonce, channel, chaincode, method, deadline string, pubKey []byte, sig []byte) error {
if err := s.crypto.Verify(pubKey,
s.crypto.Hash(PrepareToHash(payload, nonce, channel, chaincode, method, deadline, pubKey)), sig); err != nil {
return ErrCheckSignatureFailed
}
return nil
}
27 changes: 27 additions & 0 deletions extensions/envelope/verifier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package envelope

import (
"github.com/hyperledger-labs/cckit/extensions/envelope/crypto"
)

type (
Verifier interface {
Verify(payload []byte, nonce, channel, chaincode, method, deadline string, publicKey []byte, sig []byte) error
}

DefaultVerifier struct {
verifier crypto.Verifier
}
)

func NewVerifier(verifier crypto.Verifier) *DefaultVerifier {
return &DefaultVerifier{verifier: verifier}
}

func (s *DefaultVerifier) Verify(payload []byte, nonce, channel, chaincode, method, deadline string, pubKey []byte, sig []byte) error {
if err := s.verifier.Verify(pubKey,
s.verifier.Hash(PrepareToHash(payload, nonce, channel, chaincode, method, deadline, pubKey)), sig); err != nil {
return ErrCheckSignatureFailed
}
return nil
}

0 comments on commit 1bc6c8c

Please sign in to comment.