|
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
|
2 /* lib/crypto/ucrypto/enc_provider/aes.c */ |
|
3 /* |
|
4 * Copyright (C) 2003, 2007, 2008, 2009 by the Massachusetts Institute of Technology. |
|
5 * All rights reserved. |
|
6 * |
|
7 * Export of this software from the United States of America may |
|
8 * require a specific license from the United States Government. |
|
9 * It is the responsibility of any person or organization contemplating |
|
10 * export to 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 M.I.T. not be used in advertising or publicity pertaining |
|
18 * to distribution of the software without specific, written prior |
|
19 * permission. Furthermore if you modify this software you must label |
|
20 * your software as modified software and not distribute it in such a |
|
21 * fashion that it might be confused with the original M.I.T. software. |
|
22 * M.I.T. makes no representations about the suitability of |
|
23 * this software for any purpose. It is provided "as is" without express |
|
24 * or implied warranty. |
|
25 */ |
|
26 /* |
|
27 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. |
|
28 */ |
|
29 |
|
30 #include "crypto_int.h" |
|
31 #include <libucrypto.h> |
|
32 |
|
33 #define BLOCK_SIZE 16 |
|
34 |
|
35 #define ENCRYPT_OP 1 |
|
36 #define DECRYPT_OP 2 |
|
37 |
|
38 /* |
|
39 * xorblock is used in the camellia cbc mac fuction, copied from the openssl |
|
40 * camellia.c. |
|
41 */ |
|
42 static void |
|
43 xorblock(unsigned char *out, const unsigned char *in) |
|
44 { |
|
45 int z; |
|
46 for (z = 0; z < BLOCK_SIZE / 4; z++) { |
|
47 unsigned char *outptr = &out[z * 4]; |
|
48 unsigned char *inptr = (unsigned char *)&in[z * 4]; |
|
49 /* |
|
50 * Use unaligned accesses. On x86, this will probably still be faster |
|
51 * than multiple byte accesses for unaligned data, and for aligned data |
|
52 * should be far better. (One test indicated about 2.4% faster |
|
53 * encryption for 1024-byte messages.) |
|
54 * |
|
55 * If some other CPU has really slow unaligned-word or byte accesses, |
|
56 * perhaps this function (or the load/store helpers?) should test for |
|
57 * alignment first. |
|
58 * |
|
59 * If byte accesses are faster than unaligned words, we may need to |
|
60 * conditionalize on CPU type, as that may be hard to determine |
|
61 * automatically. |
|
62 */ |
|
63 store_32_n(load_32_n(outptr) ^ load_32_n(inptr), outptr); |
|
64 } |
|
65 } |
|
66 |
|
67 /* |
|
68 * The cbc_docrypt function is here to handle the case where there is only 1 |
|
69 * block of plain/cipher text to process. |
|
70 */ |
|
71 static krb5_error_code |
|
72 cbc_docrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, |
|
73 size_t num_data, int op_type) |
|
74 { |
|
75 int ret = 0; |
|
76 unsigned char iblock[BLOCK_SIZE], oblock[BLOCK_SIZE]; |
|
77 size_t olen = sizeof (oblock); |
|
78 unsigned char tmp_iv[BLOCK_SIZE]; |
|
79 struct iov_cursor cursor; |
|
80 |
|
81 if (ivec && ivec->data){ |
|
82 if (ivec->length != sizeof (tmp_iv)) |
|
83 return KRB5_CRYPTO_INTERNAL; |
|
84 memcpy(tmp_iv, ivec->data, ivec->length); |
|
85 } else { |
|
86 memset(tmp_iv, 0, sizeof (tmp_iv)); |
|
87 } |
|
88 |
|
89 /* Init iovec cursor to gather data for encypting (FALSE) */ |
|
90 k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE); |
|
91 k5_iov_cursor_get(&cursor, iblock); |
|
92 |
|
93 if (op_type == ENCRYPT_OP) { |
|
94 if (ucrypto_encrypt(CRYPTO_CAMELLIA_CBC, |
|
95 key->keyblock.contents, |
|
96 key->keyblock.length, |
|
97 tmp_iv, sizeof (tmp_iv), |
|
98 iblock, sizeof (iblock), |
|
99 oblock, &olen) != CRYPTO_SUCCESS) { |
|
100 ret = KRB5_CRYPTO_INTERNAL; |
|
101 } |
|
102 } else { |
|
103 if (ucrypto_decrypt(CRYPTO_CAMELLIA_CBC, |
|
104 key->keyblock.contents, |
|
105 key->keyblock.length, |
|
106 tmp_iv, sizeof (tmp_iv), |
|
107 iblock, sizeof (iblock), |
|
108 oblock, &olen) != CRYPTO_SUCCESS) { |
|
109 ret = KRB5_CRYPTO_INTERNAL; |
|
110 } |
|
111 } |
|
112 |
|
113 if (!ret) { |
|
114 assert(olen == BLOCK_SIZE); |
|
115 k5_iov_cursor_put(&cursor, oblock); |
|
116 |
|
117 if (ivec && ivec->data) { |
|
118 if (op_type == ENCRYPT_OP) |
|
119 memcpy(ivec->data, oblock, BLOCK_SIZE); |
|
120 else |
|
121 memcpy(ivec->data, iblock, BLOCK_SIZE); |
|
122 } |
|
123 } |
|
124 |
|
125 zap(iblock, sizeof (iblock)); |
|
126 zap(oblock, sizeof (oblock)); |
|
127 |
|
128 return ret; |
|
129 } |
|
130 |
|
131 static krb5_error_code |
|
132 cts_docrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, |
|
133 size_t num_data, size_t dlen, size_t dblks, int op_type) |
|
134 { |
|
135 int ret = 0; |
|
136 size_t olen = dlen; |
|
137 unsigned char *obuf, *dbuf; |
|
138 unsigned char iv_cts[BLOCK_SIZE]; |
|
139 struct iov_cursor cursor; |
|
140 |
|
141 if (ivec && ivec->data){ |
|
142 if (ivec->length != sizeof (iv_cts)) |
|
143 return KRB5_CRYPTO_INTERNAL; |
|
144 memcpy(iv_cts, ivec->data, ivec->length); |
|
145 } else { |
|
146 memset(iv_cts, 0, sizeof (iv_cts)); |
|
147 } |
|
148 |
|
149 obuf = malloc(olen); |
|
150 if (!obuf) |
|
151 return ENOMEM; |
|
152 |
|
153 dbuf = malloc(dlen); |
|
154 if (!dbuf){ |
|
155 free(obuf); |
|
156 return ENOMEM; |
|
157 } |
|
158 |
|
159 /* Init iov cursor to gather data for encypting/decrypting (FALSE) */ |
|
160 k5_iov_cursor_init(&cursor, data, num_data, dlen, FALSE); |
|
161 /* Get all the data to be encrypted/decrypted into dbuf */ |
|
162 k5_iov_cursor_get(&cursor, dbuf); |
|
163 |
|
164 if (op_type == ENCRYPT_OP) { |
|
165 if (ucrypto_encrypt(CRYPTO_CAMELLIA_CTS, |
|
166 key->keyblock.contents, |
|
167 key->keyblock.length, |
|
168 iv_cts, sizeof (iv_cts), |
|
169 dbuf, dlen, obuf, &olen) != CRYPTO_SUCCESS) { |
|
170 ret = KRB5_CRYPTO_INTERNAL; |
|
171 } |
|
172 } else { |
|
173 if (ucrypto_decrypt(CRYPTO_CAMELLIA_CTS, |
|
174 key->keyblock.contents, |
|
175 key->keyblock.length, |
|
176 iv_cts, sizeof (iv_cts), |
|
177 dbuf, dlen, obuf, &olen) != CRYPTO_SUCCESS) { |
|
178 ret = KRB5_CRYPTO_INTERNAL; |
|
179 } |
|
180 } |
|
181 |
|
182 if (!ret) { |
|
183 assert(olen == dlen); |
|
184 k5_iov_cursor_put(&cursor, obuf); |
|
185 /* |
|
186 * Updating the ivec arg, if present because of an old/obscure concept |
|
187 * of cipher state that is being used by only BSD rlogin. See RFCs |
|
188 * 1391 and 1392 in regards to the vague description of cipher state. |
|
189 * For encrypt/decrypt use the second to the last block of ciphertext |
|
190 * if > 1 block. |
|
191 */ |
|
192 if (ivec && ivec->data) { |
|
193 unsigned char *bufptr = (op_type == ENCRYPT_OP) ? obuf : dbuf; |
|
194 /* |
|
195 * For encrypt obuf is ciphertext, for decrypt its dbuf which was |
|
196 * input. |
|
197 */ |
|
198 memcpy(ivec->data, bufptr + ((dblks - 2) * BLOCK_SIZE), |
|
199 BLOCK_SIZE); |
|
200 } |
|
201 } |
|
202 |
|
203 zapfree(obuf, olen); |
|
204 zapfree(dbuf, dlen); |
|
205 |
|
206 return ret; |
|
207 } |
|
208 |
|
209 krb5_error_code |
|
210 krb5int_camellia_encrypt(krb5_key key, const krb5_data *ivec, |
|
211 krb5_crypto_iov *data, size_t num_data) |
|
212 { |
|
213 size_t input_length, nblocks; |
|
214 |
|
215 input_length = iov_total_length(data, num_data, FALSE); |
|
216 nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE; |
|
217 if (nblocks == 1) { |
|
218 if (input_length != BLOCK_SIZE) |
|
219 return KRB5_BAD_MSIZE; |
|
220 /* |
|
221 * Note, there is bug here (see MIT bug ticket 8551 Crypto providers not |
|
222 * updating cipher state when 1 block plaintext is encrypted) hence the |
|
223 * NULL ivec arg. For now we leave the bug in since it has existed in |
|
224 * MIT code a long time and the tests need the buggy behavior to pass at |
|
225 * this point. |
|
226 */ |
|
227 return cbc_docrypt(key, NULL, data, num_data, ENCRYPT_OP); |
|
228 } else { /* nblocks > 1 */ |
|
229 return cts_docrypt(key, ivec, data, num_data, input_length, nblocks, |
|
230 ENCRYPT_OP); |
|
231 } |
|
232 } |
|
233 |
|
234 krb5_error_code |
|
235 krb5int_camellia_decrypt(krb5_key key, const krb5_data *ivec, |
|
236 krb5_crypto_iov *data, size_t num_data) |
|
237 { |
|
238 size_t input_length, nblocks; |
|
239 |
|
240 input_length = iov_total_length(data, num_data, FALSE); |
|
241 nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE; |
|
242 if (nblocks == 1) { |
|
243 if (input_length != BLOCK_SIZE) |
|
244 return KRB5_BAD_MSIZE; |
|
245 return cbc_docrypt(key, NULL, data, num_data, DECRYPT_OP); |
|
246 } else { /* nblocks > 1 */ |
|
247 return cts_docrypt(key, ivec, data, num_data, input_length, nblocks, |
|
248 DECRYPT_OP); |
|
249 } |
|
250 } |
|
251 |
|
252 /* |
|
253 * This function is based on the openssl enc_provider/camellia.c version. |
|
254 */ |
|
255 krb5_error_code |
|
256 krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data, |
|
257 size_t num_data, const krb5_data *ivec, |
|
258 krb5_data *output) |
|
259 { |
|
260 unsigned char blockY[BLOCK_SIZE], blockB[BLOCK_SIZE]; |
|
261 size_t olen = BLOCK_SIZE; |
|
262 struct iov_cursor cursor; |
|
263 |
|
264 if (output->length < BLOCK_SIZE) |
|
265 return KRB5_BAD_MSIZE; |
|
266 |
|
267 if (ivec != NULL && ivec->data != NULL) |
|
268 memcpy(blockY, ivec->data, BLOCK_SIZE); |
|
269 else |
|
270 memset(blockY, 0, BLOCK_SIZE); |
|
271 |
|
272 k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE); |
|
273 while (k5_iov_cursor_get(&cursor, blockB)) { |
|
274 xorblock(blockB, blockY); |
|
275 olen = sizeof(blockY); |
|
276 if (ucrypto_encrypt(CRYPTO_CAMELLIA_ECB, |
|
277 key->keyblock.contents, |
|
278 key->keyblock.length, |
|
279 NULL, 0, |
|
280 blockB, sizeof(blockB), |
|
281 blockY, &olen) != CRYPTO_SUCCESS) { |
|
282 return KRB5_CRYPTO_INTERNAL; |
|
283 } |
|
284 } |
|
285 |
|
286 assert(olen == BLOCK_SIZE); |
|
287 output->length = BLOCK_SIZE; |
|
288 memcpy(output->data, blockY, BLOCK_SIZE); |
|
289 |
|
290 return 0; |
|
291 } |
|
292 |
|
293 static krb5_error_code |
|
294 krb5int_camellia_init_state (const krb5_keyblock *key, krb5_keyusage usage, |
|
295 krb5_data *state) |
|
296 { |
|
297 state->data = calloc(1, BLOCK_SIZE); |
|
298 if (state->data == NULL) |
|
299 return ENOMEM; |
|
300 state->length = BLOCK_SIZE; |
|
301 return 0; |
|
302 } |
|
303 |
|
304 const struct krb5_enc_provider krb5int_enc_camellia128 = { |
|
305 BLOCK_SIZE, |
|
306 16, 16, |
|
307 krb5int_camellia_encrypt, |
|
308 krb5int_camellia_decrypt, |
|
309 krb5int_camellia_cbc_mac, |
|
310 krb5int_camellia_init_state, |
|
311 krb5int_default_free_state |
|
312 }; |
|
313 |
|
314 const struct krb5_enc_provider krb5int_enc_camellia256 = { |
|
315 BLOCK_SIZE, |
|
316 32, 32, |
|
317 krb5int_camellia_encrypt, |
|
318 krb5int_camellia_decrypt, |
|
319 krb5int_camellia_cbc_mac, |
|
320 krb5int_camellia_init_state, |
|
321 krb5int_default_free_state |
|
322 }; |