diff options
Diffstat (limited to 'lib/crypto/c_src/aes.c')
-rw-r--r-- | lib/crypto/c_src/aes.c | 379 |
1 files changed, 270 insertions, 109 deletions
diff --git a/lib/crypto/c_src/aes.c b/lib/crypto/c_src/aes.c index 36cd02933f..2f30ec8a58 100644 --- a/lib/crypto/c_src/aes.c +++ b/lib/crypto/c_src/aes.c @@ -28,24 +28,40 @@ ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] unsigned char ivec_clone[16]; /* writable copy */ int new_ivlen = 0; ERL_NIF_TERM ret; + unsigned char *outp; CHECK_NO_FIPS_MODE(); - if (!enif_inspect_iolist_as_binary(env, argv[0], &key) - || !(key.size == 16 || key.size == 24 || key.size == 32) - || !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16 - || !enif_inspect_iolist_as_binary(env, argv[2], &text)) { - return enif_make_badarg(env); - } + ASSERT(argc == 4); + + if (!enif_inspect_iolist_as_binary(env, argv[0], &key)) + goto bad_arg; + if (key.size != 16 && key.size != 24 && key.size != 32) + goto bad_arg; + if (!enif_inspect_binary(env, argv[1], &ivec)) + goto bad_arg; + if (ivec.size != 16) + goto bad_arg; + if (!enif_inspect_iolist_as_binary(env, argv[2], &text)) + goto bad_arg; memcpy(ivec_clone, ivec.data, 16); - AES_set_encrypt_key(key.data, key.size * 8, &aes_key); + + /* NOTE: This function returns 0 on success unlike most OpenSSL functions */ + if (AES_set_encrypt_key(key.data, (int)key.size * 8, &aes_key) != 0) + goto err; + if ((outp = enif_make_new_binary(env, text.size, &ret)) == NULL) + goto err; AES_cfb8_encrypt((unsigned char *) text.data, - enif_make_new_binary(env, text.size, &ret), + outp, text.size, &aes_key, ivec_clone, &new_ivlen, (argv[3] == atom_true)); CONSUME_REDS(env,text); return ret; + + bad_arg: + err: + return enif_make_badarg(env); } ERL_NIF_TERM aes_cfb_128_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -55,22 +71,39 @@ ERL_NIF_TERM aes_cfb_128_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM unsigned char ivec_clone[16]; /* writable copy */ int new_ivlen = 0; ERL_NIF_TERM ret; + unsigned char *outp; - if (!enif_inspect_iolist_as_binary(env, argv[0], &key) - || !(key.size == 16 || key.size == 24 || key.size == 32) - || !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16 - || !enif_inspect_iolist_as_binary(env, argv[2], &text)) { - return enif_make_badarg(env); - } + ASSERT(argc == 4); + + if (!enif_inspect_iolist_as_binary(env, argv[0], &key)) + goto bad_arg; + if (key.size != 16 && key.size != 24 && key.size != 32) + goto bad_arg; + if (!enif_inspect_binary(env, argv[1], &ivec)) + goto bad_arg; + if (ivec.size != 16) + goto bad_arg; + if (!enif_inspect_iolist_as_binary(env, argv[2], &text)) + goto bad_arg; memcpy(ivec_clone, ivec.data, 16); - AES_set_encrypt_key(key.data, key.size * 8, &aes_key); + + /* NOTE: This function returns 0 on success unlike most OpenSSL functions */ + if (AES_set_encrypt_key(key.data, (int)key.size * 8, &aes_key) != 0) + goto err; + + if ((outp = enif_make_new_binary(env, text.size, &ret)) == NULL) + goto err; AES_cfb128_encrypt((unsigned char *) text.data, - enif_make_new_binary(env, text.size, &ret), + outp, text.size, &aes_key, ivec_clone, &new_ivlen, (argv[3] == atom_true)); CONSUME_REDS(env,text); return ret; + + bad_arg: + err: + return enif_make_badarg(env); } ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -79,36 +112,54 @@ ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv ErlNifBinary key_bin, ivec_bin, data_bin; AES_KEY aes_key; unsigned char ivec[32]; - int i; + int type; unsigned char* ret_ptr; ERL_NIF_TERM ret; CHECK_NO_FIPS_MODE(); - if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin) - || (key_bin.size != 16 && key_bin.size != 32) - || !enif_inspect_binary(env, argv[1], &ivec_bin) - || ivec_bin.size != 32 - || !enif_inspect_iolist_as_binary(env, argv[2], &data_bin) - || data_bin.size % 16 != 0) { - - return enif_make_badarg(env); - } + ASSERT(argc == 4); + + if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)) + goto bad_arg; + if (key_bin.size != 16 && key_bin.size != 32) + goto bad_arg; + if (!enif_inspect_binary(env, argv[1], &ivec_bin)) + goto bad_arg; + if (ivec_bin.size != 32) + goto bad_arg; + if (!enif_inspect_iolist_as_binary(env, argv[2], &data_bin)) + goto bad_arg; + if (data_bin.size % 16 != 0) + goto bad_arg; if (argv[3] == atom_true) { - i = AES_ENCRYPT; - AES_set_encrypt_key(key_bin.data, key_bin.size*8, &aes_key); + type = AES_ENCRYPT; + /* NOTE: This function returns 0 on success unlike most OpenSSL functions */ + if (AES_set_encrypt_key(key_bin.data, (int)key_bin.size * 8, &aes_key) != 0) + goto err; } else { - i = AES_DECRYPT; - AES_set_decrypt_key(key_bin.data, key_bin.size*8, &aes_key); + type = AES_DECRYPT; + /* NOTE: This function returns 0 on success unlike most OpenSSL functions */ + if (AES_set_decrypt_key(key_bin.data, (int)key_bin.size * 8, &aes_key) != 0) + goto err; } - ret_ptr = enif_make_new_binary(env, data_bin.size, &ret); + if ((ret_ptr = enif_make_new_binary(env, data_bin.size, &ret)) == NULL) + goto err; + memcpy(ivec, ivec_bin.data, 32); /* writable copy */ - AES_ige_encrypt(data_bin.data, ret_ptr, data_bin.size, &aes_key, ivec, i); + + AES_ige_encrypt(data_bin.data, ret_ptr, data_bin.size, &aes_key, ivec, type); + CONSUME_REDS(env,data_bin); return ret; + + bad_arg: + err: + return enif_make_badarg(env); + #else return atom_notsup; #endif @@ -121,56 +172,106 @@ ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key, IVec) */ ErlNifBinary key_bin, ivec_bin; - struct evp_cipher_ctx *ctx; + struct evp_cipher_ctx *ctx = NULL; const EVP_CIPHER *cipher; ERL_NIF_TERM ret; - if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin) - || !enif_inspect_binary(env, argv[1], &ivec_bin) - || ivec_bin.size != 16) { - return enif_make_badarg(env); - } + ASSERT(argc == 2); + + if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)) + goto bad_arg; + if (!enif_inspect_binary(env, argv[1], &ivec_bin)) + goto bad_arg; + if (ivec_bin.size != 16) + goto bad_arg; switch (key_bin.size) { - case 16: cipher = EVP_aes_128_ctr(); break; - case 24: cipher = EVP_aes_192_ctr(); break; - case 32: cipher = EVP_aes_256_ctr(); break; - default: return enif_make_badarg(env); + case 16: + cipher = EVP_aes_128_ctr(); + break; + case 24: + cipher = EVP_aes_192_ctr(); + break; + case 32: + cipher = EVP_aes_256_ctr(); + break; + default: + goto bad_arg; } - ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx)); - ctx->ctx = EVP_CIPHER_CTX_new(); - EVP_CipherInit_ex(ctx->ctx, cipher, NULL, - key_bin.data, ivec_bin.data, 1); - EVP_CIPHER_CTX_set_padding(ctx->ctx, 0); + if ((ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx))) == NULL) + goto err; + if ((ctx->ctx = EVP_CIPHER_CTX_new()) == NULL) + goto err; + + if (EVP_CipherInit_ex(ctx->ctx, cipher, NULL, + key_bin.data, ivec_bin.data, 1) != 1) + goto err; + + if (EVP_CIPHER_CTX_set_padding(ctx->ctx, 0) != 1) + goto err; + ret = enif_make_resource(env, ctx); - enif_release_resource(ctx); + goto done; + + bad_arg: + return enif_make_badarg(env); + + err: + ret = enif_make_badarg(env); + + done: + if (ctx) + enif_release_resource(ctx); return ret; } ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Context, Data) */ - struct evp_cipher_ctx *ctx, *new_ctx; + struct evp_cipher_ctx *ctx = NULL, *new_ctx = NULL; ErlNifBinary data_bin; ERL_NIF_TERM ret, cipher_term; unsigned char *out; int outl = 0; - if (!enif_get_resource(env, argv[0], evp_cipher_ctx_rtype, (void**)&ctx) - || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { - return enif_make_badarg(env); - } - new_ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx)); - new_ctx->ctx = EVP_CIPHER_CTX_new(); - EVP_CIPHER_CTX_copy(new_ctx->ctx, ctx->ctx); - out = enif_make_new_binary(env, data_bin.size, &cipher_term); - EVP_CipherUpdate(new_ctx->ctx, out, &outl, data_bin.data, data_bin.size); - ASSERT(outl == data_bin.size); + ASSERT(argc == 2); + + if (!enif_get_resource(env, argv[0], evp_cipher_ctx_rtype, (void**)&ctx)) + goto bad_arg; + if (!enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) + goto bad_arg; + if (data_bin.size > INT_MAX) + goto bad_arg; + + if ((new_ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx))) == NULL) + goto err; + if ((new_ctx->ctx = EVP_CIPHER_CTX_new()) == NULL) + goto err; + + if (EVP_CIPHER_CTX_copy(new_ctx->ctx, ctx->ctx) != 1) + goto err; + + if ((out = enif_make_new_binary(env, data_bin.size, &cipher_term)) == NULL) + goto err; + + if (EVP_CipherUpdate(new_ctx->ctx, out, &outl, data_bin.data, (int)data_bin.size) != 1) + goto err; + ASSERT(outl >= 0 && (size_t)outl == data_bin.size); ret = enif_make_tuple2(env, enif_make_resource(env, new_ctx), cipher_term); - enif_release_resource(new_ctx); CONSUME_REDS(env,data_bin); + goto done; + + bad_arg: + return enif_make_badarg(env); + + err: + ret = enif_make_badarg(env); + + done: + if (new_ctx) + enif_release_resource(new_ctx); return ret; } @@ -180,17 +281,29 @@ ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar {/* (Key, IVec) */ ErlNifBinary key_bin, ivec_bin; ERL_NIF_TERM ecount_bin; + unsigned char *outp; - if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin) - || !enif_inspect_binary(env, argv[1], &ivec_bin) - || !(key_bin.size == 16 || key_bin.size == 24 || key_bin.size ==32) - || ivec_bin.size != 16) { - return enif_make_badarg(env); - } + ASSERT(argc == 2); + + if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)) + goto bad_arg; + if (key_bin.size != 16 && key_bin.size != 24 && key_bin.size != 32) + goto bad_arg; + if (!enif_inspect_binary(env, argv[1], &ivec_bin)) + goto bad_arg; + if (ivec_bin.size != 16) + goto bad_arg; + + if ((outp = enif_make_new_binary(env, AES_BLOCK_SIZE, &ecount_bin)) == NULL) + goto err; + + memset(outp, 0, AES_BLOCK_SIZE); - memset(enif_make_new_binary(env, AES_BLOCK_SIZE, &ecount_bin), - 0, AES_BLOCK_SIZE); return enif_make_tuple4(env, argv[0], argv[1], ecount_bin, enif_make_int(env, 0)); + + bad_arg: + err: + return enif_make_badarg(env); } ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -203,26 +316,48 @@ ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM const ERL_NIF_TERM *state_term; unsigned char * ivec2_buf; unsigned char * ecount2_buf; + unsigned char *outp; - if (!enif_get_tuple(env, argv[0], &state_arity, &state_term) - || state_arity != 4 - || !enif_inspect_iolist_as_binary(env, state_term[0], &key_bin) - || AES_set_encrypt_key(key_bin.data, key_bin.size*8, &aes_key) != 0 - || !enif_inspect_binary(env, state_term[1], &ivec_bin) || ivec_bin.size != 16 - || !enif_inspect_binary(env, state_term[2], &ecount_bin) || ecount_bin.size != AES_BLOCK_SIZE - || !enif_get_uint(env, state_term[3], &num) - || !enif_inspect_iolist_as_binary(env, argv[1], &text_bin)) { - return enif_make_badarg(env); - } - - ivec2_buf = enif_make_new_binary(env, ivec_bin.size, &ivec2_term); - ecount2_buf = enif_make_new_binary(env, ecount_bin.size, &ecount2_term); + ASSERT(argc == 2); + + if (!enif_get_tuple(env, argv[0], &state_arity, &state_term)) + goto bad_arg; + if (state_arity != 4) + goto bad_arg; + if (!enif_inspect_iolist_as_binary(env, state_term[0], &key_bin)) + goto bad_arg; + if (key_bin.size > INT_MAX / 8) + goto bad_arg; + if (!enif_inspect_binary(env, state_term[1], &ivec_bin)) + goto bad_arg; + if (ivec_bin.size != 16) + goto bad_arg; + if (!enif_inspect_binary(env, state_term[2], &ecount_bin)) + goto bad_arg; + if (ecount_bin.size != AES_BLOCK_SIZE) + goto bad_arg; + if (!enif_get_uint(env, state_term[3], &num)) + goto bad_arg; + if (!enif_inspect_iolist_as_binary(env, argv[1], &text_bin)) + goto bad_arg; + + /* NOTE: This function returns 0 on success unlike most OpenSSL functions */ + if (AES_set_encrypt_key(key_bin.data, (int)key_bin.size * 8, &aes_key) != 0) + goto bad_arg; + + if ((ivec2_buf = enif_make_new_binary(env, ivec_bin.size, &ivec2_term)) == NULL) + goto err; + if ((ecount2_buf = enif_make_new_binary(env, ecount_bin.size, &ecount2_term)) == NULL) + goto err; memcpy(ivec2_buf, ivec_bin.data, 16); memcpy(ecount2_buf, ecount_bin.data, ecount_bin.size); + if ((outp = enif_make_new_binary(env, text_bin.size, &cipher_term)) == NULL) + goto err; + AES_ctr128_encrypt((unsigned char *) text_bin.data, - enif_make_new_binary(env, text_bin.size, &cipher_term), + outp, text_bin.size, &aes_key, ivec2_buf, ecount2_buf, &num); num2_term = enif_make_uint(env, num); @@ -230,53 +365,79 @@ ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ret = enif_make_tuple2(env, new_state_term, cipher_term); CONSUME_REDS(env,text_bin); return ret; + + bad_arg: + err: + return enif_make_badarg(env); } #endif /* !HAVE_EVP_AES_CTR */ #ifdef HAVE_GCM_EVP_DECRYPT_BUG ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Type,Key,Iv,AAD,In,Tag) */ - GCM128_CONTEXT *ctx; + GCM128_CONTEXT *ctx = NULL; ErlNifBinary key, iv, aad, in, tag; AES_KEY aes_key; unsigned char *outp; - ERL_NIF_TERM out; - - if (!enif_inspect_iolist_as_binary(env, argv[1], &key) - || AES_set_encrypt_key(key.data, key.size*8, &aes_key) != 0 - || !enif_inspect_binary(env, argv[2], &iv) || iv.size == 0 - || !enif_inspect_iolist_as_binary(env, argv[3], &aad) - || !enif_inspect_iolist_as_binary(env, argv[4], &in) - || !enif_inspect_iolist_as_binary(env, argv[5], &tag)) { - return enif_make_badarg(env); - } - - if (!(ctx = CRYPTO_gcm128_new(&aes_key, (block128_f)AES_encrypt))) - return atom_error; + ERL_NIF_TERM out, ret; + + ASSERT(argc == 6); + + if (!enif_inspect_iolist_as_binary(env, argv[1], &key)) + goto bad_arg; + if (key.size > INT_MAX / 8) + goto bad_arg; + if (!enif_inspect_binary(env, argv[2], &iv)) + goto bad_arg; + if (iv.size == 0) + goto bad_arg; + if (!enif_inspect_iolist_as_binary(env, argv[3], &aad)) + goto bad_arg; + if (!enif_inspect_iolist_as_binary(env, argv[4], &in)) + goto bad_arg; + if (!enif_inspect_iolist_as_binary(env, argv[5], &tag)) + goto bad_arg; + + /* NOTE: This function returns 0 on success unlike most OpenSSL functions */ + if (AES_set_encrypt_key(key.data, (int)key.size * 8, &aes_key) != 0) + goto bad_arg; + + if ((ctx = CRYPTO_gcm128_new(&aes_key, (block128_f)AES_encrypt)) == NULL) + goto err; CRYPTO_gcm128_setiv(ctx, iv.data, iv.size); - if (CRYPTO_gcm128_aad(ctx, aad.data, aad.size)) - goto out_err; + /* NOTE: This function returns 0 on success unlike most OpenSSL functions */ + if (CRYPTO_gcm128_aad(ctx, aad.data, aad.size) != 0) + goto err; - outp = enif_make_new_binary(env, in.size, &out); + if ((outp = enif_make_new_binary(env, in.size, &out)) == NULL) + goto err; - /* decrypt */ - if (CRYPTO_gcm128_decrypt(ctx, in.data, outp, in.size)) - goto out_err; + /* NOTE: This function returns 0 on success unlike most OpenSSL functions */ + if (CRYPTO_gcm128_decrypt(ctx, in.data, outp, in.size) != 0) + goto err; /* calculate and check the tag */ - if (CRYPTO_gcm128_finish(ctx, tag.data, tag.size)) - goto out_err; + /* NOTE: This function returns 0 on success unlike most OpenSSL functions */ + if (CRYPTO_gcm128_finish(ctx, tag.data, tag.size) != 0) + goto err; - CRYPTO_gcm128_release(ctx); CONSUME_REDS(env, in); + ret = out; + goto done; + + bad_arg: + ret = enif_make_badarg(env); + goto done; - return out; + err: + ret = atom_error; -out_err: - CRYPTO_gcm128_release(ctx); - return atom_error; + done: + if (ctx) + CRYPTO_gcm128_release(ctx); + return ret; } #endif /* HAVE_GCM_EVP_DECRYPT_BUG */ |