| // Copyright (c) 2021, Google Inc. |
| // |
| // Permission to use, copy, modify, and/or distribute this software for any |
| // purpose with or without fee is hereby granted, provided that the above |
| // copyright notice and this permission notice appear in all copies. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| |
| package main |
| |
| import ( |
| "crypto/hmac" |
| "crypto/sha256" |
| ) |
| |
| // See SP 800-90Ar1, section 10.1.2 |
| type HMACDRBGSHA256 struct { |
| k, v [32]byte |
| } |
| |
| func NewHMACDRBG(entropy, nonce, personalisation []byte) *HMACDRBGSHA256 { |
| ret := new(HMACDRBGSHA256) |
| ret.init(entropy, nonce, personalisation) |
| return ret |
| } |
| |
| func (drbg *HMACDRBGSHA256) init(entropy, nonce, personalisation []byte) { |
| for i := range drbg.k { |
| drbg.k[i] = 0 |
| } |
| for i := range drbg.v { |
| drbg.v[i] = 1 |
| } |
| |
| seed := make([]byte, 0, len(entropy)+len(nonce)+len(personalisation)) |
| seed = append(seed, entropy...) |
| seed = append(seed, nonce...) |
| seed = append(seed, personalisation...) |
| drbg.update(seed) |
| } |
| |
| func (drbg *HMACDRBGSHA256) update(data []byte) { |
| buf := make([]byte, 0, len(drbg.v)+1+len(data)) |
| buf = append(buf, drbg.v[:]...) |
| buf = append(buf, 0) |
| buf = append(buf, data...) |
| |
| mac := hmac.New(sha256.New, drbg.k[:]) |
| mac.Write(buf) |
| mac.Sum(drbg.k[:0]) |
| |
| mac = hmac.New(sha256.New, drbg.k[:]) |
| mac.Write(drbg.v[:]) |
| mac.Sum(drbg.v[:0]) |
| |
| if len(data) > 0 { |
| copy(buf, drbg.v[:]) |
| buf[len(drbg.v)] = 1 |
| |
| mac = hmac.New(sha256.New, drbg.k[:]) |
| mac.Write(buf) |
| mac.Sum(drbg.k[:0]) |
| |
| mac = hmac.New(sha256.New, drbg.k[:]) |
| mac.Write(drbg.v[:]) |
| mac.Sum(drbg.v[:0]) |
| } |
| } |
| |
| func (drbg *HMACDRBGSHA256) Reseed(entropy, additionalInput []byte) { |
| buf := make([]byte, 0, len(entropy)+len(additionalInput)) |
| buf = append(buf, entropy...) |
| buf = append(buf, additionalInput...) |
| drbg.update(buf) |
| } |
| |
| func (drbg *HMACDRBGSHA256) Generate(out []byte, additionalInput []byte) { |
| if len(additionalInput) > 0 { |
| drbg.update(additionalInput) |
| } |
| |
| done := 0 |
| for done < len(out) { |
| mac := hmac.New(sha256.New, drbg.k[:]) |
| mac.Write(drbg.v[:]) |
| mac.Sum(drbg.v[:0]) |
| |
| done += copy(out[done:], drbg.v[:]) |
| } |
| |
| drbg.update(additionalInput) |
| } |