github.com/emmansun/gmsm@v0.29.1/drbg/hmac_drbg.go (about) 1 package drbg 2 3 import ( 4 "crypto/hmac" 5 "errors" 6 "hash" 7 "time" 8 ) 9 10 // HmacDrbg hmac DRBG structure, its instance is NOT goroutine safe!!! 11 // The instance should be used in one goroutine only. 12 // Thera are NO hmac DRBR definition in GM/T 0105-2021 yet. 13 type HmacDrbg struct { 14 BaseDrbg 15 newHash func() hash.Hash 16 key []byte 17 hashSize int 18 } 19 20 // NewHmacDrbg create one hmac DRBG instance 21 func NewHmacDrbg(newHash func() hash.Hash, securityLevel SecurityLevel, gm bool, entropy, nonce, personalization []byte) (*HmacDrbg, error) { 22 hd := &HmacDrbg{} 23 24 hd.gm = gm 25 hd.newHash = newHash 26 hd.setSecurityLevel(securityLevel) 27 28 md := newHash() 29 hd.hashSize = md.Size() 30 31 // here for the min length, we just check <=0 now 32 if len(entropy) == 0 || len(entropy) >= MAX_BYTES { 33 return nil, errors.New("drbg: invalid entropy length") 34 } 35 36 // here for the min length, we just check <=0 now 37 if len(nonce) == 0 || len(nonce) >= MAX_BYTES>>1 { 38 return nil, errors.New("drbg: invalid nonce length") 39 } 40 41 if len(personalization) >= MAX_BYTES { 42 return nil, errors.New("drbg: personalization is too long") 43 } 44 45 // HMAC_DRBG_Instantiate_process 46 hd.key = make([]byte, hd.hashSize) 47 hd.v = make([]byte, hd.hashSize) 48 for i := 0; i < hd.hashSize; i++ { 49 hd.key[i] = 0x00 50 hd.v[i] = 0x01 51 } 52 hd.update(entropy, nonce, personalization) 53 hd.reseedCounter = 1 54 hd.reseedTime = time.Now() 55 56 return hd, nil 57 } 58 59 // NewNISTHmacDrbg return hmac DRBG implementation which follows NIST standard 60 func NewNISTHmacDrbg(newHash func() hash.Hash, securityLevel SecurityLevel, entropy, nonce, personalization []byte) (*HmacDrbg, error) { 61 return NewHmacDrbg(newHash, securityLevel, false, entropy, nonce, personalization) 62 } 63 64 // Generate generates pseudo random bytes usging HMAC_DRBG_Generate_process 65 func (hd *HmacDrbg) Generate(output, additional []byte) error { 66 // Step 1. If reseed_counter > reseed_interval, then return [ErrReseedRequired] that a reseed is required 67 if hd.NeedReseed() { 68 return ErrReseedRequired 69 } 70 // Step 2. If additional_input is provided, then do update 71 if len(additional) > 0 { 72 hd.update(additional) 73 } 74 requestedBytes := len(output) 75 md := hmac.New(hd.newHash, hd.key) 76 for ; requestedBytes > 0; requestedBytes -= hd.hashSize { 77 // 4.1. V = HMAC (Key, V) 78 md.Reset() 79 md.Write(hd.v) 80 hd.v = md.Sum(hd.v[:0]) 81 // 4.2. copy V to output 82 copy(output, hd.v) 83 if requestedBytes > hd.hashSize { 84 output = output[hd.hashSize:] 85 } 86 } 87 // Step 6. (Key, V) = HMAC_DRBG_Update (additional_input, Key, V) 88 hd.update(additional) 89 // Step 7. reseed_counter = reseed_counter + 1 90 hd.reseedCounter++ 91 return nil 92 } 93 94 // Reseed hash DRBG reseed process. GM/T 0105-2021 has a little different with NIST. 95 // reference to NIST.SP.800-90Ar1.pdf section 10.1.2.4 96 func (hd *HmacDrbg) Reseed(entropy, additional []byte) error { 97 // here for the min length, we just check <=0 now 98 if len(entropy) == 0 || (hd.gm && len(entropy) < hd.hashSize) || len(entropy) >= MAX_BYTES { 99 return errors.New("drbg: invalid entropy length") 100 } 101 102 if len(additional) >= MAX_BYTES { 103 return errors.New("drbg: additional input too long") 104 } 105 hd.update(entropy, additional) 106 hd.reseedCounter = 1 107 hd.reseedTime = time.Now() 108 return nil 109 } 110 111 func (hd *HmacDrbg) MaxBytesPerRequest() int { 112 return MAX_BYTES_PER_GENERATE 113 } 114 115 // The HMAC_DRBG_Update function updates the internal state of 116 // HMAC_DRBG using the provided_data. Note that for this DRBG mechanism, the 117 // HMAC_DRBG_Update function also serves as a derivation function for the 118 // instantiate and reseed functions. 119 func (hd *HmacDrbg) update(byteSlices ...[]byte) error { 120 // step 1. K = HMAC(K, V || 0x00 || provided_data) 121 md := hmac.New(hd.newHash, hd.key) 122 md.Write(hd.v) 123 md.Write([]byte{0x00}) 124 length := 0 125 for _, bytes := range byteSlices { 126 length += len(bytes) 127 if len(bytes) > 0 { 128 md.Write(bytes) 129 } 130 } 131 hd.key = md.Sum(hd.key[:0]) 132 // step 2. V = HMAC(K, V) 133 md = hmac.New(hd.newHash, hd.key) 134 md.Write(hd.v) 135 hd.v = md.Sum(hd.v[:0]) 136 // step 3. If provided_data = null, then return 137 if length == 0 { 138 return nil 139 } 140 // step 4. K = HMAC(K, V || 0x01 || provided_data) 141 md.Reset() 142 md.Write(hd.v) 143 md.Write([]byte{0x01}) 144 for _, bytes := range byteSlices { 145 if len(bytes) > 0 { 146 md.Write(bytes) 147 } 148 } 149 hd.key = md.Sum(hd.key[:0]) 150 // step 5. V = HMAC(K, V) 151 md = hmac.New(hd.newHash, hd.key) 152 md.Write(hd.v) 153 hd.v = md.Sum(hd.v[:0]) 154 return nil 155 }