1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/crypto/openssl/enc_provider/camellia.c */
3 /*
4 * Copyright (C) 2003, 2007, 2008, 2009, 2010 by the Massachusetts Institute of
5 * Technology. 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 #include "crypto_int.h"
28
29 #ifdef K5_OPENSSL_CAMELLIA
30
31 #include <openssl/evp.h>
32 #include <openssl/camellia.h>
33 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
34 #include <openssl/core_names.h>
35 #else
36 #include <openssl/modes.h>
37 #endif
38
39 static krb5_error_code
40 cbc_enc(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
41 size_t num_data);
42 static krb5_error_code
43 cbc_decr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
44 size_t num_data);
45 static krb5_error_code
46 cts_encr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
47 size_t num_data, size_t dlen);
48 static krb5_error_code
49 cts_decr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
50 size_t num_data, size_t dlen);
51
52 #define BLOCK_SIZE 16
53 #define NUM_BITS 8
54 #define IV_CTS_BUF_SIZE 16 /* 16 - hardcoded in CRYPTO_cts128_en/decrypt */
55
56 static const EVP_CIPHER *
map_mode(unsigned int len)57 map_mode(unsigned int len)
58 {
59 if (len==16)
60 return EVP_camellia_128_cbc();
61 if (len==32)
62 return EVP_camellia_256_cbc();
63 else
64 return NULL;
65 }
66
67 /* Encrypt one block using CBC. */
68 static krb5_error_code
cbc_enc(krb5_key key,const krb5_data * ivec,krb5_crypto_iov * data,size_t num_data)69 cbc_enc(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
70 size_t num_data)
71 {
72 int ret, olen = BLOCK_SIZE;
73 unsigned char iblock[BLOCK_SIZE], oblock[BLOCK_SIZE];
74 EVP_CIPHER_CTX *ctx;
75 struct iov_cursor cursor;
76
77 ctx = EVP_CIPHER_CTX_new();
78 if (ctx == NULL)
79 return ENOMEM;
80
81 ret = EVP_EncryptInit_ex(ctx, map_mode(key->keyblock.length),
82 NULL, key->keyblock.contents, (ivec) ? (unsigned char*)ivec->data : NULL);
83 if (ret == 0) {
84 EVP_CIPHER_CTX_free(ctx);
85 return KRB5_CRYPTO_INTERNAL;
86 }
87
88 k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE);
89 k5_iov_cursor_get(&cursor, iblock);
90 EVP_CIPHER_CTX_set_padding(ctx,0);
91 ret = EVP_EncryptUpdate(ctx, oblock, &olen, iblock, BLOCK_SIZE);
92 if (ret == 1)
93 k5_iov_cursor_put(&cursor, oblock);
94 EVP_CIPHER_CTX_free(ctx);
95
96 zap(iblock, BLOCK_SIZE);
97 zap(oblock, BLOCK_SIZE);
98 return (ret == 1) ? 0 : KRB5_CRYPTO_INTERNAL;
99 }
100
101 /* Decrypt one block using CBC. */
102 static krb5_error_code
cbc_decr(krb5_key key,const krb5_data * ivec,krb5_crypto_iov * data,size_t num_data)103 cbc_decr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
104 size_t num_data)
105 {
106 int ret = 0, olen = BLOCK_SIZE;
107 unsigned char iblock[BLOCK_SIZE], oblock[BLOCK_SIZE];
108 EVP_CIPHER_CTX *ctx;
109 struct iov_cursor cursor;
110
111 ctx = EVP_CIPHER_CTX_new();
112 if (ctx == NULL)
113 return ENOMEM;
114
115 ret = EVP_DecryptInit_ex(ctx, map_mode(key->keyblock.length),
116 NULL, key->keyblock.contents, (ivec) ? (unsigned char*)ivec->data : NULL);
117 if (ret == 0) {
118 EVP_CIPHER_CTX_free(ctx);
119 return KRB5_CRYPTO_INTERNAL;
120 }
121
122 k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE);
123 k5_iov_cursor_get(&cursor, iblock);
124 EVP_CIPHER_CTX_set_padding(ctx,0);
125 ret = EVP_DecryptUpdate(ctx, oblock, &olen, iblock, BLOCK_SIZE);
126 if (ret == 1)
127 k5_iov_cursor_put(&cursor, oblock);
128 EVP_CIPHER_CTX_free(ctx);
129
130 zap(iblock, BLOCK_SIZE);
131 zap(oblock, BLOCK_SIZE);
132 return (ret == 1) ? 0 : KRB5_CRYPTO_INTERNAL;
133 }
134
135 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
136
137 static krb5_error_code
do_cts(krb5_key key,const krb5_data * ivec,krb5_crypto_iov * data,size_t num_data,size_t dlen,int encrypt)138 do_cts(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
139 size_t num_data, size_t dlen, int encrypt)
140 {
141 krb5_error_code ret;
142 int outlen, len;
143 unsigned char *oblock = NULL, *dbuf = NULL;
144 unsigned char iv_cts[IV_CTS_BUF_SIZE];
145 struct iov_cursor cursor;
146 OSSL_PARAM params[2], *p = params;
147 EVP_CIPHER_CTX *ctx = NULL;
148 EVP_CIPHER *cipher = NULL;
149
150 memset(iv_cts, 0, sizeof(iv_cts));
151 if (ivec != NULL && ivec->data != NULL){
152 if (ivec->length != sizeof(iv_cts))
153 return KRB5_CRYPTO_INTERNAL;
154 memcpy(iv_cts, ivec->data, ivec->length);
155 }
156
157 if (key->keyblock.length == 16)
158 cipher = EVP_CIPHER_fetch(NULL, "CAMELLIA-128-CBC-CTS", NULL);
159 else if (key->keyblock.length == 32)
160 cipher = EVP_CIPHER_fetch(NULL, "CAMELLIA-256-CBC-CTS", NULL);
161 if (cipher == NULL)
162 return KRB5_CRYPTO_INTERNAL;
163
164 oblock = OPENSSL_malloc(dlen);
165 dbuf = OPENSSL_malloc(dlen);
166 ctx = EVP_CIPHER_CTX_new();
167 if (oblock == NULL || dbuf == NULL || ctx == NULL) {
168 ret = ENOMEM;
169 goto cleanup;
170 }
171
172 k5_iov_cursor_init(&cursor, data, num_data, dlen, FALSE);
173 k5_iov_cursor_get(&cursor, dbuf);
174
175 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_CIPHER_PARAM_CTS_MODE,
176 "CS3", 0);
177 *p = OSSL_PARAM_construct_end();
178 if (!EVP_CipherInit_ex2(ctx, cipher, key->keyblock.contents, iv_cts,
179 encrypt, params) ||
180 !EVP_CipherUpdate(ctx, oblock, &outlen, dbuf, dlen) ||
181 !EVP_CipherFinal_ex(ctx, oblock + outlen, &len)) {
182 ret = KRB5_CRYPTO_INTERNAL;
183 goto cleanup;
184 }
185
186 if (ivec != NULL && ivec->data != NULL &&
187 !EVP_CIPHER_CTX_get_updated_iv(ctx, ivec->data, sizeof(iv_cts))) {
188 ret = KRB5_CRYPTO_INTERNAL;
189 goto cleanup;
190 }
191
192 k5_iov_cursor_put(&cursor, oblock);
193
194 ret = 0;
195 cleanup:
196 OPENSSL_clear_free(oblock, dlen);
197 OPENSSL_clear_free(dbuf, dlen);
198 EVP_CIPHER_CTX_free(ctx);
199 EVP_CIPHER_free(cipher);
200 return ret;
201 }
202
203 static inline krb5_error_code
cts_encr(krb5_key key,const krb5_data * ivec,krb5_crypto_iov * data,size_t num_data,size_t dlen)204 cts_encr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
205 size_t num_data, size_t dlen)
206 {
207 return do_cts(key, ivec, data, num_data, dlen, 1);
208 }
209
210 static inline krb5_error_code
cts_decr(krb5_key key,const krb5_data * ivec,krb5_crypto_iov * data,size_t num_data,size_t dlen)211 cts_decr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
212 size_t num_data, size_t dlen)
213 {
214 return do_cts(key, ivec, data, num_data, dlen, 0);
215 }
216
217 #else /* OPENSSL_VERSION_NUMBER < 0x30000000L */
218
219 static krb5_error_code
cts_encr(krb5_key key,const krb5_data * ivec,krb5_crypto_iov * data,size_t num_data,size_t dlen)220 cts_encr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
221 size_t num_data, size_t dlen)
222 {
223 int ret = 0;
224 size_t size = 0;
225 unsigned char *oblock = NULL, *dbuf = NULL;
226 unsigned char iv_cts[IV_CTS_BUF_SIZE];
227 struct iov_cursor cursor;
228 CAMELLIA_KEY enck;
229
230 memset(iv_cts,0,sizeof(iv_cts));
231 if (ivec && ivec->data){
232 if (ivec->length != sizeof(iv_cts))
233 return KRB5_CRYPTO_INTERNAL;
234 memcpy(iv_cts, ivec->data,ivec->length);
235 }
236
237 oblock = OPENSSL_malloc(dlen);
238 if (!oblock){
239 return ENOMEM;
240 }
241 dbuf = OPENSSL_malloc(dlen);
242 if (!dbuf){
243 OPENSSL_free(oblock);
244 return ENOMEM;
245 }
246
247 k5_iov_cursor_init(&cursor, data, num_data, dlen, FALSE);
248 k5_iov_cursor_get(&cursor, dbuf);
249
250 Camellia_set_key(key->keyblock.contents, NUM_BITS * key->keyblock.length,
251 &enck);
252
253 size = CRYPTO_cts128_encrypt((unsigned char *)dbuf, oblock, dlen, &enck,
254 iv_cts, (cbc128_f)Camellia_cbc_encrypt);
255 if (size <= 0)
256 ret = KRB5_CRYPTO_INTERNAL;
257 else
258 k5_iov_cursor_put(&cursor, oblock);
259
260 if (!ret && ivec && ivec->data)
261 memcpy(ivec->data, iv_cts, sizeof(iv_cts));
262
263 zap(oblock, dlen);
264 zap(dbuf, dlen);
265 OPENSSL_free(oblock);
266 OPENSSL_free(dbuf);
267
268 return ret;
269 }
270
271 static krb5_error_code
cts_decr(krb5_key key,const krb5_data * ivec,krb5_crypto_iov * data,size_t num_data,size_t dlen)272 cts_decr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
273 size_t num_data, size_t dlen)
274 {
275 int ret = 0;
276 size_t size = 0;
277 unsigned char *oblock = NULL;
278 unsigned char *dbuf = NULL;
279 unsigned char iv_cts[IV_CTS_BUF_SIZE];
280 struct iov_cursor cursor;
281 CAMELLIA_KEY deck;
282
283 memset(iv_cts,0,sizeof(iv_cts));
284 if (ivec && ivec->data){
285 if (ivec->length != sizeof(iv_cts))
286 return KRB5_CRYPTO_INTERNAL;
287 memcpy(iv_cts, ivec->data,ivec->length);
288 }
289
290 oblock = OPENSSL_malloc(dlen);
291 if (!oblock)
292 return ENOMEM;
293 dbuf = OPENSSL_malloc(dlen);
294 if (!dbuf){
295 OPENSSL_free(oblock);
296 return ENOMEM;
297 }
298
299 Camellia_set_key(key->keyblock.contents, NUM_BITS * key->keyblock.length,
300 &deck);
301
302 k5_iov_cursor_init(&cursor, data, num_data, dlen, FALSE);
303 k5_iov_cursor_get(&cursor, dbuf);
304
305 size = CRYPTO_cts128_decrypt((unsigned char *)dbuf, oblock,
306 dlen, &deck,
307 iv_cts, (cbc128_f)Camellia_cbc_encrypt);
308 if (size <= 0)
309 ret = KRB5_CRYPTO_INTERNAL;
310 else
311 k5_iov_cursor_put(&cursor, oblock);
312
313 if (!ret && ivec && ivec->data)
314 memcpy(ivec->data, iv_cts, sizeof(iv_cts));
315
316 zap(oblock, dlen);
317 zap(dbuf, dlen);
318 OPENSSL_free(oblock);
319 OPENSSL_free(dbuf);
320
321 return ret;
322 }
323
324 #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
325
326 krb5_error_code
krb5int_camellia_encrypt(krb5_key key,const krb5_data * ivec,krb5_crypto_iov * data,size_t num_data)327 krb5int_camellia_encrypt(krb5_key key, const krb5_data *ivec,
328 krb5_crypto_iov *data, size_t num_data)
329 {
330 int ret = 0;
331 size_t input_length, nblocks;
332
333 input_length = iov_total_length(data, num_data, FALSE);
334 nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE;
335 if (nblocks == 1) {
336 if (input_length != BLOCK_SIZE)
337 return KRB5_BAD_MSIZE;
338 ret = cbc_enc(key, ivec, data, num_data);
339 } else if (nblocks > 1) {
340 ret = cts_encr(key, ivec, data, num_data, input_length);
341 }
342
343 return ret;
344 }
345
346 static krb5_error_code
krb5int_camellia_decrypt(krb5_key key,const krb5_data * ivec,krb5_crypto_iov * data,size_t num_data)347 krb5int_camellia_decrypt(krb5_key key, const krb5_data *ivec,
348 krb5_crypto_iov *data, size_t num_data)
349 {
350 int ret = 0;
351 size_t input_length, nblocks;
352
353 input_length = iov_total_length(data, num_data, FALSE);
354 nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE;
355 if (nblocks == 1) {
356 if (input_length != BLOCK_SIZE)
357 return KRB5_BAD_MSIZE;
358 ret = cbc_decr(key, ivec, data, num_data);
359 } else if (nblocks > 1) {
360 ret = cts_decr(key, ivec, data, num_data, input_length);
361 }
362
363 return ret;
364 }
365
366 #ifdef K5_BUILTIN_CMAC
367
368 static void
xorblock(uint8_t * out,const uint8_t * in)369 xorblock(uint8_t *out, const uint8_t *in)
370 {
371 int z;
372
373 for (z = 0; z < CAMELLIA_BLOCK_SIZE / 4; z++) {
374 uint8_t *outptr = &out[z * 4];
375 const uint8_t *inptr = &in[z * 4];
376
377 store_32_n(load_32_n(outptr) ^ load_32_n(inptr), outptr);
378 }
379 }
380
381 static krb5_error_code
krb5int_camellia_cbc_mac(krb5_key key,const krb5_crypto_iov * data,size_t num_data,const krb5_data * iv,krb5_data * output)382 krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data,
383 size_t num_data, const krb5_data *iv,
384 krb5_data *output)
385 {
386 CAMELLIA_KEY enck;
387 unsigned char blockY[CAMELLIA_BLOCK_SIZE], blockB[CAMELLIA_BLOCK_SIZE];
388 struct iov_cursor cursor;
389
390 if (output->length < CAMELLIA_BLOCK_SIZE)
391 return KRB5_BAD_MSIZE;
392
393 Camellia_set_key(key->keyblock.contents,
394 NUM_BITS * key->keyblock.length, &enck);
395
396 if (iv != NULL)
397 memcpy(blockY, iv->data, CAMELLIA_BLOCK_SIZE);
398 else
399 memset(blockY, 0, CAMELLIA_BLOCK_SIZE);
400
401 k5_iov_cursor_init(&cursor, data, num_data, CAMELLIA_BLOCK_SIZE, FALSE);
402 while (k5_iov_cursor_get(&cursor, blockB)) {
403 xorblock(blockB, blockY);
404 Camellia_ecb_encrypt(blockB, blockY, &enck, 1);
405 }
406
407 output->length = CAMELLIA_BLOCK_SIZE;
408 memcpy(output->data, blockY, CAMELLIA_BLOCK_SIZE);
409
410 return 0;
411 }
412
413 #else
414 #define krb5int_camellia_cbc_mac NULL
415 #endif
416
417 static krb5_error_code
krb5int_camellia_init_state(const krb5_keyblock * key,krb5_keyusage usage,krb5_data * state)418 krb5int_camellia_init_state (const krb5_keyblock *key, krb5_keyusage usage,
419 krb5_data *state)
420 {
421 state->length = 16;
422 state->data = (void *) malloc(16);
423 if (state->data == NULL)
424 return ENOMEM;
425 memset(state->data, 0, state->length);
426 return 0;
427 }
428 const struct krb5_enc_provider krb5int_enc_camellia128 = {
429 16,
430 16, 16,
431 krb5int_camellia_encrypt,
432 krb5int_camellia_decrypt,
433 krb5int_camellia_cbc_mac, /* NULL if K5_BUILTIN_CMAC not defined */
434 krb5int_camellia_init_state,
435 krb5int_default_free_state
436 };
437
438 const struct krb5_enc_provider krb5int_enc_camellia256 = {
439 16,
440 32, 32,
441 krb5int_camellia_encrypt,
442 krb5int_camellia_decrypt,
443 krb5int_camellia_cbc_mac, /* NULL if K5_BUILTIN_CMAC not defined */
444 krb5int_camellia_init_state,
445 krb5int_default_free_state
446 };
447
448 #endif /* K5_OPENSSL_CAMELLIA */
449