mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-26 20:26:19 +08:00
add comments and enhance gm validation
This commit is contained in:
parent
7f86563f74
commit
0342ada322
@ -15,9 +15,11 @@ import (
|
|||||||
const DRBG_RESEED_COUNTER_INTERVAL_LEVEL_TEST uint64 = 8
|
const DRBG_RESEED_COUNTER_INTERVAL_LEVEL_TEST uint64 = 8
|
||||||
const DRBG_RESEED_COUNTER_INTERVAL_LEVEL2 uint64 = 1 << 10
|
const DRBG_RESEED_COUNTER_INTERVAL_LEVEL2 uint64 = 1 << 10
|
||||||
const DRBG_RESEED_COUNTER_INTERVAL_LEVEL1 uint64 = 1 << 20
|
const DRBG_RESEED_COUNTER_INTERVAL_LEVEL1 uint64 = 1 << 20
|
||||||
|
|
||||||
const DRBG_RESEED_TIME_INTERVAL_LEVEL_TEST = time.Duration(6) * time.Second
|
const DRBG_RESEED_TIME_INTERVAL_LEVEL_TEST = time.Duration(6) * time.Second
|
||||||
const DRBG_RESEED_TIME_INTERVAL_LEVEL2 = time.Duration(60) * time.Second
|
const DRBG_RESEED_TIME_INTERVAL_LEVEL2 = time.Duration(60) * time.Second
|
||||||
const DRBG_RESEED_TIME_INTERVAL_LEVEL1 = time.Duration(600) * time.Second
|
const DRBG_RESEED_TIME_INTERVAL_LEVEL1 = time.Duration(600) * time.Second
|
||||||
|
|
||||||
const MAX_BYTES = 1 << 27
|
const MAX_BYTES = 1 << 27
|
||||||
const MAX_BYTES_PER_GENERATE = 1 << 11
|
const MAX_BYTES_PER_GENERATE = 1 << 11
|
||||||
|
|
||||||
@ -46,7 +48,11 @@ func NewCtrDrbgPrng(cipherProvider func(key []byte) (cipher.Block, error), keyLe
|
|||||||
} else {
|
} else {
|
||||||
prng.entropySource = rand.Reader
|
prng.entropySource = rand.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
prng.securityStrength = selectSecurityStrength(securityStrength)
|
prng.securityStrength = selectSecurityStrength(securityStrength)
|
||||||
|
if gm && securityStrength < 32 {
|
||||||
|
return nil, errors.New("invalid security strength")
|
||||||
|
}
|
||||||
|
|
||||||
// Get entropy input
|
// Get entropy input
|
||||||
entropyInput := make([]byte, prng.securityStrength)
|
entropyInput := make([]byte, prng.securityStrength)
|
||||||
@ -89,6 +95,9 @@ func NewHashDrbgPrng(md hash.Hash, entropySource io.Reader, securityStrength int
|
|||||||
prng.entropySource = rand.Reader
|
prng.entropySource = rand.Reader
|
||||||
}
|
}
|
||||||
prng.securityStrength = selectSecurityStrength(securityStrength)
|
prng.securityStrength = selectSecurityStrength(securityStrength)
|
||||||
|
if gm && securityStrength < 32 {
|
||||||
|
return nil, errors.New("invalid security strength")
|
||||||
|
}
|
||||||
|
|
||||||
// Get entropy input
|
// Get entropy input
|
||||||
entropyInput := make([]byte, prng.securityStrength)
|
entropyInput := make([]byte, prng.securityStrength)
|
||||||
@ -97,7 +106,7 @@ func NewHashDrbgPrng(md hash.Hash, entropySource io.Reader, securityStrength int
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get nonce
|
// Get nonce from entropy source here
|
||||||
nonce := make([]byte, prng.securityStrength/2)
|
nonce := make([]byte, prng.securityStrength/2)
|
||||||
err = prng.getEntropy(nonce)
|
err = prng.getEntropy(nonce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -213,8 +222,10 @@ func selectSecurityStrength(requested int) int {
|
|||||||
return 16
|
return 16
|
||||||
case requested <= 24:
|
case requested <= 24:
|
||||||
return 24
|
return 24
|
||||||
default:
|
case requested <= 32:
|
||||||
return 32
|
return 32
|
||||||
|
default:
|
||||||
|
return requested
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestGmCtrDrbgPrng(t *testing.T) {
|
func TestGmCtrDrbgPrng(t *testing.T) {
|
||||||
prng, err := NewGmCtrDrbgPrng(nil, 16, SECURITY_LEVEL_TEST, nil)
|
prng, err := NewGmCtrDrbgPrng(nil, 32, SECURITY_LEVEL_TEST, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,12 @@ func NewCtrDrbg(cipherProvider func(key []byte) (cipher.Block, error), keyLen in
|
|||||||
hd.setSecurityLevel(securityLevel)
|
hd.setSecurityLevel(securityLevel)
|
||||||
|
|
||||||
// here for the min length, we just check <=0 now
|
// here for the min length, we just check <=0 now
|
||||||
if len(entropy) <= 0 || len(entropy) >= MAX_BYTES {
|
if len(entropy) == 0 || (hd.gm && len(entropy) < 32) || 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 || len(nonce) >= MAX_BYTES>>1 {
|
if len(nonce) == 0 || (hd.gm && len(entropy) < 16) || len(nonce) >= MAX_BYTES>>1 {
|
||||||
return nil, errors.New("invalid nonce length")
|
return nil, errors.New("invalid nonce length")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,12 +49,16 @@ func NewCtrDrbg(cipherProvider func(key []byte) (cipher.Block, error), keyLen in
|
|||||||
hd.v = make([]byte, block.BlockSize())
|
hd.v = make([]byte, block.BlockSize())
|
||||||
hd.key = make([]byte, hd.keyLen)
|
hd.key = make([]byte, hd.keyLen)
|
||||||
|
|
||||||
|
// seed_material = entropy_input || instantiation_nonce || personalization_string
|
||||||
seedMaterial := make([]byte, len(entropy)+len(nonce)+len(personalization))
|
seedMaterial := make([]byte, len(entropy)+len(nonce)+len(personalization))
|
||||||
copy(seedMaterial, entropy)
|
copy(seedMaterial, entropy)
|
||||||
copy(seedMaterial[len(entropy):], nonce)
|
copy(seedMaterial[len(entropy):], nonce)
|
||||||
copy(seedMaterial[len(entropy)+len(nonce):], personalization)
|
copy(seedMaterial[len(entropy)+len(nonce):], personalization)
|
||||||
seed := hd.derive(seedMaterial, hd.seedLength)
|
// seed_material = Block_Cipher_df(seed_material, seed_length)
|
||||||
hd.update(seed)
|
seedMaterial = hd.derive(seedMaterial, hd.seedLength)
|
||||||
|
// CTR_DRBG_Updae(seed_material, Key, V)
|
||||||
|
hd.update(seedMaterial)
|
||||||
|
|
||||||
hd.reseedCounter = 1
|
hd.reseedCounter = 1
|
||||||
hd.reseedTime = time.Now()
|
hd.reseedTime = time.Now()
|
||||||
return hd, nil
|
return hd, nil
|
||||||
@ -72,7 +76,7 @@ func NewGMCtrDrbg(securityLevel SecurityLevel, entropy, nonce, personalization [
|
|||||||
|
|
||||||
func (hd *CtrDrbg) Reseed(entropy, additional []byte) error {
|
func (hd *CtrDrbg) 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 || len(entropy) >= MAX_BYTES {
|
if len(entropy) <= 0 || (hd.gm && len(entropy) < 32) || len(entropy) >= MAX_BYTES {
|
||||||
return errors.New("invalid entropy length")
|
return errors.New("invalid entropy length")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,6 +84,7 @@ func (hd *CtrDrbg) Reseed(entropy, additional []byte) error {
|
|||||||
return errors.New("additional input too long")
|
return errors.New("additional input too long")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// seed_material = entropy_input || additional_input
|
||||||
var seedMaterial []byte
|
var seedMaterial []byte
|
||||||
if len(additional) == 0 {
|
if len(additional) == 0 {
|
||||||
seedMaterial = entropy
|
seedMaterial = entropy
|
||||||
@ -88,8 +93,11 @@ func (hd *CtrDrbg) Reseed(entropy, additional []byte) error {
|
|||||||
copy(seedMaterial, entropy)
|
copy(seedMaterial, entropy)
|
||||||
copy(seedMaterial[len(entropy):], additional)
|
copy(seedMaterial[len(entropy):], additional)
|
||||||
}
|
}
|
||||||
seed := hd.derive(seedMaterial, hd.seedLength)
|
// seed_material = Block_Cipher_df(seed_material, seed_length)
|
||||||
hd.update(seed)
|
seedMaterial = hd.derive(seedMaterial, hd.seedLength)
|
||||||
|
// CTR_DRBG_Updae(seed_material, Key, V)
|
||||||
|
hd.update(seedMaterial)
|
||||||
|
|
||||||
hd.reseedCounter = 1
|
hd.reseedCounter = 1
|
||||||
hd.reseedTime = time.Now()
|
hd.reseedTime = time.Now()
|
||||||
return nil
|
return nil
|
||||||
@ -110,7 +118,7 @@ func (hd *CtrDrbg) MaxBytesPerRequest() int {
|
|||||||
return MAX_BYTES_PER_GENERATE
|
return MAX_BYTES_PER_GENERATE
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate CTR DRBG generate process.
|
// Generate CTR DRBG pseudorandom bits generate process.
|
||||||
func (hd *CtrDrbg) Generate(b, additional []byte) error {
|
func (hd *CtrDrbg) Generate(b, additional []byte) error {
|
||||||
if hd.NeedReseed() {
|
if hd.NeedReseed() {
|
||||||
return ErrReseedRequired
|
return ErrReseedRequired
|
||||||
@ -120,6 +128,9 @@ func (hd *CtrDrbg) Generate(b, additional []byte) error {
|
|||||||
return errors.New("too many bytes requested")
|
return errors.New("too many bytes requested")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If len(additional_input) > 0, then
|
||||||
|
// additional_input = Block_Cipher_df(additional_input, seed_length)
|
||||||
|
// CTR_DRBG_Update(additional_input, Key, V)
|
||||||
if len(additional) > 0 {
|
if len(additional) > 0 {
|
||||||
additional = hd.derive(additional, hd.seedLength)
|
additional = hd.derive(additional, hd.seedLength)
|
||||||
hd.update(additional)
|
hd.update(additional)
|
||||||
@ -131,7 +142,9 @@ func (hd *CtrDrbg) Generate(b, additional []byte) error {
|
|||||||
m := len(b)
|
m := len(b)
|
||||||
limit := uint64(m+outlen-1) / uint64(outlen)
|
limit := uint64(m+outlen-1) / uint64(outlen)
|
||||||
for i := 0; i < int(limit); i++ {
|
for i := 0; i < int(limit); i++ {
|
||||||
|
// V = (V + 1) mod 2^outlen)
|
||||||
addOne(hd.v, outlen)
|
addOne(hd.v, outlen)
|
||||||
|
// output_block = Encrypt(Key, V)
|
||||||
block.Encrypt(temp, hd.v)
|
block.Encrypt(temp, hd.v)
|
||||||
copy(b[i*outlen:], temp)
|
copy(b[i*outlen:], temp)
|
||||||
}
|
}
|
||||||
@ -149,20 +162,28 @@ func (cd *CtrDrbg) update(seedMaterial []byte) {
|
|||||||
output := make([]byte, outlen)
|
output := make([]byte, outlen)
|
||||||
copy(v, cd.v)
|
copy(v, cd.v)
|
||||||
for i := 0; i < (cd.seedLength+outlen-1)/outlen; i++ {
|
for i := 0; i < (cd.seedLength+outlen-1)/outlen; i++ {
|
||||||
|
// V = (V + 1) mod 2^outlen
|
||||||
addOne(v, outlen)
|
addOne(v, outlen)
|
||||||
|
// output_block = Encrypt(Key, V)
|
||||||
block.Encrypt(output, v)
|
block.Encrypt(output, v)
|
||||||
copy(temp[i*outlen:], output)
|
copy(temp[i*outlen:], output)
|
||||||
}
|
}
|
||||||
|
// temp = temp XOR seed_material
|
||||||
subtle.XORBytes(temp, temp, seedMaterial)
|
subtle.XORBytes(temp, temp, seedMaterial)
|
||||||
|
// Key = leftmost(temp, key_length)
|
||||||
copy(cd.key, temp)
|
copy(cd.key, temp)
|
||||||
|
// V = rightmost(temp, outlen)
|
||||||
copy(cd.v, temp[cd.keyLen:])
|
copy(cd.v, temp[cd.keyLen:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// derive Block_Cipher_df
|
||||||
func (cd *CtrDrbg) derive(seedMaterial []byte, returnBytes int) []byte {
|
func (cd *CtrDrbg) derive(seedMaterial []byte, returnBytes int) []byte {
|
||||||
outlen := cd.seedLength - cd.keyLen
|
outlen := cd.seedLength - cd.keyLen
|
||||||
lenS := ((4 + 4 + len(seedMaterial) + outlen) / outlen) * outlen
|
lenS := ((4 + 4 + len(seedMaterial) + outlen) / outlen) * outlen
|
||||||
S := make([]byte, lenS+outlen)
|
S := make([]byte, lenS+outlen)
|
||||||
|
|
||||||
|
// S = counter || len(seed_material) || len(return_bytes) || seed_material || 0x80
|
||||||
|
// len(S) = ((outlen + 4 + 4 + len(seed_material) + 1 + outlen - 1) / outlen) * outlen
|
||||||
binary.BigEndian.PutUint32(S[outlen:], uint32(len(seedMaterial)))
|
binary.BigEndian.PutUint32(S[outlen:], uint32(len(seedMaterial)))
|
||||||
binary.BigEndian.PutUint32(S[outlen+4:], uint32(returnBytes))
|
binary.BigEndian.PutUint32(S[outlen+4:], uint32(returnBytes))
|
||||||
copy(S[outlen+8:], seedMaterial)
|
copy(S[outlen+8:], seedMaterial)
|
||||||
|
@ -182,43 +182,43 @@ var ctrtests = []struct {
|
|||||||
true,
|
true,
|
||||||
sm4.NewCipher,
|
sm4.NewCipher,
|
||||||
16,
|
16,
|
||||||
"0f65da13dca407999d4773c2b4a11d85",
|
"2d4c9f46b981c6a0b2b5d8c69391e569ff13851437ebc0fc00d616340252fed5",
|
||||||
"5209e5b4ed82a234",
|
"0bf814b411f65ec4866be1abb59d3c32",
|
||||||
"",
|
"",
|
||||||
"3dee0b770815026b88a86a1637c4c9f6",
|
"044f9ff3b7e8ad2b60a7b2c05fe6b5b7",
|
||||||
"40ef052e0dffc441fd644f6dce7430c0",
|
"7fce60b97d8ceb60506bff1d37b1a936",
|
||||||
"1dea0a12c52bf64339dd291c80d8ca89",
|
"93500fae4fa32b86033b7a7bac9d37e710dcc67ca266bc8607d665937766d207",
|
||||||
"",
|
"",
|
||||||
"1c5c3a1369b7ab6ea6f5631b0a8e4f2d", // v1
|
"8bd44b2e39f8186497f889c73555797d", // v1
|
||||||
"ac5783e385d6d4c6a2c5a184e7cebecb", //key1
|
"02b9a8f88124bd9cec909e1fd7ec9971", //key1
|
||||||
"",
|
"",
|
||||||
"22b16dfe04896ef1ddf69f12e5d9a1dd", // v2
|
"fbc91ad876ba3a84588be2f358b9e13c", // v2
|
||||||
"3f7b6539fc274b97565b2a1b26d021e0", //key2
|
"4804b2a1a971ca729abff5bada051cf6", //key2
|
||||||
"",
|
"",
|
||||||
"58129d515c9bb6d32e1ab1206fe6c618",
|
"e732a524de8ad239aa293ac8ae588f9d",
|
||||||
"69bfff2ab5f3dbcc5eaca7eb5a3cf8e4",
|
"ce60250d77048bdbe48ade354b6869f6",
|
||||||
"c2b4a693df1f768e7d45d0926a40f527",
|
"6788e31ae27aae09a14aed967ce8b219",
|
||||||
},
|
},
|
||||||
{ // SM4-128, with additional input
|
{ // SM4-128, with additional input
|
||||||
false,
|
false,
|
||||||
sm4.NewCipher,
|
sm4.NewCipher,
|
||||||
16,
|
16,
|
||||||
"285da6cf762552634636bfee3400b156",
|
"6f60f0f9d486bc23e1223b934e61c0c78ae9232fa2e9a87c6dacd447c3f10e9e",
|
||||||
"8f8bada74820cb43",
|
"401e3f87762fa8a14ab232ccb8480a2f",
|
||||||
"",
|
"",
|
||||||
"f5cb0d67b1784b97b1d90fff63e67d32", // v0
|
"5e8c10afe142dc9c8caf35411b38730a", // v0
|
||||||
"f55a8ee6f9414feac90fe15a43c9bc11", // key0
|
"d72aefa9fd527383ad418f6158627feb", // key0
|
||||||
"b4699b33354a83bfed115f770f32db0b", // EntropyInputReseed
|
"350be52552a65a804a106543ebb7dd046cffae104e4e8b2f18936d564d3c1950", // EntropyInputReseed
|
||||||
"38bfec9a10e6e40c106841dae48dc3b8", // AdditionalInputReseed
|
"7a3688adb1cfb6c03264e2762ece96bfe4daf9558fabf74d7fff203c08b4dd9f", // AdditionalInputReseed
|
||||||
"7398bf677878ae483b0e560b9c5bf666", // v1
|
"c00836da0fd780cdc81dabec80e344ce", // v1
|
||||||
"402b8f4743e52ba2d7dc88541f5d23b1", // key1
|
"f5f3abdeff30df22f4866d83cd96bc1b", // key1
|
||||||
"629ead5bacfac8235711ffeb22f57558", // AdditionalInput1
|
"67cf4a56d081c53670f257c25557014cd5e8b0e919aa58f23d6861b10b00ea80", // AdditionalInput1
|
||||||
"095162afa9927d43e1bb531ff9719a32", // v2
|
"6ddb205ec76567b31a07ee48437acebc", // v2
|
||||||
"c8a759bc36a5b86ede53122a89041a1c", // key2
|
"5e23cbe8b97065102ca0d87bfd9ae0da", // key2
|
||||||
"dd8a02ee668ca3e03949b38cb6e6b4df", // AdditionalInput2
|
"648d4a229198b43f33dd7dd8426650be11c5656adcdf913bb3ee5eb49a2a3892", // AdditionalInput2
|
||||||
"71f9fbd6bc78149061eabfbd248f54eb",
|
"b0ac91f148efbdc3570d7e434aba8d24",
|
||||||
"eddc1b09ff7ce31f19a0922249d78345", // v3
|
"d1f029bb089613d836ddc6fe1d6fb96f", // v3
|
||||||
"8c10825d503632f8cabed20bc62d6a08", // key3
|
"8adfe65e9137b18f060ae91e7a6224c1", // key3
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ func TestCtrDRBG(t *testing.T) {
|
|||||||
key0, _ := hex.DecodeString(test.key0)
|
key0, _ := hex.DecodeString(test.key0)
|
||||||
hd, err := NewCtrDrbg(test.cipherProvider, test.keyLen, SECURITY_LEVEL_ONE, test.gm, entropyInput, nonce, personalizationString)
|
hd, err := NewCtrDrbg(test.cipherProvider, test.keyLen, SECURITY_LEVEL_ONE, test.gm, entropyInput, nonce, personalizationString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(hd.v[:len(v0)], v0) {
|
if !bytes.Equal(hd.v[:len(v0)], v0) {
|
||||||
t.Errorf("case %v, not same v0 %s", i+1, hex.EncodeToString(hd.v))
|
t.Errorf("case %v, not same v0 %s", i+1, hex.EncodeToString(hd.v))
|
||||||
@ -246,7 +246,7 @@ func TestCtrDRBG(t *testing.T) {
|
|||||||
key1, _ := hex.DecodeString(test.key1)
|
key1, _ := hex.DecodeString(test.key1)
|
||||||
err = hd.Reseed(entropyInputReseed, additionalInputReseed)
|
err = hd.Reseed(entropyInputReseed, additionalInputReseed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(hd.v, v1) {
|
if !bytes.Equal(hd.v, v1) {
|
||||||
t.Errorf("case %v, not same v1 %s", i+1, hex.EncodeToString(hd.v))
|
t.Errorf("case %v, not same v1 %s", i+1, hex.EncodeToString(hd.v))
|
||||||
|
@ -23,15 +23,16 @@ func NewHashDrbg(md hash.Hash, securityLevel SecurityLevel, gm bool, entropy, no
|
|||||||
hd := &HashDrbg{}
|
hd := &HashDrbg{}
|
||||||
|
|
||||||
hd.gm = gm
|
hd.gm = gm
|
||||||
|
hd.md = md
|
||||||
hd.setSecurityLevel(securityLevel)
|
hd.setSecurityLevel(securityLevel)
|
||||||
|
|
||||||
// here for the min length, we just check <=0 now
|
// here for the min length, we just check <=0 now
|
||||||
if len(entropy) <= 0 || len(entropy) >= MAX_BYTES {
|
if len(entropy) == 0 || (hd.gm && len(entropy) < hd.md.Size()) || 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 || len(nonce) >= MAX_BYTES>>1 {
|
if len(nonce) == 0 || (hd.gm && len(entropy) < hd.md.Size()/2) || len(nonce) >= MAX_BYTES>>1 {
|
||||||
return nil, errors.New("invalid nonce length")
|
return nil, errors.New("invalid nonce length")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +40,6 @@ 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")
|
||||||
}
|
}
|
||||||
|
|
||||||
hd.md = md
|
|
||||||
if md.Size() <= sm3.Size {
|
if md.Size() <= 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)
|
||||||
@ -49,17 +49,24 @@ func NewHashDrbg(md hash.Hash, securityLevel SecurityLevel, gm bool, entropy, no
|
|||||||
hd.c = make([]byte, HASH_DRBG_MAX_SEED_SIZE)
|
hd.c = make([]byte, HASH_DRBG_MAX_SEED_SIZE)
|
||||||
hd.seedLength = HASH_DRBG_MAX_SEED_SIZE
|
hd.seedLength = HASH_DRBG_MAX_SEED_SIZE
|
||||||
}
|
}
|
||||||
|
// seed_material = entropy_input || instantiation_nonce || personalization_string
|
||||||
seedMaterial := make([]byte, len(entropy)+len(nonce)+len(personalization))
|
seedMaterial := make([]byte, len(entropy)+len(nonce)+len(personalization))
|
||||||
copy(seedMaterial, entropy)
|
copy(seedMaterial, entropy)
|
||||||
copy(seedMaterial[len(entropy):], nonce)
|
copy(seedMaterial[len(entropy):], nonce)
|
||||||
copy(seedMaterial[len(entropy)+len(nonce):], personalization)
|
copy(seedMaterial[len(entropy)+len(nonce):], personalization)
|
||||||
|
|
||||||
|
// seed = Hash_df(seed_material, seed_length)
|
||||||
seed := hd.derive(seedMaterial, hd.seedLength)
|
seed := hd.derive(seedMaterial, hd.seedLength)
|
||||||
|
// V = seed
|
||||||
copy(hd.v, seed)
|
copy(hd.v, seed)
|
||||||
|
|
||||||
|
// C = Hash_df(0x00 || V, seed_length)
|
||||||
temp := make([]byte, hd.seedLength+1)
|
temp := make([]byte, hd.seedLength+1)
|
||||||
temp[0] = 0
|
temp[0] = 0
|
||||||
copy(temp[1:], seed)
|
copy(temp[1:], seed)
|
||||||
seed = hd.derive(temp, hd.seedLength)
|
seed = hd.derive(temp, hd.seedLength)
|
||||||
copy(hd.c, seed)
|
copy(hd.c, seed)
|
||||||
|
|
||||||
hd.reseedCounter = 1
|
hd.reseedCounter = 1
|
||||||
hd.reseedTime = time.Now()
|
hd.reseedTime = time.Now()
|
||||||
|
|
||||||
@ -79,7 +86,7 @@ func NewGMHashDrbg(securityLevel SecurityLevel, 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 || len(entropy) >= MAX_BYTES {
|
if len(entropy) == 0 || (hd.gm && len(entropy) < hd.md.Size()) || len(entropy) >= MAX_BYTES {
|
||||||
return errors.New("invalid entropy length")
|
return errors.New("invalid entropy length")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,23 +95,28 @@ func (hd *HashDrbg) Reseed(entropy, additional []byte) error {
|
|||||||
}
|
}
|
||||||
seedMaterial := make([]byte, len(entropy)+hd.seedLength+len(additional)+1)
|
seedMaterial := make([]byte, len(entropy)+hd.seedLength+len(additional)+1)
|
||||||
seedMaterial[0] = 1
|
seedMaterial[0] = 1
|
||||||
|
if hd.gm { // seed_material = 0x01 || entropy_input || V || additional_input
|
||||||
if hd.gm { // entropy_input || V || additional_input
|
|
||||||
copy(seedMaterial[1:], entropy)
|
copy(seedMaterial[1:], entropy)
|
||||||
copy(seedMaterial[len(entropy)+1:], hd.v)
|
copy(seedMaterial[len(entropy)+1:], hd.v)
|
||||||
} else { // V || entropy_input || additional_input
|
} else { // seed_material = 0x01 || V || entropy_input || additional_input
|
||||||
copy(seedMaterial[1:], hd.v)
|
copy(seedMaterial[1:], hd.v)
|
||||||
copy(seedMaterial[hd.seedLength+1:], entropy)
|
copy(seedMaterial[hd.seedLength+1:], entropy)
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(seedMaterial[len(entropy)+hd.seedLength+1:], additional)
|
copy(seedMaterial[len(entropy)+hd.seedLength+1:], additional)
|
||||||
|
|
||||||
|
// seed = Hash_df(seed_material, seed_length)
|
||||||
seed := hd.derive(seedMaterial, hd.seedLength)
|
seed := hd.derive(seedMaterial, hd.seedLength)
|
||||||
|
|
||||||
|
// V = seed
|
||||||
copy(hd.v, seed)
|
copy(hd.v, seed)
|
||||||
temp := make([]byte, hd.seedLength+1)
|
temp := make([]byte, hd.seedLength+1)
|
||||||
|
|
||||||
|
// C = Hash_df(0x01 || V, seed_length)
|
||||||
temp[0] = 0
|
temp[0] = 0
|
||||||
copy(temp[1:], seed)
|
copy(temp[1:], seed)
|
||||||
seed = hd.derive(temp, hd.seedLength)
|
seed = hd.derive(temp, hd.seedLength)
|
||||||
copy(hd.c, seed)
|
copy(hd.c, seed)
|
||||||
|
|
||||||
hd.reseedCounter = 1
|
hd.reseedCounter = 1
|
||||||
hd.reseedTime = time.Now()
|
hd.reseedTime = time.Now()
|
||||||
return nil
|
return nil
|
||||||
@ -140,7 +152,7 @@ func (hd *HashDrbg) MaxBytesPerRequest() int {
|
|||||||
return MAX_BYTES_PER_GENERATE
|
return MAX_BYTES_PER_GENERATE
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate hash DRBG generate process. GM/T 0105-2021 has a little different with NIST.
|
// Generate hash DRBG pseudorandom bits process. GM/T 0105-2021 has a little different with NIST.
|
||||||
// GM/T 0105-2021 can only generate no more than hash.Size bytes once.
|
// GM/T 0105-2021 can only generate no more than hash.Size bytes once.
|
||||||
func (hd *HashDrbg) Generate(b, additional []byte) error {
|
func (hd *HashDrbg) Generate(b, additional []byte) error {
|
||||||
if hd.NeedReseed() {
|
if hd.NeedReseed() {
|
||||||
@ -151,6 +163,9 @@ func (hd *HashDrbg) Generate(b, additional []byte) error {
|
|||||||
}
|
}
|
||||||
md := hd.md
|
md := hd.md
|
||||||
m := len(b)
|
m := len(b)
|
||||||
|
|
||||||
|
// if len(additional_input) > 0, then
|
||||||
|
// w = Hash(0x02 || V || additional_input)
|
||||||
if len(additional) > 0 {
|
if len(additional) > 0 {
|
||||||
md.Write([]byte{0x02})
|
md.Write([]byte{0x02})
|
||||||
md.Write(hd.v)
|
md.Write(hd.v)
|
||||||
@ -159,7 +174,7 @@ func (hd *HashDrbg) Generate(b, additional []byte) error {
|
|||||||
md.Reset()
|
md.Reset()
|
||||||
hd.addW(w)
|
hd.addW(w)
|
||||||
}
|
}
|
||||||
if hd.gm { // leftmost(HASH(V))
|
if hd.gm { // leftmost(Hash(V))
|
||||||
md.Write(hd.v)
|
md.Write(hd.v)
|
||||||
copy(b, md.Sum(nil))
|
copy(b, md.Sum(nil))
|
||||||
md.Reset()
|
md.Reset()
|
||||||
@ -174,6 +189,7 @@ func (hd *HashDrbg) Generate(b, additional []byte) error {
|
|||||||
md.Reset()
|
md.Reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// V = (V + H + C + reseed_counter) mode 2^seed_length
|
||||||
hd.addH()
|
hd.addH()
|
||||||
hd.addC()
|
hd.addC()
|
||||||
hd.addReseedCounter()
|
hd.addReseedCounter()
|
||||||
@ -182,6 +198,7 @@ func (hd *HashDrbg) Generate(b, additional []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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.md
|
||||||
limit := uint64(len+md.Size()-1) / uint64(md.Size())
|
limit := uint64(len+md.Size()-1) / uint64(md.Size())
|
||||||
@ -190,6 +207,7 @@ func (hd *HashDrbg) derive(seedMaterial []byte, len int) []byte {
|
|||||||
var ct byte = 1
|
var ct byte = 1
|
||||||
k := make([]byte, len)
|
k := make([]byte, len)
|
||||||
for i := 0; i < int(limit); i++ {
|
for i := 0; i < int(limit); i++ {
|
||||||
|
// Hash( counter_byte || return_bits || seed_material )
|
||||||
md.Write([]byte{ct})
|
md.Write([]byte{ct})
|
||||||
md.Write(requireBytes[:])
|
md.Write(requireBytes[:])
|
||||||
md.Write(seedMaterial)
|
md.Write(seedMaterial)
|
||||||
|
@ -185,7 +185,7 @@ func TestHashDRBG(t *testing.T) {
|
|||||||
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.md, SECURITY_LEVEL_ONE, test.gm, entropyInput, nonce, personalizationString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(hd.v[:len(v0)], v0) {
|
if !bytes.Equal(hd.v[:len(v0)], v0) {
|
||||||
t.Errorf("not same v0 %s", hex.EncodeToString(hd.v[:len(v0)]))
|
t.Errorf("not same v0 %s", hex.EncodeToString(hd.v[:len(v0)]))
|
||||||
@ -200,7 +200,7 @@ func TestHashDRBG(t *testing.T) {
|
|||||||
c1, _ := hex.DecodeString(test.c1)
|
c1, _ := hex.DecodeString(test.c1)
|
||||||
err = hd.Reseed(entropyInputReseed, additionalInputReseed)
|
err = hd.Reseed(entropyInputReseed, additionalInputReseed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(hd.v[:len(v0)], v1) {
|
if !bytes.Equal(hd.v[:len(v0)], v1) {
|
||||||
t.Errorf("not same v1 %s", hex.EncodeToString(hd.v[:len(v0)]))
|
t.Errorf("not same v1 %s", hex.EncodeToString(hd.v[:len(v0)]))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user