2 * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * Implementation of HMAC_DRBG (NIST SP800-90A).
32 * This class provides HMAC_DRBG as a deterministic PRNG from a given
33 * seed. Once a seed is set, chunks of data are obtained with
34 * GetBytes(). The GetBytes() methods can be called several times;
35 * the internal state is updated after each call. Setting a new seed
36 * resets the internal state.
39 public sealed class HMAC_DRBG {
46 * Create the instance over the provided hash function
47 * implementation. The digest instance is linked in and will
48 * be used repeatedly. The engine is not seeded yet.
50 public HMAC_DRBG(IDigest h)
52 hm = new HMAC(h.Dup());
53 int len = h.DigestSize;
61 * Reset the engine. A seed will have to be provided before
62 * generating pseudorandom bytes.
66 for (int i = 0; i < K.Length; i ++) {
74 * Reset the engine with the provided seed.
76 public void SetSeed(byte[] seed)
83 * Reset the engine with the provided seed.
85 public void SetSeed(byte[] seed, int off, int len)
88 Update(seed, off, len);
92 * Inject an additional seed. This may be null, in which case
93 * the state is modified but the engine is not marked as "seeded"
94 * (if it was not already marked so).
96 public void Update(byte[] seed)
99 Update(seed, 0, seed.Length);
106 * Inject an additional seed. If the seed length is 0, then the
107 * state is modified, but the engine is not marked as "seeded"
108 * (if it was not already marked so).
110 public void Update(byte[] seed, int off, int len)
112 /* K = HMAC_K(V || 0x00 || seed) */
114 hm.Update((byte)0x00);
115 hm.Update(seed, off, len);
124 * Stop there if the additional seed is empty.
130 /* K = HMAC_K(V || 0x01 || seed) */
132 hm.Update((byte)0x01);
133 hm.Update(seed, off, len);
142 * We get there only if a non-empty seed is used.
148 * Generate some pseudorandom bytes. The engine MUST have been
151 public void GetBytes(byte[] buf)
153 GetBytes(buf, 0, buf.Length);
157 * Generate some pseudorandom bytes. The engine MUST have been
160 public void GetBytes(byte[] buf, int off, int len)
163 throw new CryptoException(
164 "HMAC_DRBG engine was not seeded");
170 int clen = Math.Min(V.Length, len);
171 Array.Copy(V, 0, buf, off, clen);
176 /* K = HMAC_K(V || 0x00) */
178 hm.Update((byte)0x00);