/src/krb5/src/lib/crypto/builtin/kdf.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
2 | | /* |
3 | | * Copyright (C) 1998 by the FundsXpress, INC. |
4 | | * |
5 | | * All rights reserved. |
6 | | * |
7 | | * Export of this software from the United States of America may require |
8 | | * a specific license from the United States Government. It is the |
9 | | * responsibility of any person or organization contemplating export to |
10 | | * obtain such a license before exporting. |
11 | | * |
12 | | * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and |
13 | | * distribute this software and its documentation for any purpose and |
14 | | * without fee is hereby granted, provided that the above copyright |
15 | | * notice appear in all copies and that both that copyright notice and |
16 | | * this permission notice appear in supporting documentation, and that |
17 | | * the name of FundsXpress. not be used in advertising or publicity pertaining |
18 | | * to distribution of the software without specific, written prior |
19 | | * permission. FundsXpress makes no representations about the suitability of |
20 | | * this software for any purpose. It is provided "as is" without express |
21 | | * or implied warranty. |
22 | | * |
23 | | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
24 | | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
25 | | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
26 | | */ |
27 | | |
28 | | #include "crypto_int.h" |
29 | | |
30 | | #ifdef K5_BUILTIN_KDF |
31 | | |
32 | | krb5_error_code |
33 | | k5_sp800_108_counter_hmac(const struct krb5_hash_provider *hash, |
34 | | krb5_key key, const krb5_data *label, |
35 | | const krb5_data *context, krb5_data *rnd_out) |
36 | 2.71k | { |
37 | 2.71k | krb5_crypto_iov iov[5]; |
38 | 2.71k | krb5_error_code ret; |
39 | 2.71k | krb5_data prf; |
40 | 2.71k | unsigned char ibuf[4], lbuf[4]; |
41 | | |
42 | 2.71k | if (hash == NULL || rnd_out->length > hash->hashsize) |
43 | 0 | return KRB5_CRYPTO_INTERNAL; |
44 | | |
45 | | /* Allocate encryption data buffer. */ |
46 | 2.71k | ret = alloc_data(&prf, hash->hashsize); |
47 | 2.71k | if (ret) |
48 | 0 | return ret; |
49 | | |
50 | | /* [i]2: four-byte big-endian binary string giving the block counter (1) */ |
51 | 2.71k | iov[0].flags = KRB5_CRYPTO_TYPE_DATA; |
52 | 2.71k | iov[0].data = make_data(ibuf, sizeof(ibuf)); |
53 | 2.71k | store_32_be(1, ibuf); |
54 | | /* Label */ |
55 | 2.71k | iov[1].flags = KRB5_CRYPTO_TYPE_DATA; |
56 | 2.71k | iov[1].data = *label; |
57 | | /* 0x00: separator byte */ |
58 | 2.71k | iov[2].flags = KRB5_CRYPTO_TYPE_DATA; |
59 | 2.71k | iov[2].data = make_data("", 1); |
60 | | /* Context */ |
61 | 2.71k | iov[3].flags = KRB5_CRYPTO_TYPE_DATA; |
62 | 2.71k | iov[3].data = *context; |
63 | | /* [L]2: four-byte big-endian binary string giving the output length */ |
64 | 2.71k | iov[4].flags = KRB5_CRYPTO_TYPE_DATA; |
65 | 2.71k | iov[4].data = make_data(lbuf, sizeof(lbuf)); |
66 | 2.71k | store_32_be(rnd_out->length * 8, lbuf); |
67 | | |
68 | 2.71k | ret = krb5int_hmac(hash, key, iov, 5, &prf); |
69 | 2.71k | if (!ret) |
70 | 2.71k | memcpy(rnd_out->data, prf.data, rnd_out->length); |
71 | 2.71k | zapfree(prf.data, prf.length); |
72 | 2.71k | return ret; |
73 | 2.71k | } |
74 | | |
75 | | krb5_error_code |
76 | | k5_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc, krb5_key key, |
77 | | const krb5_data *label, krb5_data *rnd_out) |
78 | 2.71k | { |
79 | 2.71k | size_t blocksize, keybytes, n; |
80 | 2.71k | krb5_crypto_iov iov[6]; |
81 | 2.71k | krb5_error_code ret; |
82 | 2.71k | krb5_data prf; |
83 | 2.71k | unsigned int i; |
84 | 2.71k | unsigned char ibuf[4], Lbuf[4]; |
85 | | |
86 | 2.71k | blocksize = enc->block_size; |
87 | 2.71k | keybytes = enc->keybytes; |
88 | | |
89 | 2.71k | if (key->keyblock.length != enc->keylength || rnd_out->length != keybytes) |
90 | 0 | return KRB5_CRYPTO_INTERNAL; |
91 | | |
92 | | /* Allocate encryption data buffer. */ |
93 | 2.71k | ret = alloc_data(&prf, blocksize); |
94 | 2.71k | if (ret) |
95 | 0 | return ret; |
96 | | |
97 | | /* K(i-1): the previous block of PRF output, initially all-zeros. */ |
98 | 2.71k | iov[0].flags = KRB5_CRYPTO_TYPE_DATA; |
99 | 2.71k | iov[0].data = prf; |
100 | | /* [i]2: four-byte big-endian binary string giving the block counter */ |
101 | 2.71k | iov[1].flags = KRB5_CRYPTO_TYPE_DATA; |
102 | 2.71k | iov[1].data = make_data(ibuf, sizeof(ibuf)); |
103 | | /* Label: the fixed derived-key input */ |
104 | 2.71k | iov[2].flags = KRB5_CRYPTO_TYPE_DATA; |
105 | 2.71k | iov[2].data = *label; |
106 | | /* 0x00: separator byte */ |
107 | 2.71k | iov[3].flags = KRB5_CRYPTO_TYPE_DATA; |
108 | 2.71k | iov[3].data = make_data("", 1); |
109 | | /* Context: (unused) */ |
110 | 2.71k | iov[4].flags = KRB5_CRYPTO_TYPE_DATA; |
111 | 2.71k | iov[4].data = empty_data(); |
112 | | /* [L]2: four-byte big-endian binary string giving the output length */ |
113 | 2.71k | iov[5].flags = KRB5_CRYPTO_TYPE_DATA; |
114 | 2.71k | iov[5].data = make_data(Lbuf, sizeof(Lbuf)); |
115 | 2.71k | store_32_be(rnd_out->length * 8, Lbuf); |
116 | | |
117 | 4.07k | for (i = 1, n = 0; n < keybytes; i++) { |
118 | | /* Update the block counter. */ |
119 | 4.07k | store_32_be(i, ibuf); |
120 | | |
121 | | /* Compute a CMAC checksum, storing the result into K(i-1). */ |
122 | 4.07k | ret = krb5int_cmac_checksum(enc, key, iov, 6, &prf); |
123 | 4.07k | if (ret) |
124 | 0 | goto cleanup; |
125 | | |
126 | | /* Copy the result into the appropriate part of the output buffer. */ |
127 | 4.07k | if (keybytes - n <= blocksize) { |
128 | 2.71k | memcpy(rnd_out->data + n, prf.data, keybytes - n); |
129 | 2.71k | break; |
130 | 2.71k | } |
131 | 1.35k | memcpy(rnd_out->data + n, prf.data, blocksize); |
132 | 1.35k | n += blocksize; |
133 | 1.35k | } |
134 | | |
135 | 2.71k | cleanup: |
136 | 2.71k | zapfree(prf.data, blocksize); |
137 | 2.71k | return ret; |
138 | 2.71k | } |
139 | | |
140 | | krb5_error_code |
141 | | k5_derive_random_rfc3961(const struct krb5_enc_provider *enc, krb5_key key, |
142 | | const krb5_data *constant, krb5_data *rnd_out) |
143 | 3.77k | { |
144 | 3.77k | size_t blocksize, keybytes, n; |
145 | 3.77k | krb5_error_code ret; |
146 | 3.77k | krb5_data block = empty_data(); |
147 | | |
148 | 3.77k | blocksize = enc->block_size; |
149 | 3.77k | keybytes = enc->keybytes; |
150 | | |
151 | 3.77k | if (blocksize == 1) |
152 | 0 | return KRB5_BAD_ENCTYPE; |
153 | 3.77k | if (key->keyblock.length != enc->keylength || rnd_out->length != keybytes) |
154 | 0 | return KRB5_CRYPTO_INTERNAL; |
155 | | |
156 | | /* Allocate encryption data buffer. */ |
157 | 3.77k | ret = alloc_data(&block, blocksize); |
158 | 3.77k | if (ret) |
159 | 0 | return ret; |
160 | | |
161 | | /* Initialize the input block. */ |
162 | 3.77k | if (constant->length == blocksize) { |
163 | 0 | memcpy(block.data, constant->data, blocksize); |
164 | 3.77k | } else { |
165 | 3.77k | krb5int_nfold(constant->length * 8, (uint8_t *)constant->data, |
166 | 3.77k | blocksize * 8, (uint8_t *)block.data); |
167 | 3.77k | } |
168 | | |
169 | | /* Loop encrypting the blocks until enough key bytes are generated. */ |
170 | 3.77k | n = 0; |
171 | 7.26k | while (n < keybytes) { |
172 | 7.26k | ret = encrypt_block(enc, key, &block); |
173 | 7.26k | if (ret) |
174 | 0 | goto cleanup; |
175 | | |
176 | 7.26k | if ((keybytes - n) <= blocksize) { |
177 | 3.77k | memcpy(rnd_out->data + n, block.data, (keybytes - n)); |
178 | 3.77k | break; |
179 | 3.77k | } |
180 | | |
181 | 3.48k | memcpy(rnd_out->data + n, block.data, blocksize); |
182 | 3.48k | n += blocksize; |
183 | 3.48k | } |
184 | | |
185 | 3.77k | cleanup: |
186 | 3.77k | zapfree(block.data, blocksize); |
187 | 3.77k | return ret; |
188 | 3.77k | } |
189 | | |
190 | | #endif /* K5_BUILTIN_KDF */ |