aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorAlex Wilson <[email protected]>2014-10-09 21:39:29 +1000
committerMarcus Arendt <[email protected]>2014-11-28 09:25:45 +0100
commit425a34001fdd5de8396c5c9903f4f38a9d49a15c (patch)
treefe60dd1350a822d39040b5e96f90eb134a4815c5 /lib
parent0ba335ba103958e9378b29bbbca1cafc985316ba (diff)
downloadotp-425a34001fdd5de8396c5c9903f4f38a9d49a15c.tar.gz
otp-425a34001fdd5de8396c5c9903f4f38a9d49a15c.tar.bz2
otp-425a34001fdd5de8396c5c9903f4f38a9d49a15c.zip
crypto: use EVP for AES-CBC
This enables the use of hardware acceleration for AES crypto on newer Intel CPUs (AES-NI), among other platforms.
Diffstat (limited to 'lib')
-rw-r--r--lib/crypto/c_src/crypto.c55
1 files changed, 40 insertions, 15 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index a42de9adb1..750f3db7ef 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -2464,11 +2464,12 @@ done:
static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, IVec, Data, IsEncrypt) */
ErlNifBinary key_bin, ivec_bin, data_bin;
- AES_KEY aes_key;
unsigned char ivec[16];
- int i;
+ int enc, i = 0, outlen = 0;
+ EVP_CIPHER_CTX *ctx = NULL;
+ const EVP_CIPHER *cipher = NULL;
unsigned char* ret_ptr;
- ERL_NIF_TERM ret;
+ ERL_NIF_TERM ret;
CHECK_OSE_CRYPTO();
@@ -2482,20 +2483,44 @@ static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
return enif_make_badarg(env);
}
- if (argv[3] == atom_true) {
- i = AES_ENCRYPT;
- AES_set_encrypt_key(key_bin.data, key_bin.size*8, &aes_key);
- }
- else {
- i = AES_DECRYPT;
- AES_set_decrypt_key(key_bin.data, key_bin.size*8, &aes_key);
- }
+ if (argv[3] == atom_true)
+ enc = 1;
+ else
+ enc = 0;
+
+ if (!(ctx = EVP_CIPHER_CTX_new()))
+ return enif_make_badarg(env);
+
+ if (key_bin.size == 16)
+ cipher = EVP_aes_128_cbc();
+ else if (key_bin.size == 32)
+ cipher = EVP_aes_256_cbc();
+
+ memcpy(ivec, ivec_bin.data, 16); /* writeable copy */
+
+ /* openssl docs say we need to leave at least 3 blocks available
+ at the end of the buffer for EVP calls. let's be safe */
+ ret_ptr = enif_make_new_binary(env, data_bin.size + 16*3, &ret);
+
+ if (EVP_CipherInit_ex(ctx, cipher, NULL, key_bin.data, ivec, enc) != 1)
+ return enif_make_badarg(env);
+
+ /* disable padding, we only handle whole blocks */
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+
+ if (EVP_CipherUpdate(ctx, ret_ptr, &i, data_bin.data, data_bin.size) != 1)
+ return enif_make_badarg(env);
+ outlen += i;
+ if (EVP_CipherFinal_ex(ctx, ret_ptr + outlen, &i) != 1)
+ return enif_make_badarg(env);
+ outlen += i;
+
+ EVP_CIPHER_CTX_free(ctx);
- ret_ptr = enif_make_new_binary(env, data_bin.size, &ret);
- memcpy(ivec, ivec_bin.data, 16); /* writable copy */
- AES_cbc_encrypt(data_bin.data, ret_ptr, data_bin.size, &aes_key, ivec, i);
CONSUME_REDS(env,data_bin);
- return ret;
+
+ /* the garbage collector is going to love this */
+ return enif_make_sub_binary(env, ret, 0, outlen);
}
static ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])