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