]> git.saurik.com Git - apple/xnu.git/blob - osfmk/corecrypto/ccdrbg_nisthmac.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / corecrypto / ccdrbg_nisthmac.c
1 /*
2 * ccdrbg_nisthmac.c
3 * corecrypto
4 *
5 * Created on 05/09/2014
6 *
7 * Copyright (c) 2014,2015 Apple Inc. All rights reserved.
8 *
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@
33 */
34
35 #include <stdbool.h>
36
37 #include <corecrypto/cc_priv.h>
38 #include <corecrypto/ccdrbg.h>
39 #include <corecrypto/cchmac.h>
40 #include <corecrypto/ccsha2.h>
41 #include <corecrypto/cc_macros.h>
42
43 // This HMAC DRBG is described in:
44
45 // NIST SP 800-90A Rev. 1
46 // Recommendation for Random Number Generation Using Deterministic Random Bit Generators
47 // June 2015
48
49 // See in particular:
50 // - 9 DRBG Mechanism Functions
51 // - 10.1.2 HMAC_DRBG
52 // - B.2 HMAC_DRBGExample
53
54 #define NISTHMAC_MAX_OUTPUT_SIZE (CCSHA512_OUTPUT_SIZE)
55
56 #define MIN_REQ_ENTROPY(di) ((di)->output_size / 2)
57
58 struct ccdrbg_nisthmac_state {
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;
63 };
64
65 #define DRBG_NISTHMAC_DEBUG 0
66
67 #if DRBG_NISTHMAC_DEBUG
68 #include <corecrypto/cc_debug.h>
69
70 static void
71 dump_state(const char *label, struct ccdrbg_nisthmac_state *drbg_ctx)
72 {
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);
77 }
78 #endif
79
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;
96
97 cchmac_di_decl(info, hmac_ctx);
98
99 for (uint8_t b = 0; b < 2; b += 1) {
100 cchmac_init(info, hmac_ctx, outlen, drbg_ctx->key);
101
102 cchmac_update(info, hmac_ctx, outlen, drbg_ctx->V);
103
104 cchmac_update(info, hmac_ctx, sizeof(b), &b);
105
106 va_start(args, ndata);
107
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 *);
111
112 cchmac_update(info, hmac_ctx, nbytes, buf);
113
114 data_nbytes += nbytes;
115 }
116
117 va_end(args);
118
119 cchmac_final(info, hmac_ctx, drbg_ctx->key);
120
121 cchmac(info, outlen, drbg_ctx->key, outlen, drbg_ctx->V, drbg_ctx->V);
122
123 if (data_nbytes == 0) {
124 break;
125 }
126 }
127
128 cchmac_di_clear(info, hmac_ctx);
129 }
130
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 }
136
137 // See NIST SP 800-90A, Rev. 1, 9.1 and 10.1.2.3
138 static int
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)
147 {
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;
152
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);
157
158 status = CCDRBG_STATUS_OK;
159
160 cc_memset(drbg_ctx->key, 0, outlen);
161 cc_memset(drbg_ctx->V, 1, outlen);
162
163 update(ctx, 3, entropy_nbytes, entropy, nonce_nbytes, nonce, ps_nbytes, ps);
164
165 drbg_ctx->reseed_counter = 1;
166
167 out:
168 return status;
169 }
170
171 static bool
172 add_isvalid(size_t add_nbytes)
173 {
174 return add_nbytes <= CCDRBG_MAX_ADDITIONALINPUT_SIZE;
175 }
176
177 // See NIST SP 800-90A, Rev. 1, 9.2 and 10.1.2.4
178 static int
179 reseed(struct ccdrbg_state *ctx, size_t entropy_nbytes, const void *entropy, size_t add_nbytes, const void *add)
180 {
181 struct ccdrbg_nisthmac_state *drbg_ctx = (struct ccdrbg_nisthmac_state *)ctx;
182 const struct ccdigest_info *digest_info = drbg_ctx->custom->di;
183
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);
187
188 status = CCDRBG_STATUS_OK;
189
190 update(ctx, 2, entropy_nbytes, entropy, add_nbytes, add);
191
192 drbg_ctx->reseed_counter = 1;
193
194 out:
195 return status;
196 }
197
198 // See NIST SP 800-90A, Rev. 1, 9.3 and 10.1.2.5
199 static int
200 generate(struct ccdrbg_state *ctx, size_t out_nbytes, void *out, size_t add_nbytes, const void *add)
201 {
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;
205
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);
209
210 status = CCDRBG_STATUS_NEED_RESEED;
211 cc_require(drbg_ctx->reseed_counter <= CCDRBG_RESEED_INTERVAL || !drbg_ctx->custom->strictFIPS, out);
212
213 status = CCDRBG_STATUS_OK;
214
215 if (add_nbytes > 0) {
216 update(ctx, 1, add_nbytes, add);
217 }
218
219 uint8_t *out_bytes = out;
220 uint8_t Vprev[NISTHMAC_MAX_OUTPUT_SIZE];
221
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;
232 }
233
234 size_t n = CC_MIN(out_nbytes, outlen);
235 cc_memcpy(out_bytes, drbg_ctx->V, n);
236
237 out_bytes += n;
238 out_nbytes -= n;
239 }
240
241 update(ctx, 1, add_nbytes, add);
242
243 drbg_ctx->reseed_counter += 1;
244
245 out:
246 cc_clear(outlen, Vprev);
247 return status;
248 }
249
250 void
251 ccdrbg_factory_nisthmac(struct ccdrbg_info *info, const struct ccdrbg_nisthmac_custom *custom)
252 {
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;
259 };