/ src / rand / aesctr_drbg.c
aesctr_drbg.c
  1  /*
  2   * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
  3   *
  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:
 11   *
 12   * The above copyright notice and this permission notice shall be 
 13   * included in all copies or substantial portions of the Software.
 14   *
 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
 22   * SOFTWARE.
 23   */
 24  
 25  #include "inner.h"
 26  
 27  /* see bearssl_rand.h */
 28  void
 29  br_aesctr_drbg_init(br_aesctr_drbg_context *ctx,
 30  	const br_block_ctr_class *aesctr,
 31  	const void *seed, size_t len)
 32  {
 33  	unsigned char tmp[16];
 34  
 35  	ctx->vtable = &br_aesctr_drbg_vtable;
 36  	memset(tmp, 0, sizeof tmp);
 37  	aesctr->init(&ctx->sk.vtable, tmp, 16);
 38  	ctx->cc = 0;
 39  	br_aesctr_drbg_update(ctx, seed, len);
 40  }
 41  
 42  /* see bearssl_rand.h */
 43  void
 44  br_aesctr_drbg_generate(br_aesctr_drbg_context *ctx, void *out, size_t len)
 45  {
 46  	unsigned char *buf;
 47  	unsigned char iv[12];
 48  
 49  	buf = out;
 50  	memset(iv, 0, sizeof iv);
 51  	while (len > 0) {
 52  		size_t clen;
 53  
 54  		/*
 55  		 * We generate data by blocks of at most 65280 bytes. This
 56  		 * allows for unambiguously testing the counter overflow
 57  		 * condition; also, it should work on 16-bit architectures
 58  		 * (where 'size_t' is 16 bits only).
 59  		 */
 60  		clen = len;
 61  		if (clen > 65280) {
 62  			clen = 65280;
 63  		}
 64  
 65  		/*
 66  		 * We make sure that the counter won't exceed the configured
 67  		 * limit.
 68  		 */
 69  		if ((uint32_t)(ctx->cc + ((clen + 15) >> 4)) > 32768) {
 70  			clen = (32768 - ctx->cc) << 4;
 71  			if (clen > len) {
 72  				clen = len;
 73  			}
 74  		}
 75  
 76  		/*
 77  		 * Run CTR.
 78  		 */
 79  		memset(buf, 0, clen);
 80  		ctx->cc = ctx->sk.vtable->run(&ctx->sk.vtable,
 81  			iv, ctx->cc, buf, clen);
 82  		buf += clen;
 83  		len -= clen;
 84  
 85  		/*
 86  		 * Every 32768 blocks, we force a state update.
 87  		 */
 88  		if (ctx->cc >= 32768) {
 89  			br_aesctr_drbg_update(ctx, NULL, 0);
 90  		}
 91  	}
 92  }
 93  
 94  /* see bearssl_rand.h */
 95  void
 96  br_aesctr_drbg_update(br_aesctr_drbg_context *ctx, const void *seed, size_t len)
 97  {
 98  	/*
 99  	 * We use a Hirose construction on AES-256 to make a hash function.
100  	 * Function definition:
101  	 *  - running state consists in two 16-byte blocks G and H
102  	 *  - initial values of G and H are conventional
103  	 *  - there is a fixed block-sized constant C
104  	 *  - for next data block m:
105  	 *      set AES key to H||m
106  	 *      G' = E(G) xor G
107  	 *      H' = E(G xor C) xor G xor C
108  	 *      G <- G', H <- H'
109  	 *  - once all blocks have been processed, output is H||G
110  	 *
111  	 * Constants:
112  	 *   G_init = B6 B6 ... B6
113  	 *   H_init = A5 A5 ... A5
114  	 *   C      = 01 00 ... 00
115  	 *
116  	 * With this hash function h(), we compute the new state as
117  	 * follows:
118  	 *  - produce a state-dependent value s as encryption of an
119  	 *    all-one block with AES and the current key
120  	 *  - compute the new key as the first 128 bits of h(s||seed)
121  	 *
122  	 * Original Hirose article:
123  	 *    https://www.iacr.org/archive/fse2006/40470213/40470213.pdf
124  	 */
125  
126  	unsigned char s[16], iv[12];
127  	unsigned char G[16], H[16];
128  	int first;
129  
130  	/*
131  	 * Use an all-one IV to get a fresh output block that depends on the
132  	 * current seed.
133  	 */
134  	memset(iv, 0xFF, sizeof iv);
135  	memset(s, 0, 16);
136  	ctx->sk.vtable->run(&ctx->sk.vtable, iv, 0xFFFFFFFF, s, 16);
137  
138  	/*
139  	 * Set G[] and H[] to conventional start values.
140  	 */
141  	memset(G, 0xB6, sizeof G);
142  	memset(H, 0x5A, sizeof H);
143  
144  	/*
145  	 * Process the concatenation of the current state and the seed
146  	 * with the custom hash function.
147  	 */
148  	first = 1;
149  	for (;;) {
150  		unsigned char tmp[32];
151  		unsigned char newG[16];
152  
153  		/*
154  		 * Assemble new key H||m into tmp[].
155  		 */
156  		memcpy(tmp, H, 16);
157  		if (first) {
158  			memcpy(tmp + 16, s, 16);
159  			first = 0;
160  		} else {
161  			size_t clen;
162  
163  			if (len == 0) {
164  				break;
165  			}
166  			clen = len < 16 ? len : 16;
167  			memcpy(tmp + 16, seed, clen);
168  			memset(tmp + 16 + clen, 0, 16 - clen);
169  			seed = (const unsigned char *)seed + clen;
170  			len -= clen;
171  		}
172  		ctx->sk.vtable->init(&ctx->sk.vtable, tmp, 32);
173  
174  		/*
175  		 * Compute new G and H values.
176  		 */
177  		memcpy(iv, G, 12);
178  		memcpy(newG, G, 16);
179  		ctx->sk.vtable->run(&ctx->sk.vtable, iv,
180  			br_dec32be(G + 12), newG, 16);
181  		iv[0] ^= 0x01;
182  		memcpy(H, G, 16);
183  		H[0] ^= 0x01;
184  		ctx->sk.vtable->run(&ctx->sk.vtable, iv,
185  			br_dec32be(G + 12), H, 16);
186  		memcpy(G, newG, 16);
187  	}
188  
189  	/*
190  	 * Output hash value is H||G. We truncate it to its first 128 bits,
191  	 * i.e. H; that's our new AES key.
192  	 */
193  	ctx->sk.vtable->init(&ctx->sk.vtable, H, 16);
194  	ctx->cc = 0;
195  }
196  
197  /* see bearssl_rand.h */
198  const br_prng_class br_aesctr_drbg_vtable = {
199  	sizeof(br_aesctr_drbg_context),
200  	(void (*)(const br_prng_class **, const void *, const void *, size_t))
201  		&br_aesctr_drbg_init,
202  	(void (*)(const br_prng_class **, void *, size_t))
203  		&br_aesctr_drbg_generate,
204  	(void (*)(const br_prng_class **, const void *, size_t))
205  		&br_aesctr_drbg_update
206  };