]>
Commit | Line | Data |
---|---|---|
fe8ab488 A |
1 | /* |
2 | * ccdrbg_nisthmac.c | |
3 | * corecrypto | |
4 | * | |
3e170ce0 A |
5 | * Created on 05/09/2014 |
6 | * | |
7 | * Copyright (c) 2014,2015 Apple Inc. All rights reserved. | |
fe8ab488 | 8 | * |
5ba3f43e A |
9 | * |
10 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
11 | * | |
12 | * This file contains Original Code and/or Modifications of Original Code | |
13 | * as defined in and that are subject to the Apple Public Source License | |
14 | * Version 2.0 (the 'License'). You may not use this file except in | |
15 | * compliance with the License. The rights granted to you under the License | |
16 | * may not be used to create, or enable the creation or redistribution of, | |
17 | * unlawful or unlicensed copies of an Apple operating system, or to | |
18 | * circumvent, violate, or enable the circumvention or violation of, any | |
19 | * terms of an Apple operating system software license agreement. | |
20 | * | |
21 | * Please obtain a copy of the License at | |
22 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
23 | * | |
24 | * The Original Code and all software distributed under the License are | |
25 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
26 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
27 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
28 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
29 | * Please see the License for the specific language governing rights and | |
30 | * limitations under the License. | |
31 | * | |
32 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
fe8ab488 A |
33 | */ |
34 | ||
cb323159 A |
35 | #include <stdbool.h> |
36 | ||
37 | #include <corecrypto/cc_priv.h> | |
fe8ab488 A |
38 | #include <corecrypto/ccdrbg.h> |
39 | #include <corecrypto/cchmac.h> | |
40 | #include <corecrypto/ccsha2.h> | |
3e170ce0 | 41 | #include <corecrypto/cc_macros.h> |
fe8ab488 | 42 | |
cb323159 | 43 | // This HMAC DRBG is described in: |
fe8ab488 | 44 | |
cb323159 A |
45 | // NIST SP 800-90A Rev. 1 |
46 | // Recommendation for Random Number Generation Using Deterministic Random Bit Generators | |
47 | // June 2015 | |
fe8ab488 | 48 | |
cb323159 A |
49 | // See in particular: |
50 | // - 9 DRBG Mechanism Functions | |
51 | // - 10.1.2 HMAC_DRBG | |
52 | // - B.2 HMAC_DRBGExample | |
fe8ab488 | 53 | |
cb323159 | 54 | #define NISTHMAC_MAX_OUTPUT_SIZE (CCSHA512_OUTPUT_SIZE) |
3e170ce0 | 55 | |
cb323159 | 56 | #define MIN_REQ_ENTROPY(di) ((di)->output_size / 2) |
fe8ab488 A |
57 | |
58 | struct ccdrbg_nisthmac_state { | |
cb323159 A |
59 | const struct ccdrbg_nisthmac_custom *custom; |
60 | uint8_t key[NISTHMAC_MAX_OUTPUT_SIZE]; | |
61 | uint8_t V[NISTHMAC_MAX_OUTPUT_SIZE]; | |
62 | uint64_t reseed_counter; | |
fe8ab488 A |
63 | }; |
64 | ||
39037602 A |
65 | #define DRBG_NISTHMAC_DEBUG 0 |
66 | ||
39037602 | 67 | #if DRBG_NISTHMAC_DEBUG |
cb323159 | 68 | #include <corecrypto/cc_debug.h> |
5ba3f43e | 69 | |
0a7de745 | 70 | static void |
cb323159 | 71 | dump_state(const char *label, struct ccdrbg_nisthmac_state *drbg_ctx) |
0a7de745 | 72 | { |
cb323159 A |
73 | size_t outlen = drbg_ctx->custom->di->output_size; |
74 | ||
75 | cc_print(label, outlen, drbg_ctx->key); | |
76 | cc_print(label, outlen, drbg_ctx->V); | |
fe8ab488 A |
77 | } |
78 | #endif | |
79 | ||
cb323159 A |
80 | // See NIST SP 800-90A, Rev. 1, 9.4 |
81 | static void | |
82 | done(struct ccdrbg_state *ctx) | |
83 | { | |
84 | cc_clear(sizeof(struct ccdrbg_nisthmac_state), ctx); | |
85 | } | |
86 | ||
87 | // See NIST SP 800-90A, Rev. 1, 10.1.2.2 | |
88 | static void | |
89 | update(struct ccdrbg_state *ctx, unsigned ndata, ...) | |
90 | { | |
91 | struct ccdrbg_nisthmac_state *drbg_ctx = (struct ccdrbg_nisthmac_state *)ctx; | |
92 | const struct ccdigest_info *info = drbg_ctx->custom->di; | |
93 | size_t outlen = info->output_size; | |
94 | size_t data_nbytes = 0; | |
95 | va_list args; | |
39037602 | 96 | |
cb323159 | 97 | cchmac_di_decl(info, hmac_ctx); |
39037602 | 98 | |
cb323159 A |
99 | for (uint8_t b = 0; b < 2; b += 1) { |
100 | cchmac_init(info, hmac_ctx, outlen, drbg_ctx->key); | |
fe8ab488 | 101 | |
cb323159 | 102 | cchmac_update(info, hmac_ctx, outlen, drbg_ctx->V); |
fe8ab488 | 103 | |
cb323159 | 104 | cchmac_update(info, hmac_ctx, sizeof(b), &b); |
fe8ab488 | 105 | |
cb323159 | 106 | va_start(args, ndata); |
0a7de745 | 107 | |
cb323159 A |
108 | for (unsigned i = 0; i < ndata; i += 1) { |
109 | size_t nbytes = va_arg(args, size_t); | |
110 | const void *buf = va_arg(args, const void *); | |
0a7de745 | 111 | |
cb323159 | 112 | cchmac_update(info, hmac_ctx, nbytes, buf); |
0a7de745 | 113 | |
cb323159 | 114 | data_nbytes += nbytes; |
0a7de745 | 115 | } |
5ba3f43e | 116 | |
cb323159 | 117 | va_end(args); |
5ba3f43e | 118 | |
cb323159 | 119 | cchmac_final(info, hmac_ctx, drbg_ctx->key); |
5ba3f43e | 120 | |
cb323159 | 121 | cchmac(info, outlen, drbg_ctx->key, outlen, drbg_ctx->V, drbg_ctx->V); |
5ba3f43e | 122 | |
cb323159 A |
123 | if (data_nbytes == 0) { |
124 | break; | |
125 | } | |
126 | } | |
5ba3f43e | 127 | |
cb323159 | 128 | cchmac_di_clear(info, hmac_ctx); |
fe8ab488 A |
129 | } |
130 | ||
cb323159 A |
131 | static bool |
132 | entropy_isvalid(size_t entropy_nbytes, const struct ccdigest_info *info) | |
133 | { | |
134 | return (entropy_nbytes <= CCDRBG_MAX_ENTROPY_SIZE) && (entropy_nbytes >= MIN_REQ_ENTROPY(info)); | |
135 | } | |
fe8ab488 | 136 | |
cb323159 | 137 | // See NIST SP 800-90A, Rev. 1, 9.1 and 10.1.2.3 |
0a7de745 | 138 | static int |
cb323159 A |
139 | init(const struct ccdrbg_info *info, |
140 | struct ccdrbg_state *ctx, | |
141 | size_t entropy_nbytes, | |
142 | const void *entropy, | |
143 | size_t nonce_nbytes, | |
144 | const void *nonce, | |
145 | size_t ps_nbytes, | |
146 | const void *ps) | |
fe8ab488 | 147 | { |
cb323159 A |
148 | struct ccdrbg_nisthmac_state *drbg_ctx = (struct ccdrbg_nisthmac_state *)ctx; |
149 | drbg_ctx->custom = info->custom; | |
150 | const struct ccdigest_info *digest_info = drbg_ctx->custom->di; | |
151 | size_t outlen = digest_info->output_size; | |
5ba3f43e | 152 | |
cb323159 A |
153 | int status = CCDRBG_STATUS_PARAM_ERROR; |
154 | cc_require(outlen <= NISTHMAC_MAX_OUTPUT_SIZE, out); | |
155 | cc_require(entropy_isvalid(entropy_nbytes, digest_info), out); | |
156 | cc_require(ps_nbytes <= CCDRBG_MAX_PSINPUT_SIZE, out); | |
5ba3f43e | 157 | |
cb323159 | 158 | status = CCDRBG_STATUS_OK; |
5ba3f43e | 159 | |
cb323159 A |
160 | cc_memset(drbg_ctx->key, 0, outlen); |
161 | cc_memset(drbg_ctx->V, 1, outlen); | |
5ba3f43e | 162 | |
cb323159 | 163 | update(ctx, 3, entropy_nbytes, entropy, nonce_nbytes, nonce, ps_nbytes, ps); |
5ba3f43e | 164 | |
cb323159 | 165 | drbg_ctx->reseed_counter = 1; |
5ba3f43e | 166 | |
cb323159 A |
167 | out: |
168 | return status; | |
fe8ab488 A |
169 | } |
170 | ||
cb323159 A |
171 | static bool |
172 | add_isvalid(size_t add_nbytes) | |
173 | { | |
174 | return add_nbytes <= CCDRBG_MAX_ADDITIONALINPUT_SIZE; | |
175 | } | |
3e170ce0 | 176 | |
cb323159 | 177 | // See NIST SP 800-90A, Rev. 1, 9.2 and 10.1.2.4 |
0a7de745 | 178 | static int |
cb323159 | 179 | reseed(struct ccdrbg_state *ctx, size_t entropy_nbytes, const void *entropy, size_t add_nbytes, const void *add) |
fe8ab488 | 180 | { |
cb323159 A |
181 | struct ccdrbg_nisthmac_state *drbg_ctx = (struct ccdrbg_nisthmac_state *)ctx; |
182 | const struct ccdigest_info *digest_info = drbg_ctx->custom->di; | |
5ba3f43e | 183 | |
cb323159 A |
184 | int status = CCDRBG_STATUS_PARAM_ERROR; |
185 | cc_require(entropy_isvalid(entropy_nbytes, digest_info), out); | |
186 | cc_require(add_isvalid(add_nbytes), out); | |
fe8ab488 | 187 | |
cb323159 | 188 | status = CCDRBG_STATUS_OK; |
fe8ab488 | 189 | |
cb323159 | 190 | update(ctx, 2, entropy_nbytes, entropy, add_nbytes, add); |
5ba3f43e | 191 | |
cb323159 | 192 | drbg_ctx->reseed_counter = 1; |
5ba3f43e | 193 | |
cb323159 A |
194 | out: |
195 | return status; | |
fe8ab488 A |
196 | } |
197 | ||
cb323159 | 198 | // See NIST SP 800-90A, Rev. 1, 9.3 and 10.1.2.5 |
0a7de745 | 199 | static int |
cb323159 | 200 | generate(struct ccdrbg_state *ctx, size_t out_nbytes, void *out, size_t add_nbytes, const void *add) |
3e170ce0 | 201 | { |
cb323159 A |
202 | struct ccdrbg_nisthmac_state *drbg_ctx = (struct ccdrbg_nisthmac_state *)ctx; |
203 | const struct ccdigest_info *info = drbg_ctx->custom->di; | |
204 | size_t outlen = info->output_size; | |
5ba3f43e | 205 | |
cb323159 A |
206 | int status = CCDRBG_STATUS_PARAM_ERROR; |
207 | cc_require(out_nbytes <= CCDRBG_MAX_REQUEST_SIZE, out); | |
208 | cc_require(add_isvalid(add_nbytes), out); | |
5ba3f43e | 209 | |
cb323159 A |
210 | status = CCDRBG_STATUS_NEED_RESEED; |
211 | cc_require(drbg_ctx->reseed_counter <= CCDRBG_RESEED_INTERVAL || !drbg_ctx->custom->strictFIPS, out); | |
5ba3f43e | 212 | |
cb323159 | 213 | status = CCDRBG_STATUS_OK; |
0a7de745 | 214 | |
cb323159 A |
215 | if (add_nbytes > 0) { |
216 | update(ctx, 1, add_nbytes, add); | |
0a7de745 A |
217 | } |
218 | ||
cb323159 A |
219 | uint8_t *out_bytes = out; |
220 | uint8_t Vprev[NISTHMAC_MAX_OUTPUT_SIZE]; | |
0a7de745 | 221 | |
cb323159 A |
222 | while (out_nbytes > 0) { |
223 | cc_memcpy(Vprev, drbg_ctx->V, outlen); | |
224 | cchmac(info, outlen, drbg_ctx->key, outlen, drbg_ctx->V, drbg_ctx->V); | |
225 | ||
226 | // See FIPS 140-2, 4.9.2 Conditional Tests | |
227 | if (cc_cmp_safe(outlen, Vprev, drbg_ctx->V) == 0) { | |
228 | done(ctx); | |
229 | status = CCDRBG_STATUS_ABORT; | |
230 | cc_try_abort(NULL); | |
231 | goto out; | |
0a7de745 | 232 | } |
39037602 | 233 | |
cb323159 A |
234 | size_t n = CC_MIN(out_nbytes, outlen); |
235 | cc_memcpy(out_bytes, drbg_ctx->V, n); | |
5ba3f43e | 236 | |
cb323159 A |
237 | out_bytes += n; |
238 | out_nbytes -= n; | |
239 | } | |
5ba3f43e | 240 | |
cb323159 | 241 | update(ctx, 1, add_nbytes, add); |
fe8ab488 | 242 | |
cb323159 | 243 | drbg_ctx->reseed_counter += 1; |
fe8ab488 | 244 | |
cb323159 A |
245 | out: |
246 | cc_clear(outlen, Vprev); | |
247 | return status; | |
248 | } | |
fe8ab488 | 249 | |
0a7de745 A |
250 | void |
251 | ccdrbg_factory_nisthmac(struct ccdrbg_info *info, const struct ccdrbg_nisthmac_custom *custom) | |
fe8ab488 | 252 | { |
0a7de745 A |
253 | info->size = sizeof(struct ccdrbg_nisthmac_state) + sizeof(struct ccdrbg_nisthmac_custom); |
254 | info->init = init; | |
255 | info->generate = generate; | |
256 | info->reseed = reseed; | |
257 | info->done = done; | |
258 | info->custom = custom; | |
fe8ab488 | 259 | }; |