Imported Upstream version 5.3.21
[platform/upstream/libdb.git] / src / crypto / aes_method.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2001, 2012 Oracle and/or its affiliates.  All rights reserved.
5  *
6  * Some parts of this code originally written by Adam Stubblefield,
7  * -- astubble@rice.edu.
8  *
9  * $Id$
10  */
11
12 #include "db_config.h"
13
14 #include "db_int.h"
15 #include "dbinc/crypto.h"
16 #include "dbinc/hmac.h"
17
18 #ifdef HAVE_CRYPTO_IPP
19 #include <ippcp.h>
20 #endif
21
22 static void __aes_err __P((ENV *, int));
23 static int __aes_derivekeys __P((ENV *, DB_CIPHER *, u_int8_t *, size_t));
24
25 /*
26  * __aes_setup --
27  *      Setup AES functions.
28  *
29  * PUBLIC: int __aes_setup __P((ENV *, DB_CIPHER *));
30  */
31 int
32 __aes_setup(env, db_cipher)
33         ENV *env;
34         DB_CIPHER *db_cipher;
35 {
36         AES_CIPHER *aes_cipher;
37         int ret;
38 #ifdef  HAVE_CRYPTO_IPP
39         int ctx_size = 0;
40         IppStatus ipp_ret;
41 #endif
42
43         db_cipher->adj_size = __aes_adj_size;
44         db_cipher->close = __aes_close;
45         db_cipher->decrypt = __aes_decrypt;
46         db_cipher->encrypt = __aes_encrypt;
47         db_cipher->init = __aes_init;
48         if ((ret = __os_calloc(env, 1, sizeof(AES_CIPHER), &aes_cipher)) != 0)
49                 return (ret);
50 #ifdef  HAVE_CRYPTO_IPP
51         /*
52          * IPP AES encryption context size can only be obtained through this
53          * function call, cannot directly declare IppsRijndael128Spec within
54          * AES_CIPHER struct.
55          */
56         if ((ipp_ret = ippsRijndael128GetSize(&ctx_size)) != ippStsNoErr) {
57                 __aes_err(env, (int)ipp_ret);
58                 return (EAGAIN);
59         }
60         if ((ret = __os_malloc(env, ctx_size, &aes_cipher->ipp_ctx)) != 0) {
61                 __os_free(env, aes_cipher);
62                 return (ret);
63         }
64 #endif
65         db_cipher->data = aes_cipher;
66         return (0);
67 }
68
69 /*
70  * __aes_adj_size --
71  *      Given a size, return an addition amount needed to meet the
72  *      "chunk" needs of the algorithm.
73  *
74  * PUBLIC: u_int __aes_adj_size __P((size_t));
75  */
76 u_int
77 __aes_adj_size(len)
78         size_t len;
79 {
80         if (len % DB_AES_CHUNK == 0)
81                 return (0);
82         return (DB_AES_CHUNK - (u_int)(len % DB_AES_CHUNK));
83 }
84
85 /*
86  * __aes_close --
87  *      Destroy the AES encryption instantiation.
88  *
89  * PUBLIC: int __aes_close __P((ENV *, void *));
90  */
91 int
92 __aes_close(env, data)
93         ENV *env;
94         void *data;
95 {
96 #ifdef  HAVE_CRYPTO_IPP
97         AES_CIPHER *aes_cipher = (AES_CIPHER *)data;
98         __os_free(env, aes_cipher->ipp_ctx);
99 #endif
100         __os_free(env, data);
101         return (0);
102 }
103
104 /*
105  * __aes_decrypt --
106  *      Decrypt data with AES.
107  *
108  * PUBLIC: int __aes_decrypt __P((ENV *, void *, void *,
109  * PUBLIC:     u_int8_t *, size_t));
110  */
111 int
112 __aes_decrypt(env, aes_data, iv, cipher, cipher_len)
113         ENV *env;
114         void *aes_data;
115         void *iv;
116         u_int8_t *cipher;
117         size_t cipher_len;
118 {
119         AES_CIPHER *aes;
120 #ifdef  HAVE_CRYPTO_IPP
121         IppStatus ipp_ret;
122 #else
123         cipherInstance c;
124 #endif
125         int ret;
126
127         aes = (AES_CIPHER *)aes_data;
128         if (iv == NULL || cipher == NULL)
129                 return (EINVAL);
130         if ((cipher_len % DB_AES_CHUNK) != 0)
131                 return (EINVAL);
132
133 #ifdef  HAVE_CRYPTO_IPP
134         if ((ipp_ret = ippsRijndael128DecryptCBC((const Ipp8u *)cipher,
135             (Ipp8u *)cipher, cipher_len, (IppsRijndael128Spec *)aes->ipp_ctx,
136             (const Ipp8u *)iv, 0)) != ippStsNoErr) {
137                 __aes_err(env, (int)ipp_ret);
138                 return (EAGAIN);
139         }
140 #else
141         /*
142          * Initialize the cipher
143          */
144         if ((ret = __db_cipherInit(&c, MODE_CBC, iv)) < 0) {
145                 __aes_err(env, ret);
146                 return (EAGAIN);
147         }
148
149         /* Do the decryption */
150         if ((ret = __db_blockDecrypt(&c, &aes->decrypt_ki, cipher,
151             cipher_len * 8, cipher)) < 0) {
152                 __aes_err(env, ret);
153                 return (EAGAIN);
154         }
155 #endif
156         return (0);
157 }
158
159 /*
160  * __aes_encrypt --
161  *      Encrypt data with AES.
162  *
163  * PUBLIC: int __aes_encrypt __P((ENV *, void *, void *,
164  * PUBLIC:     u_int8_t *, size_t));
165  */
166 int
167 __aes_encrypt(env, aes_data, iv, data, data_len)
168         ENV *env;
169         void *aes_data;
170         void *iv;
171         u_int8_t *data;
172         size_t data_len;
173 {
174         AES_CIPHER *aes;
175 #ifdef  HAVE_CRYPTO_IPP
176         IppStatus ipp_ret;
177 #else
178         cipherInstance c;
179 #endif
180         u_int32_t tmp_iv[DB_IV_BYTES/4];
181         int ret;
182
183         aes = (AES_CIPHER *)aes_data;
184         if (aes == NULL || data == NULL)
185                 return (EINVAL);
186         if ((data_len % DB_AES_CHUNK) != 0)
187                 return (EINVAL);
188         /*
189          * Generate the IV here.  We store it in a tmp IV because
190          * the IV might be stored within the data we are encrypting
191          * and so we will copy it over to the given location after
192          * encryption is done.
193          * We don't do this outside of there because some encryption
194          * algorithms someone might add may not use IV's and we always
195          * want on here.
196          */
197         if ((ret = __db_generate_iv(env, tmp_iv)) != 0)
198                 return (ret);
199
200 #ifdef  HAVE_CRYPTO_IPP
201         if ((ipp_ret = ippsRijndael128EncryptCBC((const Ipp8u *)data,
202             (Ipp8u *)data, data_len, (IppsRijndael128Spec *)aes->ipp_ctx,
203             (const Ipp8u *)tmp_iv, 0)) != ippStsNoErr) {
204                 __aes_err(env, (int)ipp_ret);
205                 return (EAGAIN);
206         }
207 #else
208         /*
209          * Initialize the cipher
210          */
211         if ((ret = __db_cipherInit(&c, MODE_CBC, (char *)tmp_iv)) < 0) {
212                 __aes_err(env, ret);
213                 return (EAGAIN);
214         }
215
216         /* Do the encryption */
217         if ((ret = __db_blockEncrypt(&c, &aes->encrypt_ki, data, data_len * 8,
218             data)) < 0) {
219                 __aes_err(env, ret);
220                 return (EAGAIN);
221         }
222 #endif
223         memcpy(iv, tmp_iv, DB_IV_BYTES);
224         return (0);
225 }
226
227 /*
228  * __aes_init --
229  *      Initialize the AES encryption instantiation.
230  *
231  * PUBLIC: int __aes_init __P((ENV *, DB_CIPHER *));
232  */
233 int
234 __aes_init(env, db_cipher)
235         ENV *env;
236         DB_CIPHER *db_cipher;
237 {
238         DB_ENV *dbenv;
239
240         dbenv = env->dbenv;
241
242         return (__aes_derivekeys(
243             env, db_cipher, (u_int8_t *)dbenv->passwd, dbenv->passwd_len));
244 }
245
246 static int
247 __aes_derivekeys(env, db_cipher, passwd, plen)
248         ENV *env;
249         DB_CIPHER *db_cipher;
250         u_int8_t *passwd;
251         size_t plen;
252 {
253         AES_CIPHER *aes;
254         SHA1_CTX ctx;
255 #ifdef  HAVE_CRYPTO_IPP
256         IppStatus ipp_ret;
257 #else
258         int ret;
259 #endif
260         u_int32_t temp[DB_MAC_KEY/4];
261
262         if (passwd == NULL)
263                 return (EINVAL);
264
265         aes = (AES_CIPHER *)db_cipher->data;
266
267         /* Derive the crypto keys */
268         __db_SHA1Init(&ctx);
269         __db_SHA1Update(&ctx, passwd, plen);
270         __db_SHA1Update(&ctx, (u_int8_t *)DB_ENC_MAGIC, strlen(DB_ENC_MAGIC));
271         __db_SHA1Update(&ctx, passwd, plen);
272         __db_SHA1Final((u_int8_t *)temp, &ctx);
273
274 #ifdef  HAVE_CRYPTO_IPP
275         if ((ipp_ret = ippsRijndael128Init((const Ipp8u *)temp,
276             IppsRijndaelKey128, (IppsRijndael128Spec *)aes->ipp_ctx))
277             != ippStsNoErr) {
278                 __aes_err(env, (int)ipp_ret);
279                 return (EAGAIN);
280         }
281 #else
282         if ((ret = __db_makeKey(&aes->encrypt_ki, DIR_ENCRYPT,
283             DB_AES_KEYLEN, (char *)temp)) != TRUE) {
284                 __aes_err(env, ret);
285                 return (EAGAIN);
286         }
287         if ((ret = __db_makeKey(&aes->decrypt_ki, DIR_DECRYPT,
288             DB_AES_KEYLEN, (char *)temp)) != TRUE) {
289                 __aes_err(env, ret);
290                 return (EAGAIN);
291         }
292 #endif
293         return (0);
294 }
295
296 /*
297  * __aes_err --
298  *      Handle AES-specific errors.  Codes and messages derived from
299  *      rijndael/rijndael-api-fst.h.
300  */
301 static void
302 __aes_err(env, err)
303         ENV *env;
304         int err;
305 {
306         char *errstr;
307
308         switch (err) {
309 #ifdef  HAVE_CRYPTO_IPP
310         case ippStsNullPtrErr:
311                 errstr = DB_STR("0182", "IPP AES NULL pointer error");
312                 break;
313         case ippStsLengthErr:
314                 errstr = DB_STR("0183", "IPP AES length error");
315                 break;
316         case ippStsContextMatchErr:
317                 errstr = DB_STR("0184",
318                     "IPP AES context does not match operation");
319                 break;
320         case ippStsUnderRunErr:
321                 errstr = DB_STR("0185", "IPP AES srclen size error");
322                 break;
323 #else
324         case BAD_KEY_DIR:
325                 errstr = DB_STR("0186", "AES key direction is invalid");
326                 break;
327         case BAD_KEY_MAT:
328                 errstr = DB_STR("0187",
329                     "AES key material not of correct length");
330                 break;
331         case BAD_KEY_INSTANCE:
332                 errstr = DB_STR("0188", "AES key passwd not valid");
333                 break;
334         case BAD_CIPHER_MODE:
335                 errstr = DB_STR("0189",
336                     "AES cipher in wrong state (not initialized)");
337                 break;
338         case BAD_BLOCK_LENGTH:
339                 errstr = DB_STR("0190", "AES bad block length");
340                 break;
341         case BAD_CIPHER_INSTANCE:
342                 errstr = DB_STR("0191", "AES cipher instance is invalid");
343                 break;
344         case BAD_DATA:
345                 errstr = DB_STR("0192", "AES data contents are invalid");
346                 break;
347         case BAD_OTHER:
348                 errstr = DB_STR("0193", "AES unknown error");
349                 break;
350 #endif
351         default:
352                 errstr = DB_STR("0194", "AES error unrecognized");
353                 break;
354         }
355         __db_errx(env, "%s", errstr);
356         return;
357 }