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