github.com/emmansun/gmsm@v0.29.1/drbg/hash_drbg.go (about) 1 package drbg 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "hash" 7 "time" 8 9 "github.com/emmansun/gmsm/sm3" 10 ) 11 12 const HASH_DRBG_SEED_SIZE = 55 13 const HASH_DRBG_MAX_SEED_SIZE = 111 14 15 // HashDrbg hash DRBG structure, its instance is NOT goroutine safe!!! 16 type HashDrbg struct { 17 BaseDrbg 18 newHash func() hash.Hash 19 c []byte 20 hashSize int 21 } 22 23 // NewHashDrbg create one hash DRBG instance 24 func NewHashDrbg(newHash func() hash.Hash, securityLevel SecurityLevel, gm bool, entropy, nonce, personalization []byte) (*HashDrbg, error) { 25 hd := &HashDrbg{} 26 27 hd.gm = gm 28 hd.newHash = newHash 29 hd.setSecurityLevel(securityLevel) 30 31 md := newHash() 32 hd.hashSize = md.Size() 33 34 // here for the min length, we just check <=0 now 35 if len(entropy) == 0 || (hd.gm && len(entropy) < hd.hashSize) || len(entropy) >= MAX_BYTES { 36 return nil, errors.New("drbg: invalid entropy length") 37 } 38 39 // here for the min length, we just check <=0 now 40 if len(nonce) == 0 || (hd.gm && len(nonce) < hd.hashSize/2) || len(nonce) >= MAX_BYTES>>1 { 41 return nil, errors.New("drbg: invalid nonce length") 42 } 43 44 if len(personalization) >= MAX_BYTES { 45 return nil, errors.New("drbg: personalization is too long") 46 } 47 48 if hd.hashSize <= sm3.Size { 49 hd.v = make([]byte, HASH_DRBG_SEED_SIZE) 50 hd.c = make([]byte, HASH_DRBG_SEED_SIZE) 51 hd.seedLength = HASH_DRBG_SEED_SIZE 52 } else { 53 hd.v = make([]byte, HASH_DRBG_MAX_SEED_SIZE) 54 hd.c = make([]byte, HASH_DRBG_MAX_SEED_SIZE) 55 hd.seedLength = HASH_DRBG_MAX_SEED_SIZE 56 } 57 // seed_material = entropy_input || instantiation_nonce || personalization_string 58 seedMaterial := make([]byte, len(entropy)+len(nonce)+len(personalization)) 59 copy(seedMaterial, entropy) 60 copy(seedMaterial[len(entropy):], nonce) 61 copy(seedMaterial[len(entropy)+len(nonce):], personalization) 62 63 // seed = Hash_df(seed_material, seed_length) 64 seed := hd.derive(seedMaterial, hd.seedLength) 65 // V = seed 66 copy(hd.v, seed) 67 68 // C = Hash_df(0x00 || V, seed_length) 69 temp := make([]byte, hd.seedLength+1) 70 temp[0] = 0 71 copy(temp[1:], seed) 72 seed = hd.derive(temp, hd.seedLength) 73 copy(hd.c, seed) 74 75 hd.reseedCounter = 1 76 hd.reseedTime = time.Now() 77 78 return hd, nil 79 } 80 81 // NewNISTHashDrbg return hash DRBG implementation which follows NIST standard 82 func NewNISTHashDrbg(newHash func() hash.Hash, securityLevel SecurityLevel, entropy, nonce, personalization []byte) (*HashDrbg, error) { 83 return NewHashDrbg(newHash, securityLevel, false, entropy, nonce, personalization) 84 } 85 86 // NewGMHashDrbg return hash DRBG implementation which follows GM/T 0105-2021 standard 87 func NewGMHashDrbg(securityLevel SecurityLevel, entropy, nonce, personalization []byte) (*HashDrbg, error) { 88 return NewHashDrbg(sm3.New, securityLevel, true, entropy, nonce, personalization) 89 } 90 91 // Reseed hash DRBG reseed process. GM/T 0105-2021 has a little different with NIST. 92 func (hd *HashDrbg) Reseed(entropy, additional []byte) error { 93 // here for the min length, we just check <=0 now 94 if len(entropy) == 0 || (hd.gm && len(entropy) < hd.hashSize) || len(entropy) >= MAX_BYTES { 95 return errors.New("drbg: invalid entropy length") 96 } 97 98 if len(additional) >= MAX_BYTES { 99 return errors.New("drbg: additional input too long") 100 } 101 seedMaterial := make([]byte, len(entropy)+hd.seedLength+len(additional)+1) 102 seedMaterial[0] = 1 103 if hd.gm { // seed_material = 0x01 || entropy_input || V || additional_input 104 copy(seedMaterial[1:], entropy) 105 copy(seedMaterial[len(entropy)+1:], hd.v) 106 } else { // seed_material = 0x01 || V || entropy_input || additional_input 107 copy(seedMaterial[1:], hd.v) 108 copy(seedMaterial[hd.seedLength+1:], entropy) 109 } 110 copy(seedMaterial[len(entropy)+hd.seedLength+1:], additional) 111 112 // seed = Hash_df(seed_material, seed_length) 113 seed := hd.derive(seedMaterial, hd.seedLength) 114 115 // V = seed 116 copy(hd.v, seed) 117 temp := make([]byte, hd.seedLength+1) 118 119 // C = Hash_df(0x01 || V, seed_length) 120 temp[0] = 0 121 copy(temp[1:], seed) 122 seed = hd.derive(temp, hd.seedLength) 123 copy(hd.c, seed) 124 125 hd.reseedCounter = 1 126 hd.reseedTime = time.Now() 127 return nil 128 } 129 130 func (hd *HashDrbg) addW(w []byte) { 131 t := make([]byte, hd.seedLength) 132 copy(t[hd.seedLength-len(w):], w) 133 add(t, hd.v, hd.seedLength) 134 } 135 136 func (hd *HashDrbg) addC() { 137 add(hd.c, hd.v, hd.seedLength) 138 } 139 140 func (hd *HashDrbg) addH() { 141 md := hd.newHash() 142 md.Write([]byte{0x03}) 143 md.Write(hd.v) 144 hd.addW(md.Sum(nil)) 145 } 146 147 func (hd *HashDrbg) addReseedCounter() { 148 t := make([]byte, hd.seedLength) 149 binary.BigEndian.PutUint64(t[hd.seedLength-8:], hd.reseedCounter) 150 add(t, hd.v, hd.seedLength) 151 } 152 153 func (hd *HashDrbg) MaxBytesPerRequest() int { 154 if hd.gm { 155 return hd.hashSize 156 } 157 return MAX_BYTES_PER_GENERATE 158 } 159 160 // Generate hash DRBG pseudorandom bits process. GM/T 0105-2021 has a little different with NIST. 161 // GM/T 0105-2021 can only generate no more than hash.Size bytes once. 162 func (hd *HashDrbg) Generate(b, additional []byte) error { 163 if hd.NeedReseed() { 164 return ErrReseedRequired 165 } 166 if (hd.gm && len(b) > hd.hashSize) || (!hd.gm && len(b) > MAX_BYTES_PER_GENERATE) { 167 return errors.New("drbg: too many bytes requested") 168 } 169 md := hd.newHash() 170 m := len(b) 171 172 // if len(additional_input) > 0, then 173 // w = Hash(0x02 || V || additional_input) 174 if len(additional) > 0 { 175 md.Write([]byte{0x02}) 176 md.Write(hd.v) 177 md.Write(additional) 178 w := md.Sum(nil) 179 md.Reset() 180 hd.addW(w) 181 } 182 if hd.gm { // leftmost(Hash(V)) 183 md.Write(hd.v) 184 copy(b, md.Sum(nil)) 185 md.Reset() 186 } else { 187 limit := uint64(m+md.Size()-1) / uint64(md.Size()) 188 data := make([]byte, hd.seedLength) 189 copy(data, hd.v) 190 for i := 0; i < int(limit); i++ { 191 md.Write(data) 192 copy(b[i*md.Size():], md.Sum(nil)) 193 addOne(data, hd.seedLength) 194 md.Reset() 195 } 196 } 197 // V = (V + H + C + reseed_counter) mode 2^seed_length 198 hd.addH() 199 hd.addC() 200 hd.addReseedCounter() 201 202 hd.reseedCounter++ 203 return nil 204 } 205 206 // derive Hash_df 207 func (hd *HashDrbg) derive(seedMaterial []byte, len int) []byte { 208 md := hd.newHash() 209 limit := uint64(len+hd.hashSize-1) / uint64(hd.hashSize) 210 var requireBytes [4]byte 211 binary.BigEndian.PutUint32(requireBytes[:], uint32(len<<3)) 212 var ct byte = 1 213 k := make([]byte, len) 214 for i := 0; i < int(limit); i++ { 215 // Hash( counter_byte || return_bits || seed_material ) 216 md.Write([]byte{ct}) 217 md.Write(requireBytes[:]) 218 md.Write(seedMaterial) 219 copy(k[i*md.Size():], md.Sum(nil)) 220 ct++ 221 md.Reset() 222 } 223 return k 224 }