From 75fde484ba7a4e954886190a6f6a0df46fa76e77 Mon Sep 17 00:00:00 2001 From: Sun Yimin Date: Thu, 13 Apr 2023 09:32:14 +0800 Subject: [PATCH] drbg: use hash creator, but it's still NOT goroutine safe --- drbg/common.go | 10 +++++----- drbg/common_test.go | 2 +- drbg/ctr_drbg.go | 1 + drbg/hash_drbg.go | 45 +++++++++++++++++++++++------------------- drbg/hash_drbg_test.go | 26 ++++++++++++------------ 5 files changed, 45 insertions(+), 39 deletions(-) diff --git a/drbg/common.go b/drbg/common.go index d674093..0213cc4 100644 --- a/drbg/common.go +++ b/drbg/common.go @@ -88,7 +88,7 @@ func NewGmCtrDrbgPrng(entropySource io.Reader, securityStrength int, securityLev } // NewHashDrbgPrng create pseudo random number generator base on HASH DRBG -func NewHashDrbgPrng(md hash.Hash, entropySource io.Reader, securityStrength int, gm bool, securityLevel SecurityLevel, personalization []byte) (*DrbgPrng, error) { +func NewHashDrbgPrng(newHash func() hash.Hash, entropySource io.Reader, securityStrength int, gm bool, securityLevel SecurityLevel, personalization []byte) (*DrbgPrng, error) { prng := new(DrbgPrng) if entropySource != nil { prng.entropySource = entropySource @@ -114,7 +114,7 @@ func NewHashDrbgPrng(md hash.Hash, entropySource io.Reader, securityStrength int return nil, err } - prng.impl, err = NewHashDrbg(md, securityLevel, gm, entropyInput, nonce, personalization) + prng.impl, err = NewHashDrbg(newHash, securityLevel, gm, entropyInput, nonce, personalization) if err != nil { return nil, err } @@ -123,13 +123,13 @@ func NewHashDrbgPrng(md hash.Hash, entropySource io.Reader, securityStrength int } // NewNistHashDrbgPrng create pseudo random number generator base on hash DRBG which follows NIST standard -func NewNistHashDrbgPrng(md hash.Hash, entropySource io.Reader, securityStrength int, securityLevel SecurityLevel, personalization []byte) (*DrbgPrng, error) { - return NewHashDrbgPrng(md, entropySource, securityStrength, false, securityLevel, personalization) +func NewNistHashDrbgPrng(newHash func() hash.Hash, entropySource io.Reader, securityStrength int, securityLevel SecurityLevel, personalization []byte) (*DrbgPrng, error) { + return NewHashDrbgPrng(newHash, entropySource, securityStrength, false, securityLevel, personalization) } // NewGmHashDrbgPrng create pseudo random number generator base on hash DRBG which follows GM/T 0105-2021 standard func NewGmHashDrbgPrng(entropySource io.Reader, securityStrength int, securityLevel SecurityLevel, personalization []byte) (*DrbgPrng, error) { - return NewHashDrbgPrng(sm3.New(), entropySource, securityStrength, true, securityLevel, personalization) + return NewHashDrbgPrng(sm3.New, entropySource, securityStrength, true, securityLevel, personalization) } func (prng *DrbgPrng) getEntropy(entropyInput []byte) error { diff --git a/drbg/common_test.go b/drbg/common_test.go index 688e2d4..ff578d7 100644 --- a/drbg/common_test.go +++ b/drbg/common_test.go @@ -56,7 +56,7 @@ func TestGmHashDrbgPrng(t *testing.T) { } func TestNistHashDrbgPrng(t *testing.T) { - prng, err := NewNistHashDrbgPrng(sha256.New(), nil, 32, SECURITY_LEVEL_TEST, nil) + prng, err := NewNistHashDrbgPrng(sha256.New, nil, 32, SECURITY_LEVEL_TEST, nil) if err != nil { t.Fatal(err) } diff --git a/drbg/ctr_drbg.go b/drbg/ctr_drbg.go index c4254e8..2fd17b5 100644 --- a/drbg/ctr_drbg.go +++ b/drbg/ctr_drbg.go @@ -10,6 +10,7 @@ import ( "github.com/emmansun/gmsm/sm4" ) +// CtrDrbg CTR DRBG structure, its instance is NOT goroutine safe!!! type CtrDrbg struct { BaseDrbg cipherProvider func(key []byte) (cipher.Block, error) diff --git a/drbg/hash_drbg.go b/drbg/hash_drbg.go index dd17893..2411f5f 100644 --- a/drbg/hash_drbg.go +++ b/drbg/hash_drbg.go @@ -12,27 +12,32 @@ import ( const HASH_DRBG_SEED_SIZE = 55 const HASH_DRBG_MAX_SEED_SIZE = 111 +// HashDrbg hash DRBG structure, its instance is NOT goroutine safe!!! type HashDrbg struct { BaseDrbg - md hash.Hash - c []byte + newHash func() hash.Hash + c []byte + hashSize int } // NewHashDrbg create one hash DRBG instance -func NewHashDrbg(md hash.Hash, securityLevel SecurityLevel, gm bool, entropy, nonce, personalization []byte) (*HashDrbg, error) { +func NewHashDrbg(newHash func() hash.Hash, securityLevel SecurityLevel, gm bool, entropy, nonce, personalization []byte) (*HashDrbg, error) { hd := &HashDrbg{} hd.gm = gm - hd.md = md + hd.newHash = newHash hd.setSecurityLevel(securityLevel) + md := newHash() + hd.hashSize = md.Size() + // here for the min length, we just check <=0 now - if len(entropy) == 0 || (hd.gm && len(entropy) < hd.md.Size()) || len(entropy) >= MAX_BYTES { + if len(entropy) == 0 || (hd.gm && len(entropy) < hd.hashSize) || len(entropy) >= MAX_BYTES { return nil, errors.New("invalid entropy length") } // here for the min length, we just check <=0 now - if len(nonce) == 0 || (hd.gm && len(nonce) < hd.md.Size()/2) || len(nonce) >= MAX_BYTES>>1 { + if len(nonce) == 0 || (hd.gm && len(nonce) < hd.hashSize/2) || len(nonce) >= MAX_BYTES>>1 { return nil, errors.New("invalid nonce length") } @@ -40,7 +45,7 @@ func NewHashDrbg(md hash.Hash, securityLevel SecurityLevel, gm bool, entropy, no return nil, errors.New("personalization is too long") } - if md.Size() <= sm3.Size { + if hd.hashSize <= sm3.Size { hd.v = make([]byte, HASH_DRBG_SEED_SIZE) hd.c = make([]byte, HASH_DRBG_SEED_SIZE) hd.seedLength = HASH_DRBG_SEED_SIZE @@ -74,19 +79,19 @@ func NewHashDrbg(md hash.Hash, securityLevel SecurityLevel, gm bool, entropy, no } // NewNISTHashDrbg return hash DRBG implementation which follows NIST standard -func NewNISTHashDrbg(md hash.Hash, securityLevel SecurityLevel, entropy, nonce, personalization []byte) (*HashDrbg, error) { - return NewHashDrbg(md, securityLevel, false, entropy, nonce, personalization) +func NewNISTHashDrbg(newHash func() hash.Hash, securityLevel SecurityLevel, entropy, nonce, personalization []byte) (*HashDrbg, error) { + return NewHashDrbg(newHash, securityLevel, false, entropy, nonce, personalization) } // NewGMHashDrbg return hash DRBG implementation which follows GM/T 0105-2021 standard func NewGMHashDrbg(securityLevel SecurityLevel, entropy, nonce, personalization []byte) (*HashDrbg, error) { - return NewHashDrbg(sm3.New(), securityLevel, true, entropy, nonce, personalization) + return NewHashDrbg(sm3.New, securityLevel, true, entropy, nonce, personalization) } // Reseed hash DRBG reseed process. GM/T 0105-2021 has a little different with NIST. func (hd *HashDrbg) Reseed(entropy, additional []byte) error { // here for the min length, we just check <=0 now - if len(entropy) == 0 || (hd.gm && len(entropy) < hd.md.Size()) || len(entropy) >= MAX_BYTES { + if len(entropy) == 0 || (hd.gm && len(entropy) < hd.hashSize) || len(entropy) >= MAX_BYTES { return errors.New("invalid entropy length") } @@ -133,10 +138,10 @@ func (hd *HashDrbg) addC() { } func (hd *HashDrbg) addH() { - hd.md.Write([]byte{0x03}) - hd.md.Write(hd.v) - hd.addW(hd.md.Sum(nil)) - hd.md.Reset() + md := hd.newHash() + md.Write([]byte{0x03}) + md.Write(hd.v) + hd.addW(md.Sum(nil)) } func (hd *HashDrbg) addReseedCounter() { @@ -147,7 +152,7 @@ func (hd *HashDrbg) addReseedCounter() { func (hd *HashDrbg) MaxBytesPerRequest() int { if hd.gm { - return hd.md.Size() + return hd.hashSize } return MAX_BYTES_PER_GENERATE } @@ -158,10 +163,10 @@ func (hd *HashDrbg) Generate(b, additional []byte) error { if hd.NeedReseed() { return ErrReseedRequired } - if (hd.gm && len(b) > hd.md.Size()) || (!hd.gm && len(b) > MAX_BYTES_PER_GENERATE) { + if (hd.gm && len(b) > hd.hashSize) || (!hd.gm && len(b) > MAX_BYTES_PER_GENERATE) { return errors.New("too many bytes requested") } - md := hd.md + md := hd.newHash() m := len(b) // if len(additional_input) > 0, then @@ -200,8 +205,8 @@ func (hd *HashDrbg) Generate(b, additional []byte) error { // derive Hash_df func (hd *HashDrbg) derive(seedMaterial []byte, len int) []byte { - md := hd.md - limit := uint64(len+md.Size()-1) / uint64(md.Size()) + md := hd.newHash() + limit := uint64(len+hd.hashSize-1) / uint64(hd.hashSize) var requireBytes [4]byte binary.BigEndian.PutUint32(requireBytes[:], uint32(len<<3)) var ct byte = 1 diff --git a/drbg/hash_drbg_test.go b/drbg/hash_drbg_test.go index 684ba4a..b36bba4 100644 --- a/drbg/hash_drbg_test.go +++ b/drbg/hash_drbg_test.go @@ -14,7 +14,7 @@ import ( var tests = []struct { gm bool - md hash.Hash + newHash func() hash.Hash entropyInput string nonce string personalizationString string @@ -32,7 +32,7 @@ var tests = []struct { }{ { false, - sha1.New(), + sha1.New, "1610b828ccd27de08ceea032a20e9208", "492cf1709242f6b5", "", @@ -50,7 +50,7 @@ var tests = []struct { }, { false, - sha1.New(), + sha1.New, "d9bab5cedca96f6178d64509a0dfdc5e", "dad8989414450e01", "", @@ -68,7 +68,7 @@ var tests = []struct { }, { false, - sha256.New(), + sha256.New, "63363377e41e86468deb0ab4a8ed683f6a134e47e014c700454e81e95358a569", "808aa38f2a72a62359915a9f8a04ca68", "", @@ -86,7 +86,7 @@ var tests = []struct { }, { false, - sha256.New(), + sha256.New, "9cfb7ad03be487a3b42be06e9ae44f283c2b1458cec801da2ae6532fcb56cc4c", "a20765538e8db31295747ec922c13a69", "", @@ -104,7 +104,7 @@ var tests = []struct { }, { false, - sha512.New(), + sha512.New, "3144e17a10c856129764f58fd8e4231020546996c0bf6cff8e91c24ee09be333", "b16fcb1cf0c010f31feab733588b8e04", "", @@ -122,7 +122,7 @@ var tests = []struct { }, { false, - sha512.New(), + sha512.New, "c73a7820f0f53e8bbfc3b7b71d994143cf6e98642e9ea6d8df5dccbc43db8720", "20cc9834b588adcb1bbde64f0d2a34cb", "", @@ -140,7 +140,7 @@ var tests = []struct { }, { true, - sm3.New(), + sm3.New, "63363377e41e86468deb0ab4a8ed683f6a134e47e014c700454e81e95358a569", "808aa38f2a72a62359915a9f8a04ca68", "", @@ -158,7 +158,7 @@ var tests = []struct { }, { true, - sm3.New(), + sm3.New, "9cfb7ad03be487a3b42be06e9ae44f283c2b1458cec801da2ae6532fcb56cc4c", "a20765538e8db31295747ec922c13a69", "", @@ -183,7 +183,7 @@ func TestHashDRBG(t *testing.T) { personalizationString, _ := hex.DecodeString(test.personalizationString) v0, _ := hex.DecodeString(test.v0) c0, _ := hex.DecodeString(test.c0) - hd, err := NewHashDrbg(test.md, SECURITY_LEVEL_ONE, test.gm, entropyInput, nonce, personalizationString) + hd, err := NewHashDrbg(test.newHash, SECURITY_LEVEL_ONE, test.gm, entropyInput, nonce, personalizationString) if err != nil { t.Fatal(err) } @@ -232,15 +232,15 @@ func TestHashDRBG(t *testing.T) { func TestGmHashDRBG_Validation(t *testing.T) { entropyInput := make([]byte, 64) - _, err := NewHashDrbg(sm3.New(), SECURITY_LEVEL_ONE, true, entropyInput[:16], entropyInput[16:24], nil) + _, err := NewHashDrbg(sm3.New, SECURITY_LEVEL_ONE, true, entropyInput[:16], entropyInput[16:24], nil) if err == nil { t.Fatalf("expected error here") } - _, err = NewHashDrbg(sm3.New(), SECURITY_LEVEL_ONE, true, entropyInput[:32], entropyInput[32:40], nil) + _, err = NewHashDrbg(sm3.New, SECURITY_LEVEL_ONE, true, entropyInput[:32], entropyInput[32:40], nil) if err == nil { t.Fatalf("expected error here") } - hd, err := NewHashDrbg(sm3.New(), SECURITY_LEVEL_ONE, true, entropyInput[:32], entropyInput[32:48], nil) + hd, err := NewHashDrbg(sm3.New, SECURITY_LEVEL_ONE, true, entropyInput[:32], entropyInput[32:48], nil) if err != nil { t.Fatal(err) }