summaryrefslogtreecommitdiff
path: root/src/crypto/aes_method.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/aes_method.c')
-rw-r--r--src/crypto/aes_method.c357
1 files changed, 357 insertions, 0 deletions
diff --git a/src/crypto/aes_method.c b/src/crypto/aes_method.c
new file mode 100644
index 00000000..47193539
--- /dev/null
+++ b/src/crypto/aes_method.c
@@ -0,0 +1,357 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2001, 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Some parts of this code originally written by Adam Stubblefield,
+ * -- astubble@rice.edu.
+ *
+ * $Id$
+ */
+
+#include "db_config.h"
+
+#include "db_int.h"
+#include "dbinc/crypto.h"
+#include "dbinc/hmac.h"
+
+#ifdef HAVE_CRYPTO_IPP
+#include <ippcp.h>
+#endif
+
+static void __aes_err __P((ENV *, int));
+static int __aes_derivekeys __P((ENV *, DB_CIPHER *, u_int8_t *, size_t));
+
+/*
+ * __aes_setup --
+ * Setup AES functions.
+ *
+ * PUBLIC: int __aes_setup __P((ENV *, DB_CIPHER *));
+ */
+int
+__aes_setup(env, db_cipher)
+ ENV *env;
+ DB_CIPHER *db_cipher;
+{
+ AES_CIPHER *aes_cipher;
+ int ret;
+#ifdef HAVE_CRYPTO_IPP
+ int ctx_size = 0;
+ IppStatus ipp_ret;
+#endif
+
+ db_cipher->adj_size = __aes_adj_size;
+ db_cipher->close = __aes_close;
+ db_cipher->decrypt = __aes_decrypt;
+ db_cipher->encrypt = __aes_encrypt;
+ db_cipher->init = __aes_init;
+ if ((ret = __os_calloc(env, 1, sizeof(AES_CIPHER), &aes_cipher)) != 0)
+ return (ret);
+#ifdef HAVE_CRYPTO_IPP
+ /*
+ * IPP AES encryption context size can only be obtained through this
+ * function call, cannot directly declare IppsRijndael128Spec within
+ * AES_CIPHER struct.
+ */
+ if ((ipp_ret = ippsRijndael128GetSize(&ctx_size)) != ippStsNoErr) {
+ __aes_err(env, (int)ipp_ret);
+ return (EAGAIN);
+ }
+ if ((ret = __os_malloc(env, ctx_size, &aes_cipher->ipp_ctx)) != 0) {
+ __os_free(env, aes_cipher);
+ return (ret);
+ }
+#endif
+ db_cipher->data = aes_cipher;
+ return (0);
+}
+
+/*
+ * __aes_adj_size --
+ * Given a size, return an addition amount needed to meet the
+ * "chunk" needs of the algorithm.
+ *
+ * PUBLIC: u_int __aes_adj_size __P((size_t));
+ */
+u_int
+__aes_adj_size(len)
+ size_t len;
+{
+ if (len % DB_AES_CHUNK == 0)
+ return (0);
+ return (DB_AES_CHUNK - (u_int)(len % DB_AES_CHUNK));
+}
+
+/*
+ * __aes_close --
+ * Destroy the AES encryption instantiation.
+ *
+ * PUBLIC: int __aes_close __P((ENV *, void *));
+ */
+int
+__aes_close(env, data)
+ ENV *env;
+ void *data;
+{
+#ifdef HAVE_CRYPTO_IPP
+ AES_CIPHER *aes_cipher = (AES_CIPHER *)data;
+ __os_free(env, aes_cipher->ipp_ctx);
+#endif
+ __os_free(env, data);
+ return (0);
+}
+
+/*
+ * __aes_decrypt --
+ * Decrypt data with AES.
+ *
+ * PUBLIC: int __aes_decrypt __P((ENV *, void *, void *,
+ * PUBLIC: u_int8_t *, size_t));
+ */
+int
+__aes_decrypt(env, aes_data, iv, cipher, cipher_len)
+ ENV *env;
+ void *aes_data;
+ void *iv;
+ u_int8_t *cipher;
+ size_t cipher_len;
+{
+ AES_CIPHER *aes;
+#ifdef HAVE_CRYPTO_IPP
+ IppStatus ipp_ret;
+#else
+ cipherInstance c;
+#endif
+ int ret;
+
+ aes = (AES_CIPHER *)aes_data;
+ if (iv == NULL || cipher == NULL)
+ return (EINVAL);
+ if ((cipher_len % DB_AES_CHUNK) != 0)
+ return (EINVAL);
+
+#ifdef HAVE_CRYPTO_IPP
+ if ((ipp_ret = ippsRijndael128DecryptCBC((const Ipp8u *)cipher,
+ (Ipp8u *)cipher, cipher_len, (IppsRijndael128Spec *)aes->ipp_ctx,
+ (const Ipp8u *)iv, 0)) != ippStsNoErr) {
+ __aes_err(env, (int)ipp_ret);
+ return (EAGAIN);
+ }
+#else
+ /*
+ * Initialize the cipher
+ */
+ if ((ret = __db_cipherInit(&c, MODE_CBC, iv)) < 0) {
+ __aes_err(env, ret);
+ return (EAGAIN);
+ }
+
+ /* Do the decryption */
+ if ((ret = __db_blockDecrypt(&c, &aes->decrypt_ki, cipher,
+ cipher_len * 8, cipher)) < 0) {
+ __aes_err(env, ret);
+ return (EAGAIN);
+ }
+#endif
+ return (0);
+}
+
+/*
+ * __aes_encrypt --
+ * Encrypt data with AES.
+ *
+ * PUBLIC: int __aes_encrypt __P((ENV *, void *, void *,
+ * PUBLIC: u_int8_t *, size_t));
+ */
+int
+__aes_encrypt(env, aes_data, iv, data, data_len)
+ ENV *env;
+ void *aes_data;
+ void *iv;
+ u_int8_t *data;
+ size_t data_len;
+{
+ AES_CIPHER *aes;
+#ifdef HAVE_CRYPTO_IPP
+ IppStatus ipp_ret;
+#else
+ cipherInstance c;
+#endif
+ u_int32_t tmp_iv[DB_IV_BYTES/4];
+ int ret;
+
+ aes = (AES_CIPHER *)aes_data;
+ if (aes == NULL || data == NULL)
+ return (EINVAL);
+ if ((data_len % DB_AES_CHUNK) != 0)
+ return (EINVAL);
+ /*
+ * Generate the IV here. We store it in a tmp IV because
+ * the IV might be stored within the data we are encrypting
+ * and so we will copy it over to the given location after
+ * encryption is done.
+ * We don't do this outside of there because some encryption
+ * algorithms someone might add may not use IV's and we always
+ * want on here.
+ */
+ if ((ret = __db_generate_iv(env, tmp_iv)) != 0)
+ return (ret);
+
+#ifdef HAVE_CRYPTO_IPP
+ if ((ipp_ret = ippsRijndael128EncryptCBC((const Ipp8u *)data,
+ (Ipp8u *)data, data_len, (IppsRijndael128Spec *)aes->ipp_ctx,
+ (const Ipp8u *)tmp_iv, 0)) != ippStsNoErr) {
+ __aes_err(env, (int)ipp_ret);
+ return (EAGAIN);
+ }
+#else
+ /*
+ * Initialize the cipher
+ */
+ if ((ret = __db_cipherInit(&c, MODE_CBC, (char *)tmp_iv)) < 0) {
+ __aes_err(env, ret);
+ return (EAGAIN);
+ }
+
+ /* Do the encryption */
+ if ((ret = __db_blockEncrypt(&c, &aes->encrypt_ki, data, data_len * 8,
+ data)) < 0) {
+ __aes_err(env, ret);
+ return (EAGAIN);
+ }
+#endif
+ memcpy(iv, tmp_iv, DB_IV_BYTES);
+ return (0);
+}
+
+/*
+ * __aes_init --
+ * Initialize the AES encryption instantiation.
+ *
+ * PUBLIC: int __aes_init __P((ENV *, DB_CIPHER *));
+ */
+int
+__aes_init(env, db_cipher)
+ ENV *env;
+ DB_CIPHER *db_cipher;
+{
+ DB_ENV *dbenv;
+
+ dbenv = env->dbenv;
+
+ return (__aes_derivekeys(
+ env, db_cipher, (u_int8_t *)dbenv->passwd, dbenv->passwd_len));
+}
+
+static int
+__aes_derivekeys(env, db_cipher, passwd, plen)
+ ENV *env;
+ DB_CIPHER *db_cipher;
+ u_int8_t *passwd;
+ size_t plen;
+{
+ AES_CIPHER *aes;
+ SHA1_CTX ctx;
+#ifdef HAVE_CRYPTO_IPP
+ IppStatus ipp_ret;
+#else
+ int ret;
+#endif
+ u_int32_t temp[DB_MAC_KEY/4];
+
+ if (passwd == NULL)
+ return (EINVAL);
+
+ aes = (AES_CIPHER *)db_cipher->data;
+
+ /* Derive the crypto keys */
+ __db_SHA1Init(&ctx);
+ __db_SHA1Update(&ctx, passwd, plen);
+ __db_SHA1Update(&ctx, (u_int8_t *)DB_ENC_MAGIC, strlen(DB_ENC_MAGIC));
+ __db_SHA1Update(&ctx, passwd, plen);
+ __db_SHA1Final((u_int8_t *)temp, &ctx);
+
+#ifdef HAVE_CRYPTO_IPP
+ if ((ipp_ret = ippsRijndael128Init((const Ipp8u *)temp,
+ IppsRijndaelKey128, (IppsRijndael128Spec *)aes->ipp_ctx))
+ != ippStsNoErr) {
+ __aes_err(env, (int)ipp_ret);
+ return (EAGAIN);
+ }
+#else
+ if ((ret = __db_makeKey(&aes->encrypt_ki, DIR_ENCRYPT,
+ DB_AES_KEYLEN, (char *)temp)) != TRUE) {
+ __aes_err(env, ret);
+ return (EAGAIN);
+ }
+ if ((ret = __db_makeKey(&aes->decrypt_ki, DIR_DECRYPT,
+ DB_AES_KEYLEN, (char *)temp)) != TRUE) {
+ __aes_err(env, ret);
+ return (EAGAIN);
+ }
+#endif
+ return (0);
+}
+
+/*
+ * __aes_err --
+ * Handle AES-specific errors. Codes and messages derived from
+ * rijndael/rijndael-api-fst.h.
+ */
+static void
+__aes_err(env, err)
+ ENV *env;
+ int err;
+{
+ char *errstr;
+
+ switch (err) {
+#ifdef HAVE_CRYPTO_IPP
+ case ippStsNullPtrErr:
+ errstr = DB_STR("0182", "IPP AES NULL pointer error");
+ break;
+ case ippStsLengthErr:
+ errstr = DB_STR("0183", "IPP AES length error");
+ break;
+ case ippStsContextMatchErr:
+ errstr = DB_STR("0184",
+ "IPP AES context does not match operation");
+ break;
+ case ippStsUnderRunErr:
+ errstr = DB_STR("0185", "IPP AES srclen size error");
+ break;
+#else
+ case BAD_KEY_DIR:
+ errstr = DB_STR("0186", "AES key direction is invalid");
+ break;
+ case BAD_KEY_MAT:
+ errstr = DB_STR("0187",
+ "AES key material not of correct length");
+ break;
+ case BAD_KEY_INSTANCE:
+ errstr = DB_STR("0188", "AES key passwd not valid");
+ break;
+ case BAD_CIPHER_MODE:
+ errstr = DB_STR("0189",
+ "AES cipher in wrong state (not initialized)");
+ break;
+ case BAD_BLOCK_LENGTH:
+ errstr = DB_STR("0190", "AES bad block length");
+ break;
+ case BAD_CIPHER_INSTANCE:
+ errstr = DB_STR("0191", "AES cipher instance is invalid");
+ break;
+ case BAD_DATA:
+ errstr = DB_STR("0192", "AES data contents are invalid");
+ break;
+ case BAD_OTHER:
+ errstr = DB_STR("0193", "AES unknown error");
+ break;
+#endif
+ default:
+ errstr = DB_STR("0194", "AES error unrecognized");
+ break;
+ }
+ __db_errx(env, "%s", errstr);
+ return;
+}