Skip to content

Commit 1b7b163

Browse files
committed
[FAB-3441] bccsp/sw Hash test coverage
Using the approach discussed in FAB-3465, this change-sets refactors the way hashing is done at bccsp/sw. Essentially, the switch has been replaced by a map. The approach decouples the testing of the bccsp interface implementation from the cryptographic algorithms. Test-coverage of Hash is now at more than 85% Change-Id: Ib9c5b45da54241d959c09f7b0351f3163be0c6ef Signed-off-by: Angelo De Caro <[email protected]>
1 parent add0af3 commit 1b7b163

File tree

8 files changed

+240
-157
lines changed

8 files changed

+240
-157
lines changed

bccsp/mocks/mocks.go

+6
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,9 @@ func (*KeyImportOpts) Ephemeral() bool {
162162
}
163163

164164
type EncrypterOpts struct{}
165+
166+
type HashOpts struct{}
167+
168+
func (HashOpts) Algorithm() string {
169+
return "Mock HashOpts"
170+
}

bccsp/sw/hash.go

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package sw
18+
19+
import (
20+
"hash"
21+
22+
"github.com/hyperledger/fabric/bccsp"
23+
)
24+
25+
type hasher struct {
26+
hash func() hash.Hash
27+
}
28+
29+
func (c *hasher) Hash(msg []byte, opts bccsp.HashOpts) (hash []byte, err error) {
30+
h := c.hash()
31+
h.Write(msg)
32+
return h.Sum(nil), nil
33+
}
34+
35+
func (c *hasher) GetHash(opts bccsp.HashOpts) (h hash.Hash, err error) {
36+
return c.hash(), nil
37+
}

bccsp/sw/hash_test.go

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package sw
18+
19+
import (
20+
"crypto/sha256"
21+
"errors"
22+
"reflect"
23+
"testing"
24+
25+
mocks2 "github.com/hyperledger/fabric/bccsp/mocks"
26+
"github.com/hyperledger/fabric/bccsp/sw/mocks"
27+
"github.com/stretchr/testify/assert"
28+
)
29+
30+
func TestHash(t *testing.T) {
31+
expectetMsg := []byte{1, 2, 3, 4}
32+
expectedOpts := &mocks2.HashOpts{}
33+
expectetValue := []byte{1, 2, 3, 4, 5}
34+
expectedErr := errors.New("no error")
35+
36+
hashers := make(map[reflect.Type]Hasher)
37+
hashers[reflect.TypeOf(&mocks2.HashOpts{})] = &mocks.Hasher{
38+
MsgArg: expectetMsg,
39+
OptsArg: expectedOpts,
40+
Value: expectetValue,
41+
Err: expectedErr,
42+
}
43+
44+
csp := impl{hashers: hashers}
45+
46+
value, err := csp.Hash(expectetMsg, expectedOpts)
47+
assert.Equal(t, expectetValue, value)
48+
assert.Equal(t, expectedErr, err)
49+
}
50+
51+
func TestGetHash(t *testing.T) {
52+
expectedOpts := &mocks2.HashOpts{}
53+
expectetValue := sha256.New()
54+
expectedErr := errors.New("no error")
55+
56+
hashers := make(map[reflect.Type]Hasher)
57+
hashers[reflect.TypeOf(&mocks2.HashOpts{})] = &mocks.Hasher{
58+
OptsArg: expectedOpts,
59+
ValueHash: expectetValue,
60+
Err: expectedErr,
61+
}
62+
63+
csp := impl{hashers: hashers}
64+
65+
value, err := csp.GetHash(expectedOpts)
66+
assert.Equal(t, expectetValue, value)
67+
assert.Equal(t, expectedErr, err)
68+
}
69+
70+
func TestHasher(t *testing.T) {
71+
hasher := &hasher{hash: sha256.New}
72+
73+
msg := []byte("Hello World")
74+
out, err := hasher.Hash(msg, nil)
75+
assert.NoError(t, err)
76+
h := sha256.New()
77+
h.Write(msg)
78+
out2 := h.Sum(nil)
79+
assert.Equal(t, out, out2)
80+
81+
hf, err := hasher.GetHash(nil)
82+
assert.NoError(t, err)
83+
assert.Equal(t, hf, sha256.New())
84+
}

bccsp/sw/impl.go

+32-37
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@ import (
2121
"crypto/hmac"
2222
"crypto/rand"
2323
"crypto/rsa"
24-
"crypto/sha256"
25-
"crypto/sha512"
2624
"crypto/x509"
2725
"errors"
2826
"fmt"
2927
"hash"
3028
"math/big"
3129
"reflect"
3230

31+
"crypto/sha256"
32+
"crypto/sha512"
33+
3334
"github.com/hyperledger/fabric/bccsp"
3435
"github.com/hyperledger/fabric/bccsp/utils"
3536
"github.com/hyperledger/fabric/common/flogging"
@@ -92,13 +93,24 @@ func New(securityLevel int, hashFamily string, keyStore bccsp.KeyStore) (bccsp.B
9293
verifiers[reflect.TypeOf(&rsaPrivateKey{})] = &rsaPrivateKeyVerifier{}
9394
verifiers[reflect.TypeOf(&rsaPublicKey{})] = &rsaPublicKeyKeyVerifier{}
9495

95-
return &impl{
96+
// Set the hashers
97+
hashers := make(map[reflect.Type]Hasher)
98+
hashers[reflect.TypeOf(&bccsp.SHAOpts{})] = &hasher{hash: conf.hashFunction}
99+
hashers[reflect.TypeOf(&bccsp.SHA256Opts{})] = &hasher{hash: sha256.New}
100+
hashers[reflect.TypeOf(&bccsp.SHA384Opts{})] = &hasher{hash: sha512.New384}
101+
hashers[reflect.TypeOf(&bccsp.SHA3_256Opts{})] = &hasher{hash: sha3.New256}
102+
hashers[reflect.TypeOf(&bccsp.SHA3_384Opts{})] = &hasher{hash: sha3.New384}
103+
104+
impl := &impl{
96105
conf: conf,
97106
ks: keyStore,
98107
encryptors: encryptors,
99108
decryptors: decryptors,
100109
signers: signers,
101-
verifiers: verifiers}, nil
110+
verifiers: verifiers,
111+
hashers: hashers}
112+
113+
return impl, nil
102114
}
103115

104116
// SoftwareBasedBCCSP is the software-based implementation of the BCCSP.
@@ -110,6 +122,7 @@ type impl struct {
110122
decryptors map[reflect.Type]Decryptor
111123
signers map[reflect.Type]Signer
112124
verifiers map[reflect.Type]Verifier
125+
hashers map[reflect.Type]Hasher
113126
}
114127

115128
// KeyGen generates a key using opts.
@@ -619,51 +632,33 @@ func (csp *impl) GetKey(ski []byte) (k bccsp.Key, err error) {
619632

620633
// Hash hashes messages msg using options opts.
621634
func (csp *impl) Hash(msg []byte, opts bccsp.HashOpts) (digest []byte, err error) {
622-
var h hash.Hash
635+
// Validate arguments
623636
if opts == nil {
624-
h = csp.conf.hashFunction()
625-
} else {
626-
switch opts.(type) {
627-
case *bccsp.SHAOpts:
628-
h = csp.conf.hashFunction()
629-
case *bccsp.SHA256Opts:
630-
h = sha256.New()
631-
case *bccsp.SHA384Opts:
632-
h = sha512.New384()
633-
case *bccsp.SHA3_256Opts:
634-
h = sha3.New256()
635-
case *bccsp.SHA3_384Opts:
636-
h = sha3.New384()
637-
default:
638-
return nil, fmt.Errorf("Algorithm not recognized [%s]", opts.Algorithm())
639-
}
637+
return nil, errors.New("Invalid opts. It must not be nil.")
640638
}
641639

642-
h.Write(msg)
643-
return h.Sum(nil), nil
640+
hasher, found := csp.hashers[reflect.TypeOf(opts)]
641+
if !found {
642+
return nil, fmt.Errorf("Unsupported 'HashOpt' provided [%v]", opts)
643+
}
644+
645+
return hasher.Hash(msg, opts)
644646
}
645647

646648
// GetHash returns and instance of hash.Hash using options opts.
647649
// If opts is nil then the default hash function is returned.
648650
func (csp *impl) GetHash(opts bccsp.HashOpts) (h hash.Hash, err error) {
651+
// Validate arguments
649652
if opts == nil {
650-
return csp.conf.hashFunction(), nil
653+
return nil, errors.New("Invalid opts. It must not be nil.")
651654
}
652655

653-
switch opts.(type) {
654-
case *bccsp.SHAOpts:
655-
return csp.conf.hashFunction(), nil
656-
case *bccsp.SHA256Opts:
657-
return sha256.New(), nil
658-
case *bccsp.SHA384Opts:
659-
return sha512.New384(), nil
660-
case *bccsp.SHA3_256Opts:
661-
return sha3.New256(), nil
662-
case *bccsp.SHA3_384Opts:
663-
return sha3.New384(), nil
664-
default:
665-
return nil, fmt.Errorf("Algorithm not recognized [%s]", opts.Algorithm())
656+
hasher, found := csp.hashers[reflect.TypeOf(opts)]
657+
if !found {
658+
return nil, fmt.Errorf("Unsupported 'HashOpt' provided [%v]", opts)
666659
}
660+
661+
return hasher.GetHash(opts)
667662
}
668663

669664
// Sign signs digest using key k.

0 commit comments

Comments
 (0)