drbg: use hash creator, but it's still NOT goroutine safe

This commit is contained in:
Sun Yimin 2023-04-13 09:32:14 +08:00 committed by GitHub
parent a4d7601bd9
commit 75fde484ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 45 additions and 39 deletions

View File

@ -88,7 +88,7 @@ func NewGmCtrDrbgPrng(entropySource io.Reader, securityStrength int, securityLev
} }
// NewHashDrbgPrng create pseudo random number generator base on HASH DRBG // 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) prng := new(DrbgPrng)
if entropySource != nil { if entropySource != nil {
prng.entropySource = entropySource prng.entropySource = entropySource
@ -114,7 +114,7 @@ func NewHashDrbgPrng(md hash.Hash, entropySource io.Reader, securityStrength int
return nil, err 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 { if err != nil {
return nil, err 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 // 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) { func NewNistHashDrbgPrng(newHash func() hash.Hash, entropySource io.Reader, securityStrength int, securityLevel SecurityLevel, personalization []byte) (*DrbgPrng, error) {
return NewHashDrbgPrng(md, entropySource, securityStrength, false, securityLevel, personalization) 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 // 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) { 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 { func (prng *DrbgPrng) getEntropy(entropyInput []byte) error {

View File

@ -56,7 +56,7 @@ func TestGmHashDrbgPrng(t *testing.T) {
} }
func TestNistHashDrbgPrng(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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -10,6 +10,7 @@ import (
"github.com/emmansun/gmsm/sm4" "github.com/emmansun/gmsm/sm4"
) )
// CtrDrbg CTR DRBG structure, its instance is NOT goroutine safe!!!
type CtrDrbg struct { type CtrDrbg struct {
BaseDrbg BaseDrbg
cipherProvider func(key []byte) (cipher.Block, error) cipherProvider func(key []byte) (cipher.Block, error)

View File

@ -12,27 +12,32 @@ import (
const HASH_DRBG_SEED_SIZE = 55 const HASH_DRBG_SEED_SIZE = 55
const HASH_DRBG_MAX_SEED_SIZE = 111 const HASH_DRBG_MAX_SEED_SIZE = 111
// HashDrbg hash DRBG structure, its instance is NOT goroutine safe!!!
type HashDrbg struct { type HashDrbg struct {
BaseDrbg BaseDrbg
md hash.Hash newHash func() hash.Hash
c []byte c []byte
hashSize int
} }
// NewHashDrbg create one hash DRBG instance // 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 := &HashDrbg{}
hd.gm = gm hd.gm = gm
hd.md = md hd.newHash = newHash
hd.setSecurityLevel(securityLevel) hd.setSecurityLevel(securityLevel)
md := newHash()
hd.hashSize = md.Size()
// here for the min length, we just check <=0 now // 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") return nil, errors.New("invalid entropy length")
} }
// here for the min length, we just check <=0 now // 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") 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") 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.v = make([]byte, HASH_DRBG_SEED_SIZE)
hd.c = make([]byte, HASH_DRBG_SEED_SIZE) hd.c = make([]byte, HASH_DRBG_SEED_SIZE)
hd.seedLength = 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 // NewNISTHashDrbg return hash DRBG implementation which follows NIST standard
func NewNISTHashDrbg(md hash.Hash, securityLevel SecurityLevel, entropy, nonce, personalization []byte) (*HashDrbg, error) { func NewNISTHashDrbg(newHash func() hash.Hash, securityLevel SecurityLevel, entropy, nonce, personalization []byte) (*HashDrbg, error) {
return NewHashDrbg(md, securityLevel, false, entropy, nonce, personalization) return NewHashDrbg(newHash, securityLevel, false, entropy, nonce, personalization)
} }
// NewGMHashDrbg return hash DRBG implementation which follows GM/T 0105-2021 standard // NewGMHashDrbg return hash DRBG implementation which follows GM/T 0105-2021 standard
func NewGMHashDrbg(securityLevel SecurityLevel, entropy, nonce, personalization []byte) (*HashDrbg, error) { 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. // Reseed hash DRBG reseed process. GM/T 0105-2021 has a little different with NIST.
func (hd *HashDrbg) Reseed(entropy, additional []byte) error { func (hd *HashDrbg) Reseed(entropy, additional []byte) error {
// here for the min length, we just check <=0 now // 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") return errors.New("invalid entropy length")
} }
@ -133,10 +138,10 @@ func (hd *HashDrbg) addC() {
} }
func (hd *HashDrbg) addH() { func (hd *HashDrbg) addH() {
hd.md.Write([]byte{0x03}) md := hd.newHash()
hd.md.Write(hd.v) md.Write([]byte{0x03})
hd.addW(hd.md.Sum(nil)) md.Write(hd.v)
hd.md.Reset() hd.addW(md.Sum(nil))
} }
func (hd *HashDrbg) addReseedCounter() { func (hd *HashDrbg) addReseedCounter() {
@ -147,7 +152,7 @@ func (hd *HashDrbg) addReseedCounter() {
func (hd *HashDrbg) MaxBytesPerRequest() int { func (hd *HashDrbg) MaxBytesPerRequest() int {
if hd.gm { if hd.gm {
return hd.md.Size() return hd.hashSize
} }
return MAX_BYTES_PER_GENERATE return MAX_BYTES_PER_GENERATE
} }
@ -158,10 +163,10 @@ func (hd *HashDrbg) Generate(b, additional []byte) error {
if hd.NeedReseed() { if hd.NeedReseed() {
return ErrReseedRequired 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") return errors.New("too many bytes requested")
} }
md := hd.md md := hd.newHash()
m := len(b) m := len(b)
// if len(additional_input) > 0, then // if len(additional_input) > 0, then
@ -200,8 +205,8 @@ func (hd *HashDrbg) Generate(b, additional []byte) error {
// derive Hash_df // derive Hash_df
func (hd *HashDrbg) derive(seedMaterial []byte, len int) []byte { func (hd *HashDrbg) derive(seedMaterial []byte, len int) []byte {
md := hd.md md := hd.newHash()
limit := uint64(len+md.Size()-1) / uint64(md.Size()) limit := uint64(len+hd.hashSize-1) / uint64(hd.hashSize)
var requireBytes [4]byte var requireBytes [4]byte
binary.BigEndian.PutUint32(requireBytes[:], uint32(len<<3)) binary.BigEndian.PutUint32(requireBytes[:], uint32(len<<3))
var ct byte = 1 var ct byte = 1

View File

@ -14,7 +14,7 @@ import (
var tests = []struct { var tests = []struct {
gm bool gm bool
md hash.Hash newHash func() hash.Hash
entropyInput string entropyInput string
nonce string nonce string
personalizationString string personalizationString string
@ -32,7 +32,7 @@ var tests = []struct {
}{ }{
{ {
false, false,
sha1.New(), sha1.New,
"1610b828ccd27de08ceea032a20e9208", "1610b828ccd27de08ceea032a20e9208",
"492cf1709242f6b5", "492cf1709242f6b5",
"", "",
@ -50,7 +50,7 @@ var tests = []struct {
}, },
{ {
false, false,
sha1.New(), sha1.New,
"d9bab5cedca96f6178d64509a0dfdc5e", "d9bab5cedca96f6178d64509a0dfdc5e",
"dad8989414450e01", "dad8989414450e01",
"", "",
@ -68,7 +68,7 @@ var tests = []struct {
}, },
{ {
false, false,
sha256.New(), sha256.New,
"63363377e41e86468deb0ab4a8ed683f6a134e47e014c700454e81e95358a569", "63363377e41e86468deb0ab4a8ed683f6a134e47e014c700454e81e95358a569",
"808aa38f2a72a62359915a9f8a04ca68", "808aa38f2a72a62359915a9f8a04ca68",
"", "",
@ -86,7 +86,7 @@ var tests = []struct {
}, },
{ {
false, false,
sha256.New(), sha256.New,
"9cfb7ad03be487a3b42be06e9ae44f283c2b1458cec801da2ae6532fcb56cc4c", "9cfb7ad03be487a3b42be06e9ae44f283c2b1458cec801da2ae6532fcb56cc4c",
"a20765538e8db31295747ec922c13a69", "a20765538e8db31295747ec922c13a69",
"", "",
@ -104,7 +104,7 @@ var tests = []struct {
}, },
{ {
false, false,
sha512.New(), sha512.New,
"3144e17a10c856129764f58fd8e4231020546996c0bf6cff8e91c24ee09be333", "3144e17a10c856129764f58fd8e4231020546996c0bf6cff8e91c24ee09be333",
"b16fcb1cf0c010f31feab733588b8e04", "b16fcb1cf0c010f31feab733588b8e04",
"", "",
@ -122,7 +122,7 @@ var tests = []struct {
}, },
{ {
false, false,
sha512.New(), sha512.New,
"c73a7820f0f53e8bbfc3b7b71d994143cf6e98642e9ea6d8df5dccbc43db8720", "c73a7820f0f53e8bbfc3b7b71d994143cf6e98642e9ea6d8df5dccbc43db8720",
"20cc9834b588adcb1bbde64f0d2a34cb", "20cc9834b588adcb1bbde64f0d2a34cb",
"", "",
@ -140,7 +140,7 @@ var tests = []struct {
}, },
{ {
true, true,
sm3.New(), sm3.New,
"63363377e41e86468deb0ab4a8ed683f6a134e47e014c700454e81e95358a569", "63363377e41e86468deb0ab4a8ed683f6a134e47e014c700454e81e95358a569",
"808aa38f2a72a62359915a9f8a04ca68", "808aa38f2a72a62359915a9f8a04ca68",
"", "",
@ -158,7 +158,7 @@ var tests = []struct {
}, },
{ {
true, true,
sm3.New(), sm3.New,
"9cfb7ad03be487a3b42be06e9ae44f283c2b1458cec801da2ae6532fcb56cc4c", "9cfb7ad03be487a3b42be06e9ae44f283c2b1458cec801da2ae6532fcb56cc4c",
"a20765538e8db31295747ec922c13a69", "a20765538e8db31295747ec922c13a69",
"", "",
@ -183,7 +183,7 @@ func TestHashDRBG(t *testing.T) {
personalizationString, _ := hex.DecodeString(test.personalizationString) personalizationString, _ := hex.DecodeString(test.personalizationString)
v0, _ := hex.DecodeString(test.v0) v0, _ := hex.DecodeString(test.v0)
c0, _ := hex.DecodeString(test.c0) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -232,15 +232,15 @@ func TestHashDRBG(t *testing.T) {
func TestGmHashDRBG_Validation(t *testing.T) { func TestGmHashDRBG_Validation(t *testing.T) {
entropyInput := make([]byte, 64) 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 { if err == nil {
t.Fatalf("expected error here") 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 { if err == nil {
t.Fatalf("expected error here") 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }