]> git.saurik.com Git - apple/xnu.git/blame - osfmk/corecrypto/ccdrbg_nisthmac.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / corecrypto / ccdrbg_nisthmac.c
CommitLineData
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
58struct 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 70static void
cb323159 71dump_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
81static void
82done(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
88static void
89update(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
131static bool
132entropy_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 138static int
cb323159
A
139init(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
167out:
168 return status;
fe8ab488
A
169}
170
cb323159
A
171static bool
172add_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 178static int
cb323159 179reseed(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
194out:
195 return status;
fe8ab488
A
196}
197
cb323159 198// See NIST SP 800-90A, Rev. 1, 9.3 and 10.1.2.5
0a7de745 199static int
cb323159 200generate(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
245out:
246 cc_clear(outlen, Vprev);
247 return status;
248}
fe8ab488 249
0a7de745
A
250void
251ccdrbg_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};