diff options
author | Alex Wilson <[email protected]> | 2014-10-09 21:39:29 +1000 |
---|---|---|
committer | Sverker Eriksson <[email protected]> | 2016-02-26 18:00:18 +0100 |
commit | a77aaf91b9695d704607bf7c09b0ec515d457871 (patch) | |
tree | a56bc1ce213de8a1a206ffb9e3986a893a3fdf1e | |
parent | 23790daf1a2d384b0fc11c655fa825151d9fa420 (diff) | |
download | otp-a77aaf91b9695d704607bf7c09b0ec515d457871.tar.gz otp-a77aaf91b9695d704607bf7c09b0ec515d457871.tar.bz2 otp-a77aaf91b9695d704607bf7c09b0ec515d457871.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.
Cherry-pick from 425a34001fdd
-rw-r--r-- | lib/crypto/c_src/crypto.c | 55 |
1 files changed, 40 insertions, 15 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 42fb172953..b4fd37b5eb 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -2058,11 +2058,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; if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin) || (key_bin.size != 16 && key_bin.size != 32) @@ -2074,20 +2075,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 do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) |