aboutsummaryrefslogtreecommitdiffstats
path: root/lib/crypto/c_src/cipher.c
diff options
context:
space:
mode:
authorHans Nilsson <[email protected]>2019-01-31 10:27:23 +0100
committerHans Nilsson <[email protected]>2019-02-25 10:01:24 +0100
commitc7cab680b80ef9220832151ed2c8c23a5d590b8b (patch)
treec197e1682ecdea385f93b5bbeee540e444b84e06 /lib/crypto/c_src/cipher.c
parentb3dbf45fdbe8c584c89b5e061f6e9a28a5d3ea86 (diff)
downloadotp-c7cab680b80ef9220832151ed2c8c23a5d590b8b.tar.gz
otp-c7cab680b80ef9220832151ed2c8c23a5d590b8b.tar.bz2
otp-c7cab680b80ef9220832151ed2c8c23a5d590b8b.zip
crypto: New experimental api
The new files api_ng.h and api_ng.c implements an api using EVP. The api is not by any mean new, except for the crypto application in Erlang/OTP. The aims at using the block api in a stream manor, that is 1) call crypto_init/4 2..N) call crypto_update/{2,3} The purpose is to simplify and hopefully optimize the SSL and SSH applications. By keeping the crypto state in C in an enif_resource the costful state copying in SSL and SSH is reduced with 1-2 per message sent or received. Changes in other files are for adaptation like FIPS etc since many functions uses the central get_cipher_type() function.
Diffstat (limited to 'lib/crypto/c_src/cipher.c')
-rw-r--r--lib/crypto/c_src/cipher.c194
1 files changed, 149 insertions, 45 deletions
diff --git a/lib/crypto/c_src/cipher.c b/lib/crypto/c_src/cipher.c
index 449e636037..f8e44b228a 100644
--- a/lib/crypto/c_src/cipher.c
+++ b/lib/crypto/c_src/cipher.c
@@ -28,51 +28,122 @@
static struct cipher_type_t cipher_types[] =
{
- {{"rc2_cbc"},
#ifndef OPENSSL_NO_RC2
- {&EVP_rc2_cbc}
+ {{"rc2_cbc"}, {&EVP_rc2_cbc}, 0, NO_FIPS_CIPHER},
#else
- {NULL}
+ {{"rc2_cbc"}, {NULL}, 0, NO_FIPS_CIPHER},
#endif
- ,0},
- {{"des_cbc"}, {COND_NO_DES_PTR(&EVP_des_cbc)}, 0},
- {{"des_cfb"}, {COND_NO_DES_PTR(&EVP_des_cfb8)}, 0},
- {{"des_ecb"}, {COND_NO_DES_PTR(&EVP_des_ecb)}, 0},
- {{"des_ede3_cbc"}, {COND_NO_DES_PTR(&EVP_des_ede3_cbc)}, 0},
- {{"des_ede3_cbf"}, /* Misspelled, retained */
-#ifdef HAVE_DES_ede3_cfb_encrypt
- {COND_NO_DES_PTR(&EVP_des_ede3_cfb8)}
+#ifndef OPENSSL_NO_RC4
+ {{"rc4"}, {&EVP_rc4}, 0, NO_FIPS_CIPHER},
#else
- {NULL}
+ {{"rc4"}, {NULL}, 0, NO_FIPS_CIPHER},
#endif
- ,0},
- {{"des_ede3_cfb"},
+ {{"des_cbc"}, {COND_NO_DES_PTR(&EVP_des_cbc)}, 0, NO_FIPS_CIPHER},
+ {{"des_cfb"}, {COND_NO_DES_PTR(&EVP_des_cfb8)}, 0, NO_FIPS_CIPHER},
+ {{"des_ecb"}, {COND_NO_DES_PTR(&EVP_des_ecb)}, 0, NO_FIPS_CIPHER | ECB_BUG_0_9_8L},
+
+ {{"des_ede3_cbc"}, {COND_NO_DES_PTR(&EVP_des_ede3_cbc)}, 0, 0},
+
#ifdef HAVE_DES_ede3_cfb_encrypt
- {COND_NO_DES_PTR(&EVP_des_ede3_cfb8)}
+ {{"des_ede3_cfb"}, {COND_NO_DES_PTR(&EVP_des_ede3_cfb8)}, 0, 0},
+#else
+ {{"des_ede3_cfb"}, {NULL}, 0, 0},
+#endif
+
+ {{"blowfish_cbc"}, {&EVP_bf_cbc}, 0, NO_FIPS_CIPHER},
+ {{"blowfish_cfb64"}, {&EVP_bf_cfb64}, 0, NO_FIPS_CIPHER},
+ {{"blowfish_ofb64"}, {&EVP_bf_ofb}, 0, NO_FIPS_CIPHER},
+ {{"blowfish_ecb"}, {&EVP_bf_ecb}, 0, NO_FIPS_CIPHER | ECB_BUG_0_9_8L},
+
+ {{"aes_cbc"}, {&EVP_aes_128_cbc}, 16, 0},
+ {{"aes_cbc"}, {&EVP_aes_192_cbc}, 24, 0},
+ {{"aes_cbc"}, {&EVP_aes_256_cbc}, 32, 0},
+
+ {{"aes_128_cbc"}, {&EVP_aes_128_cbc}, 16, 0},
+ {{"aes_192_cbc"}, {&EVP_aes_192_cbc}, 24, 0},
+ {{"aes_256_cbc"}, {&EVP_aes_256_cbc}, 32, 0},
+
+ {{"aes_cfb8"}, {&EVP_aes_128_cfb8}, 16, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_cfb8"}, {&EVP_aes_192_cfb8}, 24, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_cfb8"}, {&EVP_aes_256_cfb8}, 32, NO_FIPS_CIPHER | AES_CFBx},
+
+ {{"aes_cfb128"}, {&EVP_aes_128_cfb128}, 16, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_cfb128"}, {&EVP_aes_192_cfb128}, 24, NO_FIPS_CIPHER | AES_CFBx},
+ {{"aes_cfb128"}, {&EVP_aes_256_cfb128}, 32, NO_FIPS_CIPHER | AES_CFBx},
+
+ {{"aes_ecb"}, {&EVP_aes_128_ecb}, 16, ECB_BUG_0_9_8L},
+ {{"aes_ecb"}, {&EVP_aes_192_ecb}, 24, ECB_BUG_0_9_8L},
+ {{"aes_ecb"}, {&EVP_aes_256_ecb}, 32, ECB_BUG_0_9_8L},
+
+#if defined(HAVE_EVP_AES_CTR)
+ {{"aes_128_ctr"}, {&EVP_aes_128_ctr}, 16, 0},
+ {{"aes_192_ctr"}, {&EVP_aes_192_ctr}, 24, 0},
+ {{"aes_256_ctr"}, {&EVP_aes_256_ctr}, 32, 0},
+ {{"aes_ctr"}, {&EVP_aes_128_ctr}, 16, 0},
+ {{"aes_ctr"}, {&EVP_aes_192_ctr}, 24, 0},
+ {{"aes_ctr"}, {&EVP_aes_256_ctr}, 32, 0},
+#else
+ {{"aes_128_ctr"}, {NULL}, 16, AES_CTR_COMPAT},
+ {{"aes_192_ctr"}, {NULL}, 24, AES_CTR_COMPAT},
+ {{"aes_256_ctr"}, {NULL}, 32, AES_CTR_COMPAT},
+ {{"aes_ctr"}, {NULL}, 0, AES_CTR_COMPAT},
+#endif
+
+#if defined(HAVE_CHACHA20)
+ {{"chacha20"}, {&EVP_chacha20}, 32, NO_FIPS_CIPHER},
+#else
+ {{"chacha20"}, {NULL}, 0, NO_FIPS_CIPHER},
+#endif
+
+ /*==== AEAD ciphers ====*/
+#if defined(HAVE_CHACHA20_POLY1305)
+ {{"chacha20_poly1305"}, {&EVP_chacha20_poly1305}, 0, NO_FIPS_CIPHER | AEAD_CIPHER, {{EVP_CTRL_AEAD_SET_IVLEN,EVP_CTRL_AEAD_GET_TAG,EVP_CTRL_AEAD_SET_TAG}}},
+#else
+ {{"chacha20_poly1305"}, {NULL}, 0, NO_FIPS_CIPHER | AEAD_CIPHER, {{0,0,0}}},
+#endif
+
+#if defined(HAVE_GCM)
+ {{"aes_gcm"}, {&EVP_aes_128_gcm}, 16, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_gcm"}, {&EVP_aes_192_gcm}, 24, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_gcm"}, {&EVP_aes_256_gcm}, 32, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_128_gcm"}, {&EVP_aes_128_gcm}, 16, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_192_gcm"}, {&EVP_aes_192_gcm}, 24, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+ {{"aes_256_gcm"}, {&EVP_aes_256_gcm}, 32, AEAD_CIPHER, {{EVP_CTRL_GCM_SET_IVLEN,EVP_CTRL_GCM_GET_TAG,EVP_CTRL_GCM_SET_TAG}}},
+#else
+ {{"aes_gcm"}, {NULL}, 0, AEAD_CIPHER, {{0,0,0}}},
+ {{"aes_128_gcm"}, {NULL}, 16, AEAD_CIPHER, {{0,0,0}}},
+ {{"aes_192_gcm"}, {NULL}, 24, AEAD_CIPHER, {{0,0,0}}},
+ {{"aes_256_gcm"}, {NULL}, 32, AEAD_CIPHER, {{0,0,0}}},
+#endif
+
+#if defined(HAVE_CCM)
+ {{"aes_ccm"}, {&EVP_aes_128_ccm}, 16, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_ccm"}, {&EVP_aes_192_ccm}, 24, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_ccm"}, {&EVP_aes_256_ccm}, 32, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_128_ccm"}, {&EVP_aes_128_ccm}, 16, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_192_ccm"}, {&EVP_aes_192_ccm}, 24, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
+ {{"aes_256_ccm"}, {&EVP_aes_256_ccm}, 32, AEAD_CIPHER, {{EVP_CTRL_CCM_SET_IVLEN,EVP_CTRL_CCM_GET_TAG,EVP_CTRL_CCM_SET_TAG}}},
#else
- {NULL}
+ {{"aes_ccm"}, {NULL}, 0, AEAD_CIPHER, {{0,0,0}}},
+ {{"aes_128_ccm"}, {NULL}, 16, AEAD_CIPHER, {{0,0,0}}},
+ {{"aes_192_ccm"}, {NULL}, 24, AEAD_CIPHER, {{0,0,0}}},
+ {{"aes_256_ccm"}, {NULL}, 32, AEAD_CIPHER, {{0,0,0}}},
+#endif
+
+ /*==== Specialy handled ciphers, only for inclusion in algorithm's list ====*/
+#ifdef HAVE_AES_IGE
+ {{"aes_ige256"}, {NULL}, 0, NO_FIPS_CIPHER | NON_EVP_CIPHER},
#endif
- ,0},
- {{"blowfish_cbc"}, {&EVP_bf_cbc}, 0},
- {{"blowfish_cfb64"}, {&EVP_bf_cfb64}, 0},
- {{"blowfish_ofb64"}, {&EVP_bf_ofb}, 0},
- {{"blowfish_ecb"}, {&EVP_bf_ecb}, 0},
- {{"aes_cbc"}, {&EVP_aes_128_cbc}, 16},
- {{"aes_cbc"}, {&EVP_aes_192_cbc}, 24},
- {{"aes_cbc"}, {&EVP_aes_256_cbc}, 32},
- {{"aes_cbc128"}, {&EVP_aes_128_cbc}, 0},
- {{"aes_cbc256"}, {&EVP_aes_256_cbc}, 0},
- {{"aes_cfb8"}, {&EVP_aes_128_cfb8}, 0},
- {{"aes_cfb128"}, {&EVP_aes_128_cfb128}, 0},
- {{"aes_ecb"}, {&EVP_aes_128_ecb}, 16},
- {{"aes_ecb"}, {&EVP_aes_192_ecb}, 24},
- {{"aes_ecb"}, {&EVP_aes_256_ecb}, 32},
- {{NULL},{NULL},0}
+
+ /*==== End of list ==== */
+
+ {{NULL},{NULL},0,0}
};
-#ifdef HAVE_EVP_AES_CTR
ErlNifResourceType* evp_cipher_ctx_rtype;
+static size_t num_cipher_types = 0;
+
static void evp_cipher_ctx_dtor(ErlNifEnv* env, struct evp_cipher_ctx* ctx) {
if (ctx == NULL)
return;
@@ -80,46 +151,79 @@ static void evp_cipher_ctx_dtor(ErlNifEnv* env, struct evp_cipher_ctx* ctx) {
if (ctx->ctx)
EVP_CIPHER_CTX_free(ctx->ctx);
}
-#endif
int init_cipher_ctx(ErlNifEnv *env) {
-#ifdef HAVE_EVP_AES_CTR
evp_cipher_ctx_rtype = enif_open_resource_type(env, NULL, "EVP_CIPHER_CTX",
(ErlNifResourceDtor*) evp_cipher_ctx_dtor,
ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
NULL);
if (evp_cipher_ctx_rtype == NULL)
goto err;
-#endif
return 1;
-#ifdef HAVE_EVP_AES_CTR
err:
PRINTF_ERR0("CRYPTO: Could not open resource type 'EVP_CIPHER_CTX'");
return 0;
-#endif
}
void init_cipher_types(ErlNifEnv* env)
{
struct cipher_type_t* p = cipher_types;
+ num_cipher_types = 0;
for (p = cipher_types; p->type.str; p++) {
+ num_cipher_types++;
p->type.atom = enif_make_atom(env, p->type.str);
if (p->cipher.funcp)
p->cipher.p = p->cipher.funcp();
}
p->type.atom = atom_false; /* end marker */
+
+ qsort(cipher_types, num_cipher_types, sizeof(cipher_types[0]), cmp_cipher_types);
}
-struct cipher_type_t* get_cipher_type(ERL_NIF_TERM type, size_t key_len)
+const struct cipher_type_t* get_cipher_type(ERL_NIF_TERM type, size_t key_len)
{
- struct cipher_type_t* p = NULL;
- for (p = cipher_types; p->type.atom != atom_false; p++) {
- if (type == p->type.atom && (!p->key_len || key_len == p->key_len)) {
- return p;
- }
+ struct cipher_type_t key;
+
+ key.type.atom = type;
+ key.key_len = key_len;
+
+ return bsearch(&key, cipher_types, num_cipher_types, sizeof(cipher_types[0]), cmp_cipher_types);
+}
+
+
+int cmp_cipher_types(const void *keyp, const void *elemp) {
+ const struct cipher_type_t *key = keyp;
+ const struct cipher_type_t *elem = elemp;
+
+ if (key->type.atom < elem->type.atom) return -1;
+ else if (key->type.atom > elem->type.atom) return 1;
+ else /* key->type.atom == elem->type.atom */
+ if (!elem->key_len || key->key_len == elem->key_len) return 0;
+ else if (key->key_len < elem->key_len) return -1;
+ else return 1;
+}
+
+
+ERL_NIF_TERM cipher_types_as_list(ErlNifEnv* env)
+{
+ struct cipher_type_t* p;
+ ERL_NIF_TERM prev, hd;
+
+ hd = enif_make_list(env, 0);
+ prev = atom_undefined;
+
+ for (p = cipher_types; (p->type.atom & (p->type.atom != atom_false)); p++) {
+ if ((prev != p->type.atom) &&
+ ((p->cipher.p != NULL) ||
+ (p->flags & (NON_EVP_CIPHER|AES_CTR_COMPAT)) ) && /* Special handling. Bad indeed... */
+ ! FORBIDDEN_IN_FIPS(p)
+ )
+ hd = enif_make_list_cell(env, p->type.atom, hd);
+ prev = p->type.atom;
}
- return NULL;
+
+ return hd;
}