1 //
2 //  rng.c
3 //
4 //  Created by Bassham, Lawrence E (Fed) on 8/29/17.
5 //  Copyright © 2017 Bassham, Lawrence E (Fed). All rights reserved.
6 //  SPDX-License-Identifier: Unknown
7 //  Modified for PQClean by Sebastian Verschoor
8 //
9 
10 #include "nistseedexpander.h"
11 #include "aes.h"
12 #include <string.h>
13 
14 /*
15  seedexpander_init()
16  ctx            - stores the current state of an instance of the seed expander
17  seed           - a 32 byte random value
18  diversifier    - an 8 byte diversifier
19  maxlen         - maximum number of bytes (less than 2**32) generated under this seed and diversifier
20  */
21 int
22 seedexpander_init(AES_XOF_struct *ctx,
23                   const uint8_t *seed,
24                   const uint8_t *diversifier,
25                   size_t maxlen) {
26 	ctx->length_remaining = maxlen;
27 
28 	memcpy(ctx->key, seed, 32);
29 	memcpy(ctx->ctr, diversifier, 8);
30 
31 	ctx->ctr[11] = (uint8_t) (maxlen % 256);
32 	maxlen >>= 8;
33 	ctx->ctr[10] = (uint8_t) (maxlen % 256);
34 	maxlen >>= 8;
35 	ctx->ctr[9] = (uint8_t) (maxlen % 256);
36 	maxlen >>= 8;
37 	ctx->ctr[8] = (uint8_t) (maxlen % 256);
38 	memset(ctx->ctr + 12, 0x00, 4);
39 
40 	ctx->buffer_pos = 16;
41 	memset(ctx->buffer, 0x00, 16);
42 
43 	return RNG_SUCCESS;
44 }
45 
46 static void AES256_ECB(uint8_t *key, uint8_t *ctr, uint8_t *buffer) {
47 	aes256ctx ctx;
48 	aes256_ecb_keyexp(&ctx, key);
49 	aes256_ecb(buffer, ctr, 1, &ctx);
50 	aes256_ctx_release(&ctx);
51 }
52 
53 /*
54  seedexpander()
55     ctx  - stores the current state of an instance of the seed expander
56     x    - returns the XOF data
57     xlen - number of bytes to return
58  */
59 int
60 seedexpander(AES_XOF_struct *ctx, uint8_t *x, size_t xlen) {
61 	size_t offset;
62 
63 	if ( x == NULL ) {
64 		return RNG_BAD_OUTBUF;
65 	}
66 	if ( xlen >= ctx->length_remaining ) {
67 		return RNG_BAD_REQ_LEN;
68 	}
69 
70 	ctx->length_remaining -= xlen;
71 
72 	offset = 0;
73 	while ( xlen > 0 ) {
74 		if ( xlen <= (16 - ctx->buffer_pos) ) { // buffer has what we need
75 			memcpy(x + offset, ctx->buffer + ctx->buffer_pos, xlen);
76 			ctx->buffer_pos += xlen;
77 
78 			return RNG_SUCCESS;
79 		}
80 
81 		// take what's in the buffer
82 		memcpy(x + offset, ctx->buffer + ctx->buffer_pos, 16 - ctx->buffer_pos);
83 		xlen -= 16 - ctx->buffer_pos;
84 		offset += 16 - ctx->buffer_pos;
85 
86 		AES256_ECB(ctx->key, ctx->ctr, ctx->buffer);
87 		ctx->buffer_pos = 0;
88 
89 		//increment the counter
90 		for (size_t i = 15; i >= 12; i--) {
91 			if ( ctx->ctr[i] == 0xff ) {
92 				ctx->ctr[i] = 0x00;
93 			} else {
94 				ctx->ctr[i]++;
95 				break;
96 			}
97 		}
98 
99 	}
100 
101 	return RNG_SUCCESS;
102 }
103