5 * Created on 05/09/2014
7 * Copyright (c) 2014,2015 Apple Inc. All rights reserved.
10 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
21 * Please obtain a copy of the License at
22 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
32 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
43 // This HMAC DRBG is described in:
45 // NIST SP 800-90A Rev. 1
46 // Recommendation for Random Number Generation Using Deterministic Random Bit Generators
50 // - 9 DRBG Mechanism Functions
52 // - B.2 HMAC_DRBGExample
54 #define NISTHMAC_MAX_OUTPUT_SIZE (CCSHA512_OUTPUT_SIZE)
56 #define MIN_REQ_ENTROPY(di) ((di)->output_size / 2)
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
;
65 #define DRBG_NISTHMAC_DEBUG 0
67 #if DRBG_NISTHMAC_DEBUG
68 #include <corecrypto/cc_debug.h>
71 dump_state(const char *label
, struct ccdrbg_nisthmac_state
*drbg_ctx
)
73 size_t outlen
= drbg_ctx
->custom
->di
->output_size
;
75 cc_print(label
, outlen
, drbg_ctx
->key
);
76 cc_print(label
, outlen
, drbg_ctx
->V
);
80 // See NIST SP 800-90A, Rev. 1, 9.4
82 done(struct ccdrbg_state
*ctx
)
84 cc_clear(sizeof(struct ccdrbg_nisthmac_state
), ctx
);
87 // See NIST SP 800-90A, Rev. 1, 10.1.2.2
89 update(struct ccdrbg_state
*ctx
, unsigned ndata
, ...)
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;
97 cchmac_di_decl(info
, hmac_ctx
);
99 for (uint8_t b
= 0; b
< 2; b
+= 1) {
100 cchmac_init(info
, hmac_ctx
, outlen
, drbg_ctx
->key
);
102 cchmac_update(info
, hmac_ctx
, outlen
, drbg_ctx
->V
);
104 cchmac_update(info
, hmac_ctx
, sizeof(b
), &b
);
106 va_start(args
, ndata
);
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 *);
112 cchmac_update(info
, hmac_ctx
, nbytes
, buf
);
114 data_nbytes
+= nbytes
;
119 cchmac_final(info
, hmac_ctx
, drbg_ctx
->key
);
121 cchmac(info
, outlen
, drbg_ctx
->key
, outlen
, drbg_ctx
->V
, drbg_ctx
->V
);
123 if (data_nbytes
== 0) {
128 cchmac_di_clear(info
, hmac_ctx
);
132 entropy_isvalid(size_t entropy_nbytes
, const struct ccdigest_info
*info
)
134 return (entropy_nbytes
<= CCDRBG_MAX_ENTROPY_SIZE
) && (entropy_nbytes
>= MIN_REQ_ENTROPY(info
));
137 // See NIST SP 800-90A, Rev. 1, 9.1 and 10.1.2.3
139 init(const struct ccdrbg_info
*info
,
140 struct ccdrbg_state
*ctx
,
141 size_t entropy_nbytes
,
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
;
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
);
158 status
= CCDRBG_STATUS_OK
;
160 cc_memset(drbg_ctx
->key
, 0, outlen
);
161 cc_memset(drbg_ctx
->V
, 1, outlen
);
163 update(ctx
, 3, entropy_nbytes
, entropy
, nonce_nbytes
, nonce
, ps_nbytes
, ps
);
165 drbg_ctx
->reseed_counter
= 1;
172 add_isvalid(size_t add_nbytes
)
174 return add_nbytes
<= CCDRBG_MAX_ADDITIONALINPUT_SIZE
;
177 // See NIST SP 800-90A, Rev. 1, 9.2 and 10.1.2.4
179 reseed(struct ccdrbg_state
*ctx
, size_t entropy_nbytes
, const void *entropy
, size_t add_nbytes
, const void *add
)
181 struct ccdrbg_nisthmac_state
*drbg_ctx
= (struct ccdrbg_nisthmac_state
*)ctx
;
182 const struct ccdigest_info
*digest_info
= drbg_ctx
->custom
->di
;
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
);
188 status
= CCDRBG_STATUS_OK
;
190 update(ctx
, 2, entropy_nbytes
, entropy
, add_nbytes
, add
);
192 drbg_ctx
->reseed_counter
= 1;
198 // See NIST SP 800-90A, Rev. 1, 9.3 and 10.1.2.5
200 generate(struct ccdrbg_state
*ctx
, size_t out_nbytes
, void *out
, size_t add_nbytes
, const void *add
)
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
;
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
);
210 status
= CCDRBG_STATUS_NEED_RESEED
;
211 cc_require(drbg_ctx
->reseed_counter
<= CCDRBG_RESEED_INTERVAL
|| !drbg_ctx
->custom
->strictFIPS
, out
);
213 status
= CCDRBG_STATUS_OK
;
215 if (add_nbytes
> 0) {
216 update(ctx
, 1, add_nbytes
, add
);
219 uint8_t *out_bytes
= out
;
220 uint8_t Vprev
[NISTHMAC_MAX_OUTPUT_SIZE
];
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
);
226 // See FIPS 140-2, 4.9.2 Conditional Tests
227 if (cc_cmp_safe(outlen
, Vprev
, drbg_ctx
->V
) == 0) {
229 status
= CCDRBG_STATUS_ABORT
;
234 size_t n
= CC_MIN(out_nbytes
, outlen
);
235 cc_memcpy(out_bytes
, drbg_ctx
->V
, n
);
241 update(ctx
, 1, add_nbytes
, add
);
243 drbg_ctx
->reseed_counter
+= 1;
246 cc_clear(outlen
, Vprev
);
251 ccdrbg_factory_nisthmac(struct ccdrbg_info
*info
, const struct ccdrbg_nisthmac_custom
*custom
)
253 info
->size
= sizeof(struct ccdrbg_nisthmac_state
) + sizeof(struct ccdrbg_nisthmac_custom
);
255 info
->generate
= generate
;
256 info
->reseed
= reseed
;
258 info
->custom
= custom
;