xref: /freebsd/crypto/krb5/src/lib/crypto/openssl/enc_provider/camellia.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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