diff --git a/core/crypto/bccsp/bccsp.go b/core/crypto/bccsp/bccsp.go index 81e745858f0..74486057cf3 100644 --- a/core/crypto/bccsp/bccsp.go +++ b/core/crypto/bccsp/bccsp.go @@ -16,7 +16,10 @@ limitations under the License. package bccsp -import "crypto" +import ( + "crypto" + "hash" +) // Key represents a cryptographic key type Key interface { @@ -114,8 +117,13 @@ type BCCSP interface { GetKey(ski []byte) (k Key, err error) // Hash hashes messages msg using options opts. + // If opts is nil, the default hash function will be used. Hash(msg []byte, opts HashOpts) (hash []byte, err error) + // GetHash returns and instance of hash.Hash using options opts. + // If opts is nil, the default hash function will be returned. + GetHash(opts HashOpts) (h hash.Hash, err error) + // Sign signs digest using key k. // The opts argument should be appropriate for the algorithm used. // diff --git a/core/crypto/bccsp/bccsp_opts.go b/core/crypto/bccsp/bccsp_opts.go index 8e8466a672f..3033931dc06 100644 --- a/core/crypto/bccsp/bccsp_opts.go +++ b/core/crypto/bccsp/bccsp_opts.go @@ -45,6 +45,9 @@ const ( // X509Certificate Label for X509 certificate realted operation X509Certificate = "X509Certificate" + + // DefaultHash is the identifier for the default hash function (see primitives package) + DefaultHash = "DEFAULT_HASH" ) // ECDSAKeyGenOpts contains options for ECDSA key generation. diff --git a/core/crypto/bccsp/sw/impl.go b/core/crypto/bccsp/sw/impl.go index 0b3f9dedf5c..1bdd4a428ae 100644 --- a/core/crypto/bccsp/sw/impl.go +++ b/core/crypto/bccsp/sw/impl.go @@ -26,6 +26,8 @@ import ( "crypto/rsa" + "hash" + "github.com/hyperledger/fabric/core/crypto/bccsp" "github.com/hyperledger/fabric/core/crypto/primitives" "github.com/hyperledger/fabric/core/crypto/utils" @@ -463,17 +465,32 @@ func (csp *impl) GetKey(ski []byte) (k bccsp.Key, err error) { // Hash hashes messages msg using options opts. func (csp *impl) Hash(msg []byte, opts bccsp.HashOpts) (hash []byte, err error) { if opts == nil { - return nil, errors.New("Invalid Opts parameter. It must not be nil.") + return primitives.Hash(msg), nil } switch opts.Algorithm() { - case bccsp.SHA: + case bccsp.DefaultHash, bccsp.SHA: return primitives.Hash(msg), nil default: return nil, fmt.Errorf("Algorithm not recognized [%s]", opts.Algorithm()) } } +// GetHash returns and instance of hash.Hash using options opts. +// If opts is nil then the default hash function is returned. +func (csp *impl) GetHash(opts bccsp.HashOpts) (h hash.Hash, err error) { + if opts == nil { + return primitives.NewHash(), nil + } + + switch opts.Algorithm() { + case bccsp.SHA, bccsp.DefaultHash: + return primitives.NewHash(), nil + default: + return nil, fmt.Errorf("Algorithm not recognized [%s]", opts.Algorithm()) + } +} + // Sign signs digest using key k. // The opts argument should be appropriate for the primitive used. // diff --git a/core/crypto/bccsp/sw/impl_test.go b/core/crypto/bccsp/sw/impl_test.go index 317ea50bd3d..58d285865f9 100644 --- a/core/crypto/bccsp/sw/impl_test.go +++ b/core/crypto/bccsp/sw/impl_test.go @@ -1245,3 +1245,49 @@ func TestKeyImportFromX509RSAPublicKey(t *testing.T) { t.Fatal("Failed verifying RSA signature. Signature not valid.") } } + +func TestGetHashAndHashCompatibility(t *testing.T) { + csp := getBCCSP(t) + + msg1 := []byte("abcd") + msg2 := []byte("efgh") + msg := []byte("abcdefgh") + + digest1, err := csp.Hash(msg, &bccsp.SHAOpts{}) + if err != nil { + t.Fatalf("Failed computing HASH [%s]", err) + } + + digest2, err := csp.Hash(msg, nil) + if err != nil { + t.Fatalf("Failed computing HASH [%s]", err) + } + + if !bytes.Equal(digest1, digest2) { + t.Fatalf("Different hash computed. [%x][%x]", digest1, digest2) + } + + h, err := csp.GetHash(nil) + if err != nil { + t.Fatalf("Failed getting hash.Hash instance [%s]", err) + } + h.Write(msg1) + h.Write(msg2) + digest3 := h.Sum(nil) + + h2, err := csp.GetHash(&bccsp.SHAOpts{}) + if err != nil { + t.Fatalf("Failed getting SHA hash.Hash instance [%s]", err) + } + h2.Write(msg1) + h2.Write(msg2) + digest4 := h2.Sum(nil) + + if !bytes.Equal(digest3, digest4) { + t.Fatalf("Different hash computed. [%x][%x]", digest3, digest4) + } + + if !bytes.Equal(digest1, digest3) { + t.Fatalf("Different hash computed. [%x][%x]", digest1, digest3) + } +}