diff options
Diffstat (limited to 'lib/crypto/c_src/crypto.c')
| -rw-r--r-- | lib/crypto/c_src/crypto.c | 2779 | 
1 files changed, 966 insertions, 1813 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 4966701e41..d1f620d892 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -91,6 +91,7 @@  #endif  #if OPENSSL_VERSION_NUMBER >= 0x1000100fL +# define HAVE_EVP_AES_CTR  # define HAVE_GCM  #endif @@ -98,6 +99,10 @@  # define HAVE_CHACHA20_POLY1305  #endif +#if OPENSSL_VERSION_NUMBER <= 0x009080cfL +# define HAVE_ECB_IVEC_BUG +#endif +  #if defined(HAVE_EC)  #include <openssl/ec.h>  #include <openssl/ecdh.h> @@ -193,57 +198,20 @@ static void unload(ErlNifEnv* env, void* priv_data);  /* The NIFs: */  static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM md5(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM md5_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM md5_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM md5_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM ripemd160(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM ripemd160_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM ripemd160_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM ripemd160_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha224_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha224_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha224_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha224_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha256_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha256_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha256_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha256_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha384_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha384_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha384_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha384_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha512_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha512_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha512_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha512_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM md4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM md4_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha224_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha384_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM hmac_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM des_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM des_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM des_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM des_ede3_cfb_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM hash_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM hash_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM hash_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM hmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM block_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM aes_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM rand_bytes_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -252,13 +220,10 @@ static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER  static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -270,10 +235,6 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T  static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -291,32 +252,7 @@ static ERL_NIF_TERM chacha20_poly1305_decrypt(ErlNifEnv* env, int argc, const ER  /* helpers */  static void init_algorithms_types(ErlNifEnv*);  static void init_digest_types(ErlNifEnv* env); -static void hmac_md5(unsigned char *key, int klen, -		     unsigned char *dbuf, int dlen,  -		     unsigned char *hmacbuf); -static void hmac_sha1(unsigned char *key, int klen, -		      unsigned char *dbuf, int dlen,  -		      unsigned char *hmacbuf); -#ifdef HAVE_SHA224 -static void hmac_sha224(unsigned char *key, int klen, -			unsigned char *dbuf, int dlen, -			unsigned char *hmacbuf); -#endif -#ifdef HAVE_SHA256 -static void hmac_sha256(unsigned char *key, int klen, -			unsigned char *dbuf, int dlen, -			unsigned char *hmacbuf); -#endif -#ifdef HAVE_SHA384 -static void hmac_sha384(unsigned char *key, int klen, -			unsigned char *dbuf, int dlen, -			unsigned char *hmacbuf); -#endif -#ifdef HAVE_SHA512 -static void hmac_sha512(unsigned char *key, int klen, -			unsigned char *dbuf, int dlen, -			unsigned char *hmacbuf); -#endif +static void init_cipher_types(ErlNifEnv* env);  #ifdef HAVE_EC  static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg);  static int term2point(ErlNifEnv* env, ERL_NIF_TERM term, @@ -328,60 +264,25 @@ static int library_refc = 0; /* number of users of this dynamic library */  static ErlNifFunc nif_funcs[] = {      {"info_lib", 0, info_lib},      {"algorithms", 0, algorithms}, -    {"md5", 1, md5}, -    {"md5_init", 0, md5_init}, -    {"md5_update", 2, md5_update}, -    {"md5_final", 1, md5_final}, -    {"ripemd160", 1, ripemd160}, -    {"ripemd160_init", 0, ripemd160_init}, -    {"ripemd160_update", 2, ripemd160_update}, -    {"ripemd160_final", 1, ripemd160_final}, -    {"sha", 1, sha}, -    {"sha_init", 0, sha_init}, -    {"sha_update", 2, sha_update}, -    {"sha_final", 1, sha_final}, -    {"sha224_nif", 1, sha224_nif}, -    {"sha224_init_nif", 0, sha224_init_nif}, -    {"sha224_update_nif", 2, sha224_update_nif}, -    {"sha224_final_nif", 1, sha224_final_nif}, -    {"sha256_nif", 1, sha256_nif}, -    {"sha256_init_nif", 0, sha256_init_nif}, -    {"sha256_update_nif", 2, sha256_update_nif}, -    {"sha256_final_nif", 1, sha256_final_nif}, -    {"sha384_nif", 1, sha384_nif}, -    {"sha384_init_nif", 0, sha384_init_nif}, -    {"sha384_update_nif", 2, sha384_update_nif}, -    {"sha384_final_nif", 1, sha384_final_nif}, -    {"sha512_nif", 1, sha512_nif}, -    {"sha512_init_nif", 0, sha512_init_nif}, -    {"sha512_update_nif", 2, sha512_update_nif}, -    {"sha512_final_nif", 1, sha512_final_nif}, -    {"md4", 1, md4}, -    {"md4_init", 0, md4_init}, -    {"md4_update", 2, md4_update}, -    {"md4_final", 1, md4_final}, -    {"md5_mac_n", 3, md5_mac_n}, -    {"sha_mac_n", 3, sha_mac_n}, -    {"sha224_mac_nif", 3, sha224_mac_nif}, -    {"sha256_mac_nif", 3, sha256_mac_nif}, -    {"sha384_mac_nif", 3, sha384_mac_nif}, -    {"sha512_mac_nif", 3, sha512_mac_nif}, -    {"hmac_init", 2, hmac_init}, -    {"hmac_update", 2, hmac_update}, -    {"hmac_final", 1, hmac_final}, -    {"hmac_final_n", 2, hmac_final}, -    {"des_cbc_crypt", 4, des_cbc_crypt}, -    {"des_cfb_crypt", 4, des_cfb_crypt}, -    {"des_ecb_crypt", 3, des_ecb_crypt}, -    {"des_ede3_cbc_crypt", 6, des_ede3_cbc_crypt}, -    {"des_ede3_cfb_crypt_nif", 6, des_ede3_cfb_crypt_nif}, -    {"aes_cfb_8_crypt", 4, aes_cfb_8_crypt}, -    {"aes_cfb_128_crypt", 4, aes_cfb_128_crypt}, +    {"hash_nif", 2, hash_nif}, +    {"hash_init_nif", 1, hash_init_nif}, +    {"hash_update_nif", 2, hash_update_nif}, +    {"hash_final_nif", 1, hash_final_nif}, +    {"hmac_nif", 3, hmac_nif}, +    {"hmac_nif", 4, hmac_nif}, +    {"hmac_init_nif", 2, hmac_init_nif}, +    {"hmac_update_nif", 2, hmac_update_nif}, +    {"hmac_final_nif", 1, hmac_final_nif}, +    {"hmac_final_nif", 2, hmac_final_nif}, +    {"block_crypt_nif", 5, block_crypt_nif}, +    {"block_crypt_nif", 4, block_crypt_nif}, +    {"aes_ige_crypt_nif", 4, aes_ige_crypt_nif}, +      {"aes_ctr_encrypt", 3, aes_ctr_encrypt},      {"aes_ctr_decrypt", 3, aes_ctr_encrypt}, +    {"aes_ctr_stream_init", 2, aes_ctr_stream_init},      {"aes_ctr_stream_encrypt", 2, aes_ctr_stream_encrypt},      {"aes_ctr_stream_decrypt", 2, aes_ctr_stream_encrypt}, -    {"aes_ecb_crypt", 3, aes_ecb_crypt},      {"rand_bytes", 1, rand_bytes_1},      {"strong_rand_bytes_nif", 1, strong_rand_bytes_nif},      {"rand_bytes", 3, rand_bytes_3}, @@ -390,13 +291,10 @@ static ErlNifFunc nif_funcs[] = {      {"mod_exp_nif", 4, mod_exp_nif},      {"dss_verify_nif", 4, dss_verify_nif},      {"rsa_verify_nif", 4, rsa_verify_nif}, -    {"aes_cbc_crypt", 4, aes_cbc_crypt}, -    {"aes_ige_crypt_nif", 4, aes_ige_crypt_nif},      {"do_exor", 2, do_exor},      {"rc4_encrypt", 2, rc4_encrypt},      {"rc4_set_key", 1, rc4_set_key},      {"rc4_encrypt_with_state", 2, rc4_encrypt_with_state}, -    {"rc2_cbc_crypt", 4, rc2_cbc_crypt},      {"rsa_sign_nif", 3, rsa_sign_nif},      {"dss_sign_nif", 3, dss_sign_nif},      {"rsa_public_crypt", 4, rsa_public_crypt}, @@ -408,10 +306,6 @@ static ErlNifFunc nif_funcs[] = {      {"srp_value_B_nif", 5, srp_value_B_nif},      {"srp_user_secret_nif", 7, srp_user_secret_nif},      {"srp_host_secret_nif", 5, srp_host_secret_nif}, -    {"bf_cfb64_crypt", 4, bf_cfb64_crypt}, -    {"bf_cbc_crypt", 4, bf_cbc_crypt}, -    {"bf_ecb_crypt", 3, bf_ecb_crypt}, -    {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt},      {"ec_key_generate", 2, ec_key_generate},      {"ecdsa_sign_nif", 4, ecdsa_sign_nif}, @@ -432,37 +326,14 @@ static ErlNifFunc nif_funcs[] = {  ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload) -#define MD5_CTX_LEN     (sizeof(MD5_CTX)) -#define MD5_LEN         16 -#define MD5_LEN_96      12 -#define MD4_CTX_LEN     (sizeof(MD4_CTX)) -#define MD4_LEN         16 +#define MD5_CTX_LEN       (sizeof(MD5_CTX)) +#define MD4_CTX_LEN       (sizeof(MD4_CTX))  #define RIPEMD160_CTX_LEN (sizeof(RIPEMD160_CTX)) -#define RIPEMD160_LEN   20 -#define SHA_CTX_LEN     (sizeof(SHA_CTX)) -#define SHA_LEN         20 -#define SHA_LEN_96      12 -#define SHA224_LEN	(224/8) -#define SHA256_LEN	(256/8) -#define SHA384_LEN	(384/8) -#define SHA512_LEN	(512/8) -#define HMAC_INT_LEN    64 -#define HMAC_INT2_LEN   128 - -#define HMAC_IPAD       0x36 -#define HMAC_OPAD       0x5c  static ERL_NIF_TERM atom_true;  static ERL_NIF_TERM atom_false;  static ERL_NIF_TERM atom_sha; -static ERL_NIF_TERM atom_sha224; -static ERL_NIF_TERM atom_sha256; -static ERL_NIF_TERM atom_sha384; -static ERL_NIF_TERM atom_sha512; -static ERL_NIF_TERM atom_md5; -static ERL_NIF_TERM atom_md4; -static ERL_NIF_TERM atom_ripemd160;  static ERL_NIF_TERM atom_error;  static ERL_NIF_TERM atom_rsa_pkcs1_padding;  static ERL_NIF_TERM atom_rsa_pkcs1_oaep_padding; @@ -489,6 +360,14 @@ static ERL_NIF_TERM atom_ppbasis;  static ERL_NIF_TERM atom_onbasis;  #endif +static ERL_NIF_TERM atom_aes_cfb8; +static ERL_NIF_TERM atom_aes_cfb128; +#ifdef HAVE_ECB_IVEC_BUG +static ERL_NIF_TERM atom_aes_ecb; +static ERL_NIF_TERM atom_des_ecb; +static ERL_NIF_TERM atom_blowfish_ecb; +#endif +  static ErlNifResourceType* hmac_context_rtype;  struct hmac_context  { @@ -498,6 +377,91 @@ struct hmac_context  };  static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context*); +struct digest_type_t { +    const char* type_str; +    const EVP_MD* (*md_func)(void); /* NULL if notsup */ +    ERL_NIF_TERM type_atom; +}; + +struct digest_type_t digest_types[] = +{ +    {"md4", &EVP_md4}, +    {"md5", &EVP_md5}, +    {"ripemd160", &EVP_ripemd160}, +    {"sha", &EVP_sha1}, +    {"sha224", +#ifdef HAVE_SHA224 +     &EVP_sha224 +#else +     NULL +#endif +    }, +    {"sha256", +#ifdef HAVE_SHA256 +     &EVP_sha256 +#else +     NULL +#endif +    }, +    {"sha384", +#ifdef HAVE_SHA384 +     &EVP_sha384 +#else +     NULL +#endif +    }, +    {"sha512", +#ifdef HAVE_SHA512 +     &EVP_sha512 +#else +     NULL +#endif +    }, +    {NULL} +}; + +static struct digest_type_t* get_digest_type(ERL_NIF_TERM type); + +struct cipher_type_t { +    const char* type_str; +    const EVP_CIPHER* (*cipher_func)(void); /* NULL if notsup */ +    const size_t key_len;      /* != 0 to also match on key_len */ +    ERL_NIF_TERM type_atom; +}; + +struct cipher_type_t cipher_types[] = +{ +    {"rc2_cbc", &EVP_rc2_cbc}, +    {"des_cbc", &EVP_des_cbc}, +    {"des_cfb", &EVP_des_cfb8}, +    {"des_ecb", &EVP_des_ecb}, +    {"des_ede3_cbc", &EVP_des_ede3_cbc}, +    {"des_ede3_cbf", +#ifdef HAVE_DES_ede3_cfb_encrypt +     &EVP_des_ede3_cfb8 +#else +     NULL +#endif +    }, +    {"blowfish_cbc", &EVP_bf_cbc}, +    {"blowfish_cfb64", &EVP_bf_cfb64}, +    {"blowfish_ofb64", &EVP_bf_ofb}, +    {"blowfish_ecb", &EVP_bf_ecb}, +    {"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}, +    {"aes_cbc256", &EVP_aes_256_cbc}, +    {"aes_cfb8", &EVP_aes_128_cfb8}, +    {"aes_cfb128", &EVP_aes_128_cfb128}, +    {"aes_ecb", &EVP_aes_128_ecb, 16}, +    {"aes_ecb", &EVP_aes_192_ecb, 24}, +    {"aes_ecb", &EVP_aes_256_ecb, 32}, +    {NULL} +}; + +static struct cipher_type_t* get_cipher_type(ERL_NIF_TERM type, size_t key_len); +  /*  #define PRINTF_ERR0(FMT) enif_fprintf(stderr, FMT "\n")  #define PRINTF_ERR1(FMT, A1) enif_fprintf(stderr, FMT "\n", A1) @@ -507,47 +471,21 @@ static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context*);  #define PRINTF_ERR1(FMT,A1)  #define PRINTF_ERR2(FMT,A1,A2) -#ifdef __OSE__ - -/* For crypto on OSE we have to initialize the crypto library on each -   process that uses it. So since we do not know which scheduler is going -   to execute the nif we have to check before each nif call that we have -   initialized crypto in that process. */ - -#include "ose.h" -#include "openssl/osessl.h" - -static ErlNifTSDKey crypto_init_key; -static int check_ose_crypto(void); -static int init_ose_crypto(void); - -static int check_ose_crypto() { -    int key = (int)enif_tsd_get(crypto_init_key); -    if (!key) { -	if (!CRYPTO_OSE5_init()) { -	    PRINTF_ERR0("CRYPTO: Call to CRYPTO_OSE5_init failed"); -	    return 0; -	} -	enif_tsd_set(crypto_init_key,1); -    } -    return 1; +#if OPENSSL_VERSION_NUMBER >= 0x1000000fL +/* Define resource types for OpenSSL context structures. */ +static ErlNifResourceType* evp_md_ctx_rtype; +static void evp_md_ctx_dtor(ErlNifEnv* env, EVP_MD_CTX* ctx) { +    EVP_MD_CTX_cleanup(ctx);  } +#endif -static int init_ose_crypto() { -    /* Crypto nif upgrade does not work on OSE so no need to -       destroy this key */ -    enif_tsd_key_create("crypto_init_key", &crypto_init_key); -    return check_ose_crypto(); +#ifdef HAVE_EVP_AES_CTR +static ErlNifResourceType* evp_cipher_ctx_rtype; +static void evp_cipher_ctx_dtor(ErlNifEnv* env, EVP_CIPHER_CTX* ctx) { +    EVP_CIPHER_CTX_cleanup(ctx);  } - -#define INIT_OSE_CRYPTO() init_ose_crypto() -#define CHECK_OSE_CRYPTO() check_ose_crypto() -#else -#define INIT_OSE_CRYPTO() 1 -#define CHECK_OSE_CRYPTO()  #endif -  static int verify_lib_version(void)  {      const unsigned long libv = SSLeay(); @@ -563,7 +501,6 @@ static int verify_lib_version(void)      return 1;  } -  #ifdef HAVE_DYNAMIC_CRYPTO_LIB  # if defined(DEBUG) @@ -599,7 +536,9 @@ static void error_handler(void* null, const char* errstr)  static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)  { +#ifdef OPENSSL_THREADS      ErlNifSysInfo sys_info; +#endif      get_crypto_callbacks_t* funcp;      struct crypto_callbacks* ccb;      int nlocks = 0; @@ -609,9 +548,6 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)      ErlNifBinary lib_bin;      char lib_buf[1000]; -    if (!INIT_OSE_CRYPTO()) -      return 0; -      if (!verify_lib_version())  	return 0; @@ -634,7 +570,26 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)  	PRINTF_ERR0("CRYPTO: Could not open resource type 'hmac_context'");  	return 0;      } - +#if OPENSSL_VERSION_NUMBER >= 0x1000000fL +    evp_md_ctx_rtype = enif_open_resource_type(env, NULL, "EVP_MD_CTX", +                                               (ErlNifResourceDtor*) evp_md_ctx_dtor, +                                               ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, +                                               NULL); +    if (!evp_md_ctx_rtype) { +        PRINTF_ERR0("CRYPTO: Could not open resource type 'EVP_MD_CTX'"); +        return 0; +    } +#endif +#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) { +        PRINTF_ERR0("CRYPTO: Could not open resource type 'EVP_CIPHER_CTX'"); +        return 0; +    } +#endif      if (library_refc > 0) {  	/* Repeated loading of this library (module upgrade).  	 * Atoms and callbacks are already set, we are done. @@ -642,16 +597,9 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)  	return 1;      } -    atom_true = enif_make_atom(env,"true"); +    atom_true  = enif_make_atom(env,"true");      atom_false = enif_make_atom(env,"false");      atom_sha = enif_make_atom(env,"sha"); -    atom_sha224 = enif_make_atom(env,"sha224"); -    atom_sha256 = enif_make_atom(env,"sha256"); -    atom_sha384 = enif_make_atom(env,"sha384"); -    atom_sha512 = enif_make_atom(env,"sha512"); -    atom_md4 = enif_make_atom(env,"md4"); -    atom_md5 = enif_make_atom(env,"md5"); -    atom_ripemd160 = enif_make_atom(env,"ripemd160");      atom_error = enif_make_atom(env,"error");      atom_rsa_pkcs1_padding = enif_make_atom(env,"rsa_pkcs1_padding");      atom_rsa_pkcs1_oaep_padding = enif_make_atom(env,"rsa_pkcs1_oaep_padding"); @@ -676,8 +624,16 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)      atom_ppbasis = enif_make_atom(env,"ppbasis");      atom_onbasis = enif_make_atom(env,"onbasis");  #endif +    atom_aes_cfb8 = enif_make_atom(env, "aes_cfb8"); +    atom_aes_cfb128 = enif_make_atom(env, "aes_cfb128"); +#ifdef HAVE_ECB_IVEC_BUG +    atom_aes_ecb = enif_make_atom(env, "aes_ecb"); +    atom_des_ecb = enif_make_atom(env, "des_ecb"); +    atom_blowfish_ecb = enif_make_atom(env, "blowfish_ecb"); +#endif      init_digest_types(env); +    init_cipher_types(env);      init_algorithms_types(env);  #ifdef HAVE_DYNAMIC_CRYPTO_LIB @@ -762,46 +718,67 @@ static void unload(ErlNifEnv* env, void* priv_data)  static int algo_hash_cnt;  static ERL_NIF_TERM algo_hash[8];   /* increase when extending the list */  static int algo_pubkey_cnt; -static ERL_NIF_TERM algo_pubkey[3]; /* increase when extending the list */ +static ERL_NIF_TERM algo_pubkey[7]; /* increase when extending the list */  static int algo_cipher_cnt; -static ERL_NIF_TERM algo_cipher[4]; /* increase when extending the list */ +static ERL_NIF_TERM algo_cipher[20]; /* increase when extending the list */  static void init_algorithms_types(ErlNifEnv* env)  {      algo_hash_cnt = 0; -    algo_hash[algo_hash_cnt++] = atom_md4; -    algo_hash[algo_hash_cnt++] = atom_md5;      algo_hash[algo_hash_cnt++] = atom_sha; -    algo_hash[algo_hash_cnt++] = atom_ripemd160;  #ifdef HAVE_SHA224 -    algo_hash[algo_hash_cnt++] = atom_sha224; +    algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha224");  #endif  #ifdef HAVE_SHA256 -    algo_hash[algo_hash_cnt++] = atom_sha256; +    algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha256");  #endif  #ifdef HAVE_SHA384 -    algo_hash[algo_hash_cnt++] = atom_sha384; +    algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha384");  #endif  #ifdef HAVE_SHA512 -    algo_hash[algo_hash_cnt++] = atom_sha512; +    algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha512");  #endif +    algo_hash[algo_hash_cnt++] = enif_make_atom(env, "md4"); +    algo_hash[algo_hash_cnt++] = enif_make_atom(env, "md5"); +    algo_hash[algo_hash_cnt++] = enif_make_atom(env, "ripemd160");      algo_pubkey_cnt = 0; +    algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "rsa"); +    algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "dss"); +    algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "dh");  #if defined(HAVE_EC)  #if !defined(OPENSSL_NO_EC2M) -    algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env,"ec_gf2m"); +    algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "ec_gf2m");  #endif -    algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env,"ecdsa"); -    algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env,"ecdh"); +    algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "ecdsa"); +    algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "ecdh");  #endif +    algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "srp");      algo_cipher_cnt = 0; +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des3_cbc"); +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des_ede3");  #ifdef HAVE_DES_ede3_cfb_encrypt      algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des3_cbf");  #endif +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cbc"); +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cbc128"); +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cfb8"); +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cfb128"); +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cbc256"); +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_ctr"); +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_ecb");  #ifdef HAVE_AES_IGE      algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"aes_ige256");  #endif +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"des_cbc"); +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"des_cfb"); +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_cbc"); +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_cfb64"); +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_ofb64"); +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_ecb"); +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"rc2_cbc"); +    algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"rc4");  #if defined(HAVE_GCM)      algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"aes_gcm");  #endif @@ -816,10 +793,13 @@ static void init_algorithms_types(ErlNifEnv* env)  static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])  { +    int hash_cnt   = algo_hash_cnt; +    int pubkey_cnt = algo_pubkey_cnt; +    int cipher_cnt = algo_cipher_cnt;      return enif_make_tuple3(env, -			    enif_make_list_from_array(env, algo_hash, algo_hash_cnt), -			    enif_make_list_from_array(env, algo_pubkey, algo_pubkey_cnt), -			    enif_make_list_from_array(env, algo_cipher, algo_cipher_cnt)); +			    enif_make_list_from_array(env, algo_hash,   hash_cnt), +			    enif_make_list_from_array(env, algo_pubkey, pubkey_cnt), +			    enif_make_list_from_array(env, algo_cipher, cipher_cnt));  }  static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -849,601 +829,383 @@ static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]  						 ver_term));  } -static ERL_NIF_TERM md5(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Data) */ -    ErlNifBinary ibin; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) { -	return enif_make_badarg(env); -    } -    MD5((unsigned char *) ibin.data, ibin.size, -	enif_make_new_binary(env,MD5_LEN, &ret)); -    CONSUME_REDS(env,ibin); -    return ret; -} -static ERL_NIF_TERM md5_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* () */    -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    MD5_Init((MD5_CTX *) enif_make_new_binary(env, MD5_CTX_LEN, &ret)); -    return ret; -} -static ERL_NIF_TERM md5_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context, Data) */ -    MD5_CTX* new_ctx; -    ErlNifBinary ctx_bin, data_bin; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) -	|| ctx_bin.size != MD5_CTX_LEN -	|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { +static ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Type, Data) */ +    struct digest_type_t *digp = NULL; +    const EVP_MD         *md; +    ErlNifBinary         data; +    ERL_NIF_TERM         ret; +    unsigned             ret_size; + +    digp = get_digest_type(argv[0]); +    if (!digp || +        !enif_inspect_iolist_as_binary(env, argv[1], &data)) {  	return enif_make_badarg(env);      } -    new_ctx = (MD5_CTX*) enif_make_new_binary(env,MD5_CTX_LEN, &ret); -    memcpy(new_ctx, ctx_bin.data, MD5_CTX_LEN); -    MD5_Update(new_ctx, data_bin.data, data_bin.size); -    CONSUME_REDS(env,data_bin); -    return ret; -} -static ERL_NIF_TERM md5_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context) */ -    ErlNifBinary ctx_bin; -    MD5_CTX ctx_clone;  -    ERL_NIF_TERM ret;     -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != MD5_CTX_LEN) { -	return enif_make_badarg(env); +    if (!digp->md_func) { +	return atom_notsup;      } -    memcpy(&ctx_clone, ctx_bin.data, MD5_CTX_LEN); /* writable */ -    MD5_Final(enif_make_new_binary(env, MD5_LEN, &ret), &ctx_clone); -    return ret; -} -static ERL_NIF_TERM ripemd160(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Data) */ -    ErlNifBinary ibin; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) { -	return enif_make_badarg(env); +    md = digp->md_func(); +    ret_size = (unsigned)EVP_MD_size(md); +    ASSERT(0 < ret_size && ret_size <= EVP_MAX_MD_SIZE); +    if (!EVP_Digest(data.data, data.size, +                    enif_make_new_binary(env, ret_size, &ret), &ret_size, +                    md, NULL)) { +        return atom_notsup;      } -    RIPEMD160((unsigned char *) ibin.data, ibin.size, -	      enif_make_new_binary(env,RIPEMD160_LEN, &ret)); -    CONSUME_REDS(env,ibin); -    return ret; -} -static ERL_NIF_TERM ripemd160_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* () */ -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    RIPEMD160_Init((RIPEMD160_CTX *) enif_make_new_binary(env, RIPEMD160_CTX_LEN, &ret)); +    ASSERT(ret_size == (unsigned)EVP_MD_size(md)); + +    CONSUME_REDS(env, data);      return ret;  } -static ERL_NIF_TERM ripemd160_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context, Data) */ -    RIPEMD160_CTX* new_ctx; -    ErlNifBinary ctx_bin, data_bin; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) -	|| ctx_bin.size != RIPEMD160_CTX_LEN -	|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { + +#if OPENSSL_VERSION_NUMBER >= 0x1000000fL + +static ERL_NIF_TERM hash_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Type) */ +    struct digest_type_t *digp = NULL; +    EVP_MD_CTX           *ctx; +    ERL_NIF_TERM         ret; + +    digp = get_digest_type(argv[0]); +    if (!digp) {  	return enif_make_badarg(env);      } -    new_ctx = (RIPEMD160_CTX*) enif_make_new_binary(env,RIPEMD160_CTX_LEN, &ret); -    memcpy(new_ctx, ctx_bin.data, RIPEMD160_CTX_LEN); -    RIPEMD160_Update(new_ctx, data_bin.data, data_bin.size); -    CONSUME_REDS(env, data_bin); -    return ret; -} -static ERL_NIF_TERM ripemd160_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context) */ -    ErlNifBinary ctx_bin; -    RIPEMD160_CTX ctx_clone; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != RIPEMD160_CTX_LEN) { -	return enif_make_badarg(env); +    if (!digp->md_func) { +	return atom_notsup;      } -    memcpy(&ctx_clone, ctx_bin.data, RIPEMD160_CTX_LEN); /* writable */ -    RIPEMD160_Final(enif_make_new_binary(env, RIPEMD160_LEN, &ret), &ctx_clone); -    return ret; -} - -static ERL_NIF_TERM sha(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Data) */     -    ErlNifBinary ibin; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) { -	return enif_make_badarg(env); +    ctx = enif_alloc_resource(evp_md_ctx_rtype, sizeof(EVP_MD_CTX)); +    if (!EVP_DigestInit(ctx, digp->md_func())) { +        enif_release_resource(ctx); +        return atom_notsup;      } -    SHA1((unsigned char *) ibin.data, ibin.size, -	 enif_make_new_binary(env,SHA_LEN, &ret)); -    CONSUME_REDS(env,ibin); -    return ret; -} -static ERL_NIF_TERM sha_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* () */    -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    SHA1_Init((SHA_CTX *) enif_make_new_binary(env, SHA_CTX_LEN, &ret)); +    ret = enif_make_resource(env, ctx); +    enif_release_resource(ctx);      return ret;  } -static ERL_NIF_TERM sha_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM hash_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])  {/* (Context, Data) */ -    SHA_CTX* new_ctx; -    ErlNifBinary ctx_bin, data_bin; +    EVP_MD_CTX   *ctx, *new_ctx; +    ErlNifBinary data;      ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != SHA_CTX_LEN -	|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { -	return enif_make_badarg(env); + +    if (!enif_get_resource(env, argv[0], evp_md_ctx_rtype, (void**)&ctx) || +        !enif_inspect_iolist_as_binary(env, argv[1], &data)) { +        return enif_make_badarg(env);      } -    new_ctx = (SHA_CTX*) enif_make_new_binary(env,SHA_CTX_LEN, &ret); -    memcpy(new_ctx, ctx_bin.data, SHA_CTX_LEN); -    SHA1_Update(new_ctx, data_bin.data, data_bin.size); -    CONSUME_REDS(env,data_bin); + +    new_ctx = enif_alloc_resource(evp_md_ctx_rtype, sizeof(EVP_MD_CTX)); +    if (!EVP_MD_CTX_copy(new_ctx, ctx) || +        !EVP_DigestUpdate(new_ctx, data.data, data.size)) { +        enif_release_resource(new_ctx); +        return atom_notsup; +    } + +    ret = enif_make_resource(env, new_ctx); +    enif_release_resource(new_ctx); +    CONSUME_REDS(env, data);      return ret;  } -static ERL_NIF_TERM sha_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM hash_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])  {/* (Context) */ -    ErlNifBinary ctx_bin; -    SHA_CTX ctx_clone; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != SHA_CTX_LEN) { -	return enif_make_badarg(env); +    EVP_MD_CTX    *ctx, new_ctx; +    ERL_NIF_TERM  ret; +    unsigned      ret_size; + +    if (!enif_get_resource(env, argv[0], evp_md_ctx_rtype, (void**)&ctx)) { +        return enif_make_badarg(env);      } -    memcpy(&ctx_clone, ctx_bin.data, SHA_CTX_LEN); /* writable */ -    SHA1_Final(enif_make_new_binary(env, SHA_LEN, &ret), &ctx_clone);     -    return ret; -} -static ERL_NIF_TERM sha224_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Data) */ -#ifdef HAVE_SHA224 -    ErlNifBinary ibin; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) { -	return enif_make_badarg(env); +    ret_size = (unsigned)EVP_MD_CTX_size(ctx); +    ASSERT(0 < ret_size && ret_size <= EVP_MAX_MD_SIZE); + +    if (!EVP_MD_CTX_copy(&new_ctx, ctx) || +        !EVP_DigestFinal(&new_ctx, +                         enif_make_new_binary(env, ret_size, &ret), +                         &ret_size)) { +        return atom_notsup;      } -    SHA224((unsigned char *) ibin.data, ibin.size, -	 enif_make_new_binary(env,SHA224_LEN, &ret)); -    CONSUME_REDS(env,ibin); +    ASSERT(ret_size == (unsigned)EVP_MD_CTX_size(ctx)); +      return ret; -#else -    return atom_notsup; -#endif  } -static ERL_NIF_TERM sha224_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* () */ -#ifdef HAVE_SHA224 -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    SHA224_Init((SHA256_CTX *) enif_make_new_binary(env, sizeof(SHA256_CTX), &ret)); -    return ret; -#else -    return atom_notsup; -#endif -} -static ERL_NIF_TERM sha224_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context, Data) */ -#ifdef HAVE_SHA224 -    SHA256_CTX* new_ctx; -    ErlNifBinary ctx_bin, data_bin; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA256_CTX) -	|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { + +#else /* if OPENSSL_VERSION_NUMBER < 1.0 */ + +static ERL_NIF_TERM hash_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Type) */ +    typedef int (*init_fun)(unsigned char*); +    struct digest_type_t *digp = NULL; +    ERL_NIF_TERM         ctx; +    size_t               ctx_size = 0; +    init_fun             ctx_init = 0; + +    digp = get_digest_type(argv[0]); +    if (!digp) {  	return enif_make_badarg(env);      } -    new_ctx = (SHA256_CTX*) enif_make_new_binary(env,sizeof(SHA256_CTX), &ret); -    memcpy(new_ctx, ctx_bin.data, sizeof(SHA256_CTX)); -    SHA224_Update(new_ctx, data_bin.data, data_bin.size); -    CONSUME_REDS(env,data_bin); -    return ret; -#else -    return atom_notsup; -#endif -} -static ERL_NIF_TERM sha224_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context) */ -#ifdef HAVE_SHA224 -    ErlNifBinary ctx_bin; -    SHA256_CTX ctx_clone; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA256_CTX)) { -	return enif_make_badarg(env); +    if (!digp->md_func) { +	return atom_notsup;      } -    memcpy(&ctx_clone, ctx_bin.data, sizeof(SHA256_CTX)); /* writable */ -    SHA224_Final(enif_make_new_binary(env, SHA224_LEN, &ret), &ctx_clone); -    return ret; -#else -    return atom_notsup; -#endif -} -static ERL_NIF_TERM sha256_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Data) */ -#ifdef HAVE_SHA256 -    ErlNifBinary ibin; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) { -	return enif_make_badarg(env); -    } -    SHA256((unsigned char *) ibin.data, ibin.size, -	 enif_make_new_binary(env,SHA256_LEN, &ret)); -    CONSUME_REDS(env,ibin); -    return ret; -#else -    return atom_notsup; +    switch (EVP_MD_type(digp->md_func())) +    { +    case NID_md4: +        ctx_size = MD4_CTX_LEN; +        ctx_init = (init_fun)(&MD4_Init); +        break; +    case NID_md5: +        ctx_size = MD5_CTX_LEN; +        ctx_init = (init_fun)(&MD5_Init); +        break; +    case NID_ripemd160: +        ctx_size = RIPEMD160_CTX_LEN; +        ctx_init = (init_fun)(&RIPEMD160_Init); +        break; +    case NID_sha1: +        ctx_size = sizeof(SHA_CTX); +        ctx_init = (init_fun)(&SHA1_Init); +        break; +#ifdef HAVE_SHA224 +    case NID_sha224: +        ctx_size = sizeof(SHA256_CTX); +        ctx_init = (init_fun)(&SHA224_Init); +        break;  #endif -} -static ERL_NIF_TERM sha256_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* () */     #ifdef HAVE_SHA256 -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    SHA256_Init((SHA256_CTX *) enif_make_new_binary(env, sizeof(SHA256_CTX), &ret)); -    return ret; -#else -    return atom_notsup; +    case NID_sha256: +        ctx_size = sizeof(SHA256_CTX); +        ctx_init = (init_fun)(&SHA256_Init); +        break;  #endif -} -static ERL_NIF_TERM sha256_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context, Data) */ -#ifdef HAVE_SHA256 -    SHA256_CTX* new_ctx; -    ErlNifBinary ctx_bin, data_bin; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA256_CTX) -	|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { -	return enif_make_badarg(env); +#ifdef HAVE_SHA384 +    case NID_sha384: +        ctx_size = sizeof(SHA512_CTX); +        ctx_init = (init_fun)(&SHA384_Init); +        break; +#endif +#ifdef HAVE_SHA512 +    case NID_sha512: +        ctx_size = sizeof(SHA512_CTX); +        ctx_init = (init_fun)(&SHA512_Init); +        break; +#endif +    default: +        return atom_notsup; +    } +    ASSERT(ctx_size); +    ASSERT(ctx_init); + +    ctx_init(enif_make_new_binary(env, ctx_size, &ctx)); +    return enif_make_tuple2(env, argv[0], ctx); +} +static ERL_NIF_TERM hash_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* ({Type, Context}, Data) */ +    typedef int (*update_fun)(unsigned char*, const unsigned char*, size_t); +    ERL_NIF_TERM         new_ctx; +    ErlNifBinary         ctx, data; +    const ERL_NIF_TERM   *tuple; +    int                  arity; +    struct digest_type_t *digp = NULL; +    unsigned char        *ctx_buff; +    size_t               ctx_size   = 0; +    update_fun           ctx_update = 0; + +    if (!enif_get_tuple(env, argv[0], &arity, &tuple) || +        arity != 2 || +        !(digp = get_digest_type(tuple[0])) || +        !enif_inspect_binary(env, tuple[1], &ctx) || +        !enif_inspect_iolist_as_binary(env, argv[1], &data)) { +        return enif_make_badarg(env);      } -    new_ctx = (SHA256_CTX*) enif_make_new_binary(env,sizeof(SHA256_CTX), &ret); -    memcpy(new_ctx, ctx_bin.data, sizeof(SHA256_CTX)); -    SHA256_Update(new_ctx, data_bin.data, data_bin.size); -    CONSUME_REDS(env,data_bin); -    return ret; -#else -    return atom_notsup; +    if (!digp->md_func) { +	return atom_notsup; +    } + +    switch (EVP_MD_type(digp->md_func())) +    { +    case NID_md4: +        ctx_size   = MD4_CTX_LEN; +        ctx_update = (update_fun)(&MD4_Update); +        break; +    case NID_md5: +        ctx_size   = MD5_CTX_LEN; +        ctx_update = (update_fun)(&MD5_Update); +        break; +    case NID_ripemd160: +        ctx_size   = RIPEMD160_CTX_LEN; +        ctx_update = (update_fun)(&RIPEMD160_Update); +        break; +    case NID_sha1: +        ctx_size   = sizeof(SHA_CTX); +        ctx_update = (update_fun)(&SHA1_Update); +        break; +#ifdef HAVE_SHA224 +    case NID_sha224: +        ctx_size   = sizeof(SHA256_CTX); +        ctx_update = (update_fun)(&SHA224_Update); +        break;  #endif -} -static ERL_NIF_TERM sha256_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context) */  #ifdef HAVE_SHA256 -    ErlNifBinary ctx_bin; -    SHA256_CTX ctx_clone; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA256_CTX)) { -	return enif_make_badarg(env); -    } -    memcpy(&ctx_clone, ctx_bin.data, sizeof(SHA256_CTX)); /* writable */ -    SHA256_Final(enif_make_new_binary(env, SHA256_LEN, &ret), &ctx_clone);     -    return ret; -#else -    return atom_notsup; +    case NID_sha256: +        ctx_size   = sizeof(SHA256_CTX); +        ctx_update = (update_fun)(&SHA256_Update); +        break;  #endif -} - -static ERL_NIF_TERM sha384_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Data) */  #ifdef HAVE_SHA384 -    ErlNifBinary ibin; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) { -	return enif_make_badarg(env); -    } -    SHA384((unsigned char *) ibin.data, ibin.size, -	 enif_make_new_binary(env,SHA384_LEN, &ret)); -    CONSUME_REDS(env,ibin); -    return ret; -#else -    return atom_notsup; +    case NID_sha384: +        ctx_size   = sizeof(SHA512_CTX); +        ctx_update = (update_fun)(&SHA384_Update); +        break;  #endif -} -static ERL_NIF_TERM sha384_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* () */ -#ifdef HAVE_SHA384 -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    SHA384_Init((SHA512_CTX *) enif_make_new_binary(env, sizeof(SHA512_CTX), &ret)); -    return ret; -#else -    return atom_notsup; +#ifdef HAVE_SHA512 +    case NID_sha512: +        ctx_size   = sizeof(SHA512_CTX); +        ctx_update = (update_fun)(&SHA512_Update); +        break;  #endif -} -static ERL_NIF_TERM sha384_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context, Data) */ -#ifdef HAVE_SHA384 -    SHA512_CTX* new_ctx; -    ErlNifBinary ctx_bin, data_bin; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA512_CTX) -	|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { -	return enif_make_badarg(env); +    default: +        return atom_notsup;      } -    new_ctx = (SHA512_CTX*) enif_make_new_binary(env,sizeof(SHA512_CTX), &ret); -    memcpy(new_ctx, ctx_bin.data, sizeof(SHA512_CTX)); -    SHA384_Update(new_ctx, data_bin.data, data_bin.size); -    CONSUME_REDS(env,data_bin); -    return ret; -#else -    return atom_notsup; -#endif -} -static ERL_NIF_TERM sha384_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context) */ -#ifdef HAVE_SHA384 -    ErlNifBinary ctx_bin; -    SHA512_CTX ctx_clone; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA512_CTX)) { -	return enif_make_badarg(env); +    ASSERT(ctx_size); +    ASSERT(ctx_update); + +    if (ctx.size != ctx_size) { +        return enif_make_badarg(env);      } -    memcpy(&ctx_clone, ctx_bin.data, sizeof(SHA512_CTX)); /* writable */ -    SHA384_Final(enif_make_new_binary(env, SHA384_LEN, &ret), &ctx_clone); -    return ret; -#else -    return atom_notsup; -#endif -} -static ERL_NIF_TERM sha512_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Data) */ -#ifdef HAVE_SHA512 -    ErlNifBinary ibin; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) { -	return enif_make_badarg(env); +    ctx_buff = enif_make_new_binary(env, ctx_size, &new_ctx); +    memcpy(ctx_buff, ctx.data, ctx_size); +    ctx_update(ctx_buff, data.data, data.size); + +    CONSUME_REDS(env, data); +    return enif_make_tuple2(env, tuple[0], new_ctx); +} +static ERL_NIF_TERM hash_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* ({Type, Context}) */ +    typedef int (*final_fun)(unsigned char*, void*); +    ERL_NIF_TERM         ret; +    ErlNifBinary         ctx; +    const ERL_NIF_TERM   *tuple; +    int                  arity; +    struct digest_type_t *digp = NULL; +    const EVP_MD         *md; +    void                 *new_ctx; +    size_t               ctx_size  = 0; +    final_fun            ctx_final = 0; + +    if (!enif_get_tuple(env, argv[0], &arity, &tuple) || +        arity != 2 || +        !(digp = get_digest_type(tuple[0])) || +        !enif_inspect_binary(env, tuple[1], &ctx)) { +        return enif_make_badarg(env);      } -    SHA512((unsigned char *) ibin.data, ibin.size, -	 enif_make_new_binary(env,SHA512_LEN, &ret)); -    CONSUME_REDS(env,ibin); -    return ret; -#else -    return atom_notsup; +    if (!digp->md_func) { +	return atom_notsup; +    } + +    md = digp->md_func(); + +    switch (EVP_MD_type(md)) +    { +    case NID_md4: +        ctx_size  = MD4_CTX_LEN; +        ctx_final = (final_fun)(&MD4_Final); +        break; +    case NID_md5: +        ctx_size  = MD5_CTX_LEN; +        ctx_final = (final_fun)(&MD5_Final); +        break; +    case NID_ripemd160: +        ctx_size  = RIPEMD160_CTX_LEN; +        ctx_final = (final_fun)(&RIPEMD160_Final); +        break; +    case NID_sha1: +        ctx_size  = sizeof(SHA_CTX); +        ctx_final = (final_fun)(&SHA1_Final); +        break; +#ifdef HAVE_SHA224 +    case NID_sha224: +        ctx_size  = sizeof(SHA256_CTX); +        ctx_final = (final_fun)(&SHA224_Final); +        break;  #endif -} -static ERL_NIF_TERM sha512_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* () */    -#ifdef HAVE_SHA512 -    ERL_NIF_TERM ret; -    SHA512_Init((SHA512_CTX *) enif_make_new_binary(env, sizeof(SHA512_CTX), &ret)); -    return ret; -#else -    return atom_notsup; +#ifdef HAVE_SHA256 +    case NID_sha256: +        ctx_size  = sizeof(SHA256_CTX); +        ctx_final = (final_fun)(&SHA256_Final); +        break;  #endif -} -static ERL_NIF_TERM sha512_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context, Data) */ -#ifdef HAVE_SHA512 -    SHA512_CTX* new_ctx; -    ErlNifBinary ctx_bin, data_bin; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA512_CTX) -	|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { -	return enif_make_badarg(env); -    } -    new_ctx = (SHA512_CTX*) enif_make_new_binary(env,sizeof(SHA512_CTX), &ret); -    memcpy(new_ctx, ctx_bin.data, sizeof(SHA512_CTX)); -    SHA512_Update(new_ctx, data_bin.data, data_bin.size); -    CONSUME_REDS(env,data_bin); -    return ret; -#else -    return atom_notsup; +#ifdef HAVE_SHA384 +    case NID_sha384: +        ctx_size  = sizeof(SHA512_CTX); +        ctx_final = (final_fun)(&SHA384_Final); +        break;  #endif -} -static ERL_NIF_TERM sha512_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context) */  #ifdef HAVE_SHA512 -    ErlNifBinary ctx_bin; -    SHA512_CTX ctx_clone; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA512_CTX)) { -	return enif_make_badarg(env); -    } -    memcpy(&ctx_clone, ctx_bin.data, sizeof(SHA512_CTX)); /* writable */ -    SHA512_Final(enif_make_new_binary(env, SHA512_LEN, &ret), &ctx_clone);     -    return ret; -#else -    return atom_notsup; +    case NID_sha512: +        ctx_size  = sizeof(SHA512_CTX); +        ctx_final = (final_fun)(&SHA512_Final); +        break;  #endif -} - - -static ERL_NIF_TERM md4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Data) */     -    ErlNifBinary ibin; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) { -	return enif_make_badarg(env); +    default: +        return atom_notsup;      } -    MD4((unsigned char *) ibin.data, ibin.size, -	enif_make_new_binary(env,MD4_LEN, &ret)); -    CONSUME_REDS(env,ibin); -    return ret; -} -static ERL_NIF_TERM md4_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* () */    -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    MD4_Init((MD4_CTX *) enif_make_new_binary(env, MD4_CTX_LEN, &ret)); -    return ret; -} -static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context, Data) */ -    MD4_CTX* new_ctx; -    ErlNifBinary ctx_bin, data_bin; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != MD4_CTX_LEN -	|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { -	return enif_make_badarg(env); -    } -    new_ctx = (MD4_CTX*) enif_make_new_binary(env,MD4_CTX_LEN, &ret); -    memcpy(new_ctx, ctx_bin.data, MD4_CTX_LEN); -    MD4_Update(new_ctx, data_bin.data, data_bin.size); -    CONSUME_REDS(env,data_bin); -    return ret; -} -static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context) */ -    ErlNifBinary ctx_bin; -    MD4_CTX ctx_clone; -    ERL_NIF_TERM ret;     -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != MD4_CTX_LEN) { -	return enif_make_badarg(env); -    } -    memcpy(&ctx_clone, ctx_bin.data, MD4_CTX_LEN); /* writable */ -    MD4_Final(enif_make_new_binary(env, MD4_LEN, &ret), &ctx_clone);     -    return ret; -} +    ASSERT(ctx_size); +    ASSERT(ctx_final); -static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, Data, MacSize) */ -    unsigned char hmacbuf[SHA_DIGEST_LENGTH]; -    ErlNifBinary key, data; -    unsigned mac_sz; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key) -	|| !enif_inspect_iolist_as_binary(env, argv[1], &data) -	|| !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > MD5_LEN) { -	return enif_make_badarg(env); +    if (ctx.size != ctx_size) { +        return enif_make_badarg(env);      } -    hmac_md5(key.data, key.size, data.data, data.size, hmacbuf); -    memcpy(enif_make_new_binary(env, mac_sz, &ret), hmacbuf, mac_sz); -    CONSUME_REDS(env,data); -    return ret; -} -static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, Data, MacSize) */ -    unsigned char hmacbuf[SHA_DIGEST_LENGTH]; -    ErlNifBinary key, data; -    unsigned mac_sz; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key) -	|| !enif_inspect_iolist_as_binary(env, argv[1], &data) -	|| !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA_LEN) { -	return enif_make_badarg(env); -    } -    hmac_sha1(key.data, key.size, data.data, data.size, hmacbuf); -    memcpy(enif_make_new_binary(env, mac_sz, &ret), -	   hmacbuf, mac_sz); -    CONSUME_REDS(env,data); -    return ret; -} +    new_ctx = enif_alloc(ctx_size); +    memcpy(new_ctx, ctx.data, ctx_size); +    ctx_final(enif_make_new_binary(env, (size_t)EVP_MD_size(md), &ret), +              new_ctx); +    enif_free(new_ctx); -static ERL_NIF_TERM sha224_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, Data, MacSize) */ -#ifdef HAVE_SHA224 -    unsigned char hmacbuf[SHA224_DIGEST_LENGTH]; -    ErlNifBinary key, data; -    unsigned mac_sz; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key) -	|| !enif_inspect_iolist_as_binary(env, argv[1], &data) -	|| !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA224_DIGEST_LENGTH) { -	return enif_make_badarg(env); -    } -    hmac_sha224(key.data, key.size, data.data, data.size, hmacbuf); -    memcpy(enif_make_new_binary(env, mac_sz, &ret), -	   hmacbuf, mac_sz); -    CONSUME_REDS(env,data);      return ret; -#else -    return atom_notsup; -#endif  } +#endif  /* OPENSSL_VERSION_NUMBER < 1.0 */ -static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, Data, MacSize) */ -#ifdef HAVE_SHA256 -    unsigned char hmacbuf[SHA256_DIGEST_LENGTH]; -    ErlNifBinary key, data; -    unsigned mac_sz; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key) -	|| !enif_inspect_iolist_as_binary(env, argv[1], &data) -	|| !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA256_DIGEST_LENGTH) { -	return enif_make_badarg(env); -    } -    hmac_sha256(key.data, key.size, data.data, data.size, hmacbuf); -    memcpy(enif_make_new_binary(env, mac_sz, &ret), -	   hmacbuf, mac_sz); -    CONSUME_REDS(env,data); -    return ret; -#else -    return atom_notsup; -#endif -} +static ERL_NIF_TERM hmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Type, Key, Data) or (Type, Key, Data, MacSize) */ +    struct digest_type_t *digp = NULL; +    ErlNifBinary         key, data; +    unsigned char        buff[EVP_MAX_MD_SIZE]; +    unsigned             size = 0, req_size = 0; +    ERL_NIF_TERM         ret; -static ERL_NIF_TERM sha384_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, Data, MacSize) */ -#ifdef HAVE_SHA384 -    unsigned char hmacbuf[SHA384_DIGEST_LENGTH]; -    ErlNifBinary key, data; -    unsigned mac_sz; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key) -	|| !enif_inspect_iolist_as_binary(env, argv[1], &data) -	|| !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA384_DIGEST_LENGTH) { -	return enif_make_badarg(env); +    digp = get_digest_type(argv[0]); +    if (!digp || +        !enif_inspect_iolist_as_binary(env, argv[1], &key) || +        !enif_inspect_iolist_as_binary(env, argv[2], &data) || +        (argc == 4 && !enif_get_uint(env, argv[3], &req_size))) { +        return enif_make_badarg(env);      } -    hmac_sha384(key.data, key.size, data.data, data.size, hmacbuf); -    memcpy(enif_make_new_binary(env, mac_sz, &ret), -	   hmacbuf, mac_sz); -    CONSUME_REDS(env,data); -    return ret; -#else -    return atom_notsup; -#endif -} +    if (!digp->md_func || +        !HMAC(digp->md_func(), +              key.data, key.size, +              data.data, data.size, +              buff, &size)) { +        return atom_notsup; +    } +    ASSERT(0 < size && size <= EVP_MAX_MD_SIZE); +    CONSUME_REDS(env, data); -static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, Data, MacSize) */ -#ifdef HAVE_SHA512 -    unsigned char hmacbuf[SHA512_DIGEST_LENGTH]; -    ErlNifBinary key, data; -    unsigned mac_sz; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key) -	|| !enif_inspect_iolist_as_binary(env, argv[1], &data) -	|| !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA512_DIGEST_LENGTH) { -	return enif_make_badarg(env); +    if (argc == 4) { +        if (req_size <= size) { +            size = req_size; +        } +        else { +            return enif_make_badarg(env); +        }      } -    hmac_sha512(key.data, key.size, data.data, data.size, hmacbuf); -    memcpy(enif_make_new_binary(env, mac_sz, &ret), -	   hmacbuf, mac_sz); -    CONSUME_REDS(env,data); +    memcpy(enif_make_new_binary(env, size, &ret), buff, size);      return ret; -#else -    return atom_notsup; -#endif  }  static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context *obj) @@ -1455,55 +1217,46 @@ static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context *obj)      enif_mutex_destroy(obj->mtx);  } -static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])  {/* (Type, Key) */ -    ErlNifBinary key; -    struct hmac_context* obj; -    const EVP_MD *md; -    ERL_NIF_TERM ret; -     -    CHECK_OSE_CRYPTO(); +    struct digest_type_t *digp = NULL; +    ErlNifBinary         key; +    ERL_NIF_TERM         ret; +    struct hmac_context  *obj; -    if (argv[0] == atom_sha) md = EVP_sha1(); -#ifdef HAVE_SHA224 -    else if (argv[0] == atom_sha224) md = EVP_sha224(); -#endif -#ifdef HAVE_SHA256 -    else if (argv[0] == atom_sha256) md = EVP_sha256(); -#endif -#ifdef HAVE_SHA384 -    else if (argv[0] == atom_sha384) md = EVP_sha384(); -#endif -#ifdef HAVE_SHA512 -    else if (argv[0] == atom_sha512) md = EVP_sha512(); -#endif -    else if (argv[0] == atom_md5) md = EVP_md5(); -    else if (argv[0] == atom_ripemd160) md = EVP_ripemd160(); -    else goto badarg; -     -    if (!enif_inspect_iolist_as_binary(env, argv[1], &key)) { -    badarg: -	return enif_make_badarg(env); +    digp = get_digest_type(argv[0]); +    if (!digp || +        !enif_inspect_iolist_as_binary(env, argv[1], &key)) { +        return enif_make_badarg(env); +    } +    if (!digp->md_func) { +        return atom_notsup;      }      obj = enif_alloc_resource(hmac_context_rtype, sizeof(struct hmac_context));      obj->mtx = enif_mutex_create("crypto.hmac");      obj->alive = 1; -    HMAC_CTX_init(&obj->ctx); -    HMAC_Init(&obj->ctx, key.data, key.size, md); +#if OPENSSL_VERSION_NUMBER >= 0x1000000fL +    // Check the return value of HMAC_Init: it may fail in FIPS mode +    // for disabled algorithms +    if (!HMAC_Init(&obj->ctx, key.data, key.size, digp->md_func())) { +        enif_release_resource(obj); +        return atom_notsup; +    } +#else +    HMAC_Init(&obj->ctx, key.data, key.size, digp->md_func()); +#endif      ret = enif_make_resource(env, obj);      enif_release_resource(obj);      return ret;  } -static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])  {/* (Context, Data) */      ErlNifBinary data;      struct hmac_context* obj; -    CHECK_OSE_CRYPTO(); -      if (!enif_get_resource(env, argv[0], hmac_context_rtype, (void**)&obj)  	|| !enif_inspect_iolist_as_binary(env, argv[1], &data)) {  	return enif_make_badarg(env); @@ -1520,7 +1273,7 @@ static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg      return argv[0];  } -static ERL_NIF_TERM hmac_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])  {/* (Context) or (Context, HashLen) */      ERL_NIF_TERM ret;      struct hmac_context* obj; @@ -1529,8 +1282,6 @@ static ERL_NIF_TERM hmac_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv      unsigned int req_len = 0;      unsigned int mac_len; -    CHECK_OSE_CRYPTO(); -          if (!enif_get_resource(env,argv[0],hmac_context_rtype, (void**)&obj)  	|| (argc == 2 && !enif_get_uint(env, argv[1], &req_len))) {  	return enif_make_badarg(env); @@ -1557,206 +1308,197 @@ static ERL_NIF_TERM hmac_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv      return ret;  } -static ERL_NIF_TERM des_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, Ivec, Text, IsEncrypt) */     -    ErlNifBinary key, ivec, text; -    DES_key_schedule schedule; -    DES_cblock ivec_clone; /* writable copy */ -    ERL_NIF_TERM ret; - -    CHECK_OSE_CRYPTO(); +static ERL_NIF_TERM block_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Type, Key, Ivec, Text, IsEncrypt) or (Type, Key, Text, IsEncrypt) */ +    struct cipher_type_t *cipherp = NULL; +    const EVP_CIPHER     *cipher; +    ErlNifBinary         key, ivec, text; +    EVP_CIPHER_CTX       ctx; +    ERL_NIF_TERM         ret; +    unsigned char        *out; +    int                  ivec_size, out_size = 0; -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 8 -	|| !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 8 -	|| !enif_inspect_iolist_as_binary(env, argv[2], &text) -	|| text.size % 8 != 0) { -	return enif_make_badarg(env); +    if (!enif_inspect_iolist_as_binary(env, argv[1], &key) +        || !(cipherp = get_cipher_type(argv[0], key.size)) +        || !enif_inspect_iolist_as_binary(env, argv[argc - 2], &text)) { +        return enif_make_badarg(env);      } -    memcpy(&ivec_clone, ivec.data, 8); -    DES_set_key((const_DES_cblock*)key.data, &schedule); -    DES_ncbc_encrypt(text.data, enif_make_new_binary(env, text.size, &ret), -		     text.size, &schedule, &ivec_clone, (argv[3] == atom_true)); -    CONSUME_REDS(env,text); -    return ret; -} - -static ERL_NIF_TERM des_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, Ivec, Text, IsEncrypt) */ -    ErlNifBinary key, ivec, text; -    DES_key_schedule schedule; -    DES_cblock ivec_clone; /* writable copy */ -    ERL_NIF_TERM ret; - -    CHECK_OSE_CRYPTO(); - -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 8 -	|| !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 8 -	|| !enif_inspect_iolist_as_binary(env, argv[2], &text)) { -	return enif_make_badarg(env); +    if (!cipherp->cipher_func) { +        return enif_raise_exception(env, atom_notsup);      } -    memcpy(&ivec_clone, ivec.data, 8); -    DES_set_key((const_DES_cblock*)key.data, &schedule); -    DES_cfb_encrypt(text.data, enif_make_new_binary(env, text.size, &ret), -		     8, text.size, &schedule, &ivec_clone, (argv[3] == atom_true)); -    CONSUME_REDS(env,text); -    return ret; -} -static ERL_NIF_TERM des_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, Text/Cipher, IsEncrypt) */ -    ErlNifBinary key, text; -    DES_key_schedule schedule; -    ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 8 || -	!enif_inspect_iolist_as_binary(env, argv[1], &text) || text.size != 8) { -	return enif_make_badarg(env); +    if ((argv[0] == atom_aes_cfb8 || argv[0] == atom_aes_cfb128) +        && (key.size == 24 || key.size == 32)) { +        /* Why do EVP_CIPHER_CTX_set_key_length() fail on these key sizes? +         * Fall back on low level API +         */ +        return aes_cfb_8_crypt(env, argc-1, argv+1);      } -    DES_set_key((const_DES_cblock*)key.data, &schedule); -    DES_ecb_encrypt((const_DES_cblock*)text.data, -		    (DES_cblock*)enif_make_new_binary(env, 8, &ret), -		    &schedule, (argv[2] == atom_true)); -    CONSUME_REDS(env,text); -    return ret; -} -static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key1, Key2, Key3, IVec, Text/Cipher, IsEncrypt) */     -    ErlNifBinary key1, key2, key3, ivec, text; -    DES_key_schedule schedule1, schedule2, schedule3; -    DES_cblock ivec_clone; /* writable copy */ -    ERL_NIF_TERM ret; +    cipher = cipherp->cipher_func(); +    ivec_size  = EVP_CIPHER_iv_length(cipher); -    CHECK_OSE_CRYPTO(); +#ifdef HAVE_ECB_IVEC_BUG +    if (argv[0] == atom_aes_ecb || argv[0] == atom_blowfish_ecb || +	argv[0] == atom_des_ecb) +	ivec_size = 0; /* 0.9.8l returns faulty ivec_size */ +#endif -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key1) || key1.size != 8 -	|| !enif_inspect_iolist_as_binary(env, argv[1], &key2) || key2.size != 8 -	|| !enif_inspect_iolist_as_binary(env, argv[2], &key3) || key3.size != 8 -	|| !enif_inspect_binary(env, argv[3], &ivec) || ivec.size != 8 -	|| !enif_inspect_iolist_as_binary(env, argv[4], &text) -	|| text.size % 8 != 0) { -	return enif_make_badarg(env); +    if (text.size % EVP_CIPHER_block_size(cipher) != 0 || +        (ivec_size == 0 ? argc != 4 +                      : (argc != 5 || +                         !enif_inspect_iolist_as_binary(env, argv[2], &ivec) || +                         ivec.size != ivec_size))) { +        return enif_make_badarg(env);      } -    memcpy(&ivec_clone, ivec.data, 8); -    DES_set_key((const_DES_cblock*)key1.data, &schedule1); -    DES_set_key((const_DES_cblock*)key2.data, &schedule2); -    DES_set_key((const_DES_cblock*)key3.data, &schedule3); -    DES_ede3_cbc_encrypt(text.data, enif_make_new_binary(env,text.size,&ret),  -			 text.size, &schedule1, &schedule2, &schedule3, -			 &ivec_clone, (argv[5] == atom_true)); -    CONSUME_REDS(env,text); -    return ret; -} +    out = enif_make_new_binary(env, text.size, &ret); -static ERL_NIF_TERM des_ede3_cfb_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key1, Key2, Key3, IVec, Text/Cipher, IsEncrypt) */ -#ifdef HAVE_DES_ede3_cfb_encrypt -    ErlNifBinary key1, key2, key3, ivec, text; -    DES_key_schedule schedule1, schedule2, schedule3; -    DES_cblock ivec_clone; /* writable copy */ -    ERL_NIF_TERM ret; +    EVP_CIPHER_CTX_init(&ctx); +    if (!EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, NULL, +                           (argv[argc - 1] == atom_true)) || +        !EVP_CIPHER_CTX_set_key_length(&ctx, key.size) || +        !(EVP_CIPHER_type(cipher) != NID_rc2_cbc || +          EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_SET_RC2_KEY_BITS, key.size * 8, NULL)) || +        !EVP_CipherInit_ex(&ctx, NULL, NULL, +                           key.data, ivec_size ? ivec.data : NULL, -1) || +        !EVP_CIPHER_CTX_set_padding(&ctx, 0)) { -    CHECK_OSE_CRYPTO(); +        EVP_CIPHER_CTX_cleanup(&ctx); +        return enif_raise_exception(env, atom_notsup); +    } -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key1) || key1.size != 8 -	|| !enif_inspect_iolist_as_binary(env, argv[1], &key2) || key2.size != 8 -	|| !enif_inspect_iolist_as_binary(env, argv[2], &key3) || key3.size != 8 -	|| !enif_inspect_binary(env, argv[3], &ivec) || ivec.size != 8 -	|| !enif_inspect_iolist_as_binary(env, argv[4], &text)) { -	return enif_make_badarg(env); +    if (text.size > 0 && /* OpenSSL 0.9.8h asserts text.size > 0 */ +        (!EVP_CipherUpdate(&ctx, out, &out_size, text.data, text.size) +         || (ASSERT(out_size == text.size), 0) +         || !EVP_CipherFinal_ex(&ctx, out + out_size, &out_size))) { + +        EVP_CIPHER_CTX_cleanup(&ctx); +        return enif_raise_exception(env, atom_notsup);      } +    ASSERT(out_size == 0); +    EVP_CIPHER_CTX_cleanup(&ctx); +    CONSUME_REDS(env, text); -    memcpy(&ivec_clone, ivec.data, 8); -    DES_set_key((const_DES_cblock*)key1.data, &schedule1); -    DES_set_key((const_DES_cblock*)key2.data, &schedule2); -    DES_set_key((const_DES_cblock*)key3.data, &schedule3); -    DES_ede3_cfb_encrypt(text.data, enif_make_new_binary(env,text.size,&ret), -			 8, text.size, &schedule1, &schedule2, &schedule3, -			 &ivec_clone, (argv[5] == atom_true)); -    CONSUME_REDS(env,text);      return ret; -#else -    return atom_notsup; -#endif  }  static ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, IVec, Data, IsEncrypt) */     -    ErlNifBinary key, ivec, text; -    AES_KEY aes_key; -    unsigned char ivec_clone[16]; /* writable copy */ -    int new_ivlen = 0; -    ERL_NIF_TERM ret; - -    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); -    } - -    memcpy(ivec_clone, ivec.data, 16); -    AES_set_encrypt_key(key.data, key.size * 8, &aes_key); -    AES_cfb8_encrypt((unsigned char *) text.data, -		       enif_make_new_binary(env, text.size, &ret),  -		       text.size, &aes_key, ivec_clone, &new_ivlen, -		       (argv[3] == atom_true)); -    CONSUME_REDS(env,text); -    return ret; +{/* (Key, IVec, Data, IsEncrypt) */ +     ErlNifBinary key, ivec, text; +     AES_KEY aes_key; +     unsigned char ivec_clone[16]; /* writable copy */ +     int new_ivlen = 0; +     ERL_NIF_TERM ret; + +     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); +     } + +     memcpy(ivec_clone, ivec.data, 16); +     AES_set_encrypt_key(key.data, key.size * 8, &aes_key); +     AES_cfb8_encrypt((unsigned char *) text.data, +                      enif_make_new_binary(env, text.size, &ret), +                      text.size, &aes_key, ivec_clone, &new_ivlen, +                      (argv[3] == atom_true)); +     CONSUME_REDS(env,text); +     return ret;  } -static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, IVec, Data, IsEncrypt) */     -    ErlNifBinary key, ivec, text; +static ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Key, IVec, Data, IsEncrypt) */ +#ifdef HAVE_AES_IGE +    ErlNifBinary key_bin, ivec_bin, data_bin;      AES_KEY aes_key; -    unsigned char ivec_clone[16]; /* writable copy */ -    int new_ivlen = 0; +    unsigned char ivec[32]; +    int i; +    unsigned char* ret_ptr;      ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); +    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) { -    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); +       return enif_make_badarg(env);      } -    memcpy(ivec_clone, ivec.data, 16); -    AES_set_encrypt_key(key.data, key.size * 8, &aes_key); -    AES_cfb128_encrypt((unsigned char *) text.data, -		       enif_make_new_binary(env, text.size, &ret),  -		       text.size, &aes_key, ivec_clone, &new_ivlen, -		       (argv[3] == atom_true)); -    CONSUME_REDS(env,text); +    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); +    } + +    ret_ptr = enif_make_new_binary(env, data_bin.size, &ret); +    memcpy(ivec, ivec_bin.data, 32); /* writable copy */ +    AES_ige_encrypt(data_bin.data, ret_ptr, data_bin.size, &aes_key, ivec, i); +    CONSUME_REDS(env,data_bin);      return ret; +#else +    return atom_notsup; +#endif  }  /* Common for both encrypt and decrypt  */  static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])  {/* (Key, IVec, Data) */     -    ErlNifBinary key, ivec, text; -    AES_KEY aes_key; -    unsigned char ivec_clone[16]; /* writable copy */ -    unsigned char ecount_buf[AES_BLOCK_SIZE]; -    unsigned int num = 0; -    ERL_NIF_TERM ret; - -    CHECK_OSE_CRYPTO(); +    ErlNifBinary     key, ivec, text; +#ifdef HAVE_EVP_AES_CTR +    const EVP_CIPHER *cipher; +    EVP_CIPHER_CTX   ctx; +    unsigned char    *out; +    int              outl = 0; +#else +    AES_KEY          aes_key; +    unsigned char    ivec_clone[16]; /* writable copy */ +    unsigned char    ecount_buf[AES_BLOCK_SIZE]; +    unsigned int     num = 0; +#endif +    ERL_NIF_TERM     ret;      if (!enif_inspect_iolist_as_binary(env, argv[0], &key) +#ifndef HAVE_EVP_AES_CTR  	|| AES_set_encrypt_key(key.data, key.size*8, &aes_key) != 0 +#endif  	|| !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16  	|| !enif_inspect_iolist_as_binary(env, argv[2], &text)) {  	return enif_make_badarg(env);      } +#ifdef HAVE_EVP_AES_CTR +    switch (key.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); +    } + +    out = enif_make_new_binary(env,text.size,&ret); +    EVP_CIPHER_CTX_init(&ctx); +    EVP_CipherInit_ex(&ctx, cipher, NULL, +                      key.data, ivec.data, (argv[3] == atom_true)); +    EVP_CIPHER_CTX_set_padding(&ctx, 0); +    EVP_CipherUpdate(&ctx, out, &outl, text.data, text.size); +    ASSERT(outl == text.size); +    EVP_CipherFinal_ex(&ctx, out + outl, &outl); +    ASSERT(outl == 0); +    EVP_CIPHER_CTX_cleanup(&ctx); +#else      memcpy(ivec_clone, ivec.data, 16);          memset(ecount_buf, 0, sizeof(ecount_buf));      AES_ctr128_encrypt((unsigned char *) text.data,  		       enif_make_new_binary(env, text.size, &ret),   		       text.size, &aes_key, ivec_clone, ecount_buf, &num); +#endif      CONSUME_REDS(env,text);      /* To do an incremental {en|de}cryption, the state to to keep between calls @@ -1766,6 +1508,81 @@ static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM  /* Initializes state for ctr streaming (de)encryption  */ +#ifdef HAVE_EVP_AES_CTR +static ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Key, IVec) */ +    ErlNifBinary     key_bin, ivec_bin; +    EVP_CIPHER_CTX   *ctx; +    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); +    } + +    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); +    } + +    ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(EVP_CIPHER_CTX)); +    EVP_CIPHER_CTX_init(ctx); +    EVP_CipherInit_ex(ctx, cipher, NULL, +                      key_bin.data, ivec_bin.data, 1); +    EVP_CIPHER_CTX_set_padding(ctx, 0); +    ret = enif_make_resource(env, ctx); +    enif_release_resource(ctx); +    return ret; +} +static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Context, Data) */ +    EVP_CIPHER_CTX *ctx, *new_ctx; +    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(EVP_CIPHER_CTX)); +    EVP_CIPHER_CTX_init(new_ctx); +    EVP_CIPHER_CTX_copy(new_ctx, ctx); +    out = enif_make_new_binary(env, data_bin.size, &cipher_term); +    EVP_CipherUpdate(new_ctx, out, &outl, data_bin.data, data_bin.size); +    ASSERT(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); +    return ret; +} + +#else /* if not HAVE_EVP_AES_CTR */ + +static ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Key, IVec) */ +    ErlNifBinary key_bin, ivec_bin; +    ERL_NIF_TERM ecount_bin; + +    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); +    } + +    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)); +} +  static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])  {/* ({Key, IVec, ECount, Num}, Data) */          ErlNifBinary key_bin, ivec_bin, text_bin, ecount_bin; @@ -1777,8 +1594,6 @@ static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_N      unsigned char * ivec2_buf;      unsigned char * ecount2_buf; -    CHECK_OSE_CRYPTO(); -      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) @@ -1806,70 +1621,86 @@ static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_N      CONSUME_REDS(env,text_bin);      return ret;  } +#endif /* !HAVE_EVP_AES_CTR */  static ERL_NIF_TERM aes_gcm_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])  {/* (Key,Iv,AAD,In) */  #if defined(HAVE_GCM) -    GCM128_CONTEXT *ctx = NULL; +    EVP_CIPHER_CTX ctx; +    const EVP_CIPHER *cipher = NULL;      ErlNifBinary key, iv, aad, in; -    AES_KEY aes_key; -    unsigned char *outp; +    unsigned char *outp, *tagp;      ERL_NIF_TERM out, out_tag; - -    CHECK_OSE_CRYPTO(); +    int len;      if (!enif_inspect_iolist_as_binary(env, argv[0], &key) -	|| AES_set_encrypt_key(key.data, key.size*8, &aes_key) != 0 +	|| (key.size != 16 && key.size != 24 && key.size != 32)  	|| !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0  	|| !enif_inspect_iolist_as_binary(env, argv[2], &aad)  	|| !enif_inspect_iolist_as_binary(env, argv[3], &in)) {  	return enif_make_badarg(env);      } -    if (!(ctx = CRYPTO_gcm128_new(&aes_key, (block128_f)AES_encrypt))) -	return atom_error; +    if (key.size == 16) +        cipher = EVP_aes_128_gcm(); +    else if (key.size == 24) +        cipher = EVP_aes_192_gcm(); +    else if (key.size == 32) +        cipher = EVP_aes_256_gcm(); -    CRYPTO_gcm128_setiv(ctx, iv.data, iv.size); +    EVP_CIPHER_CTX_init(&ctx); -    if (CRYPTO_gcm128_aad(ctx, aad.data, aad.size)) -	goto out_err; +    if (EVP_EncryptInit_ex(&ctx, cipher, NULL, NULL, NULL) != 1) +        goto out_err; + +    EVP_CIPHER_CTX_set_padding(&ctx, 0); + +    if (EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size, NULL) != 1) +        goto out_err; +    if (EVP_EncryptInit_ex(&ctx, NULL, NULL, key.data, iv.data) != 1) +        goto out_err; +    if (EVP_EncryptUpdate(&ctx, NULL, &len, aad.data, aad.size) != 1) +        goto out_err;      outp = enif_make_new_binary(env, in.size, &out); -    /* encrypt */ -    if (CRYPTO_gcm128_encrypt(ctx, in.data, outp, in.size)) -	goto out_err; +    if (EVP_EncryptUpdate(&ctx, outp, &len, in.data, in.size) != 1) +        goto out_err; +    if (EVP_EncryptFinal_ex(&ctx, outp+len, &len) != 1) +        goto out_err; + +    tagp = enif_make_new_binary(env, EVP_GCM_TLS_TAG_LEN, &out_tag); -    /* calculate the tag */ -    CRYPTO_gcm128_tag(ctx, enif_make_new_binary(env, EVP_GCM_TLS_TAG_LEN, &out_tag), EVP_GCM_TLS_TAG_LEN); -    CRYPTO_gcm128_release(ctx); +    if (EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, EVP_GCM_TLS_TAG_LEN, tagp) != 1) +        goto out_err; + +    EVP_CIPHER_CTX_cleanup(&ctx);      CONSUME_REDS(env, in);      return enif_make_tuple2(env, out, out_tag);  out_err: -    CRYPTO_gcm128_release(ctx); +    EVP_CIPHER_CTX_cleanup(&ctx);      return atom_error;  #else -    return atom_notsup; +    return enif_raise_exception(env, atom_notsup);  #endif  }  static ERL_NIF_TERM aes_gcm_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])  {/* (Key,Iv,AAD,In,Tag) */  #if defined(HAVE_GCM) -    GCM128_CONTEXT *ctx; +    EVP_CIPHER_CTX ctx; +    const EVP_CIPHER *cipher = NULL;      ErlNifBinary key, iv, aad, in, tag; -    AES_KEY aes_key;      unsigned char *outp;      ERL_NIF_TERM out; - -    CHECK_OSE_CRYPTO(); +    int len;      if (!enif_inspect_iolist_as_binary(env, argv[0], &key) -        || AES_set_encrypt_key(key.data, key.size*8, &aes_key) != 0 +	|| (key.size != 16 && key.size != 24 && key.size != 32)  	|| !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0  	|| !enif_inspect_iolist_as_binary(env, argv[2], &aad)  	|| !enif_inspect_iolist_as_binary(env, argv[3], &in) @@ -1877,34 +1708,45 @@ static ERL_NIF_TERM aes_gcm_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM  	return enif_make_badarg(env);      } -    if (!(ctx = CRYPTO_gcm128_new(&aes_key, (block128_f)AES_encrypt))) -	return atom_error; +    if (key.size == 16) +        cipher = EVP_aes_128_gcm(); +    else if (key.size == 24) +        cipher = EVP_aes_192_gcm(); +    else if (key.size == 32) +        cipher = EVP_aes_256_gcm(); -    CRYPTO_gcm128_setiv(ctx, iv.data, iv.size); +    EVP_CIPHER_CTX_init(&ctx); -    if (CRYPTO_gcm128_aad(ctx, aad.data, aad.size)) -	goto out_err; +    if (EVP_DecryptInit_ex(&ctx, cipher, NULL, NULL, NULL) != 1) +        goto out_err; +    if (EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size, NULL) != 1) +        goto out_err; +    if (EVP_DecryptInit_ex(&ctx, NULL, NULL, key.data, iv.data) != 1) +        goto out_err; +    if (EVP_DecryptUpdate(&ctx, NULL, &len, aad.data, aad.size) != 1) +        goto out_err;      outp = enif_make_new_binary(env, in.size, &out); -    /* decrypt */ -    if (CRYPTO_gcm128_decrypt(ctx, in.data, outp, in.size)) -	    goto out_err; +    if (EVP_DecryptUpdate(&ctx, outp, &len, in.data, in.size) != 1) +        goto out_err; +    if (EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_TAG, EVP_GCM_TLS_TAG_LEN, tag.data) != 1) +        goto out_err; +    if (EVP_DecryptFinal_ex(&ctx, outp+len, &len) != 1) +        goto out_err; -    /* calculate and check the tag */ -    if (CRYPTO_gcm128_finish(ctx, tag.data, EVP_GCM_TLS_TAG_LEN)) -	    goto out_err; +    EVP_CIPHER_CTX_cleanup(&ctx); -    CRYPTO_gcm128_release(ctx);      CONSUME_REDS(env, in);      return out;  out_err: -    CRYPTO_gcm128_release(ctx); +    EVP_CIPHER_CTX_cleanup(&ctx);      return atom_error; +  #else -    return atom_notsup; +    return enif_raise_exception(env, atom_notsup);  #endif  } @@ -1937,8 +1779,6 @@ static ERL_NIF_TERM chacha20_poly1305_encrypt(ErlNifEnv* env, int argc, const ER      unsigned char poly1305_key[32];      poly1305_state poly1305; -    CHECK_OSE_CRYPTO(); -      if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 32  	|| !enif_inspect_binary(env, argv[1], &iv) || iv.size != CHACHA20_NONCE_LEN  	|| !enif_inspect_iolist_as_binary(env, argv[2], &aad) @@ -1976,7 +1816,7 @@ static ERL_NIF_TERM chacha20_poly1305_encrypt(ErlNifEnv* env, int argc, const ER      return enif_make_tuple2(env, out, out_tag);  #else -    return atom_notsup; +    return enif_raise_exception(env, atom_notsup);  #endif  } @@ -1991,8 +1831,6 @@ static ERL_NIF_TERM chacha20_poly1305_decrypt(ErlNifEnv* env, int argc, const ER      unsigned char mac[POLY1305_TAG_LEN];      poly1305_state poly1305; -    CHECK_OSE_CRYPTO(); -      if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 32  	|| !enif_inspect_binary(env, argv[1], &iv) || iv.size != CHACHA20_NONCE_LEN  	|| !enif_inspect_iolist_as_binary(env, argv[2], &aad) @@ -2033,51 +1871,16 @@ static ERL_NIF_TERM chacha20_poly1305_decrypt(ErlNifEnv* env, int argc, const ER      return out;  #else -    return atom_notsup; +    return enif_raise_exception(env, atom_notsup);  #endif  } -static ERL_NIF_TERM aes_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, Data, IsEncrypt) */     -    ErlNifBinary key_bin, data_bin; -    AES_KEY aes_key; -    int i; -    int j; -    unsigned char* ret_ptr; -    ERL_NIF_TERM ret;     - -    CHECK_OSE_CRYPTO(); - -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin) -    || (key_bin.size != 16 && key_bin.size != 32) -    || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin) -    || data_bin.size % 16 != 0) { -    return enif_make_badarg(env); -    } - -    if (argv[2] == 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); -    } - -    ret_ptr = enif_make_new_binary(env, data_bin.size, &ret); -    for (j = 0; j < data_bin.size; j += 16) { -	AES_ecb_encrypt(data_bin.data+j, ret_ptr+j, &aes_key, i); -    } -    CONSUME_REDS(env,data_bin); -    return ret; -} -  static ERL_NIF_TERM rand_bytes_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])  {/* (Bytes) */           unsigned bytes;      unsigned char* data;      ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); +      if (!enif_get_uint(env, argv[0], &bytes)) {  	return enif_make_badarg(env);      } @@ -2091,7 +1894,7 @@ static ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NI      unsigned bytes;      unsigned char* data;      ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); +      if (!enif_get_uint(env, argv[0], &bytes)) {  	return enif_make_badarg(env);      } @@ -2109,7 +1912,7 @@ static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar      unsigned char* data;      unsigned top_mask, bot_mask;      ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); +      if (!enif_get_uint(env, argv[0], &bytes)  	|| !enif_get_uint(env, argv[1], &top_mask)  	|| !enif_get_uint(env, argv[2], &bot_mask)) { @@ -2133,8 +1936,6 @@ static ERL_NIF_TERM strong_rand_mpint_nif(ErlNifEnv* env, int argc, const ERL_NI      unsigned dlen;      ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -      if (!enif_get_uint(env, argv[0], &bits)  	|| !enif_get_int(env, argv[1], &top)  	|| !enif_get_int(env, argv[2], &bottom)) { @@ -2203,8 +2004,6 @@ static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER      unsigned dlen;      ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -      if (!get_bn_from_mpint(env, argv[0], &bn_from)  	|| !get_bn_from_mpint(env, argv[1], &bn_rand)) {  	if (bn_from) BN_free(bn_from); @@ -2236,8 +2035,6 @@ static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg      unsigned extra_byte;      ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -      if (!get_bn_from_bin(env, argv[0], &bn_base)  	|| !get_bn_from_bin(env, argv[1], &bn_exponent)  	|| !get_bn_from_bin(env, argv[2], &bn_modulo) @@ -2269,46 +2066,17 @@ static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg  }  static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (DigestType|none, Data|{digest,Digest}, Signature,Key=[P, Q, G, Y]) */ -    ErlNifBinary data_bin, sign_bin; +{/* (sha, Digest, Signature,Key=[P, Q, G, Y]) */ +    ErlNifBinary digest_bin, sign_bin;      BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_y = NULL; -    unsigned char hmacbuf[SHA_DIGEST_LENGTH]; -    unsigned char* digest;      ERL_NIF_TERM head, tail; -    const ERL_NIF_TERM* tpl_terms; -    int tpl_arity;      DSA *dsa;      int i; -    CHECK_OSE_CRYPTO(); - -    if (argv[0] == atom_sha) { -	if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { -	    if (tpl_arity != 2 || tpl_terms[0] != atom_digest -		|| !enif_inspect_binary(env, tpl_terms[1], &data_bin) -		|| data_bin.size != SHA_DIGEST_LENGTH) { - -		return enif_make_badarg(env); -	    } -	    digest = data_bin.data; -	} -	else { -	    if (!enif_inspect_binary(env, argv[1], &data_bin)) { -		return enif_make_badarg(env); -	    } -	    SHA1(data_bin.data, data_bin.size, hmacbuf); -	    digest = hmacbuf; -	} -    } -    else if (argv[0] == atom_none && enif_inspect_binary(env, argv[1], &data_bin) -	     && data_bin.size == SHA_DIGEST_LENGTH) { -	digest = data_bin.data; -    } -    else { -	return enif_make_badarg(env); -    } - -    if (!enif_inspect_binary(env, argv[2], &sign_bin) +    if (!argv[0] == atom_sha +        || !enif_inspect_binary(env, argv[1], &digest_bin) +        || digest_bin.size != SHA_DIGEST_LENGTH +        || !enif_inspect_binary(env, argv[2], &sign_bin)  	|| !enif_get_list_cell(env, argv[3], &head, &tail)  	|| !get_bn_from_bin(env, head, &dsa_p)  	|| !enif_get_list_cell(env, tail, &head, &tail) @@ -2332,94 +2100,27 @@ static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM      dsa->g = dsa_g;      dsa->priv_key = NULL;      dsa->pub_key = dsa_y; -    i =  DSA_verify(0, digest, SHA_DIGEST_LENGTH, +    i =  DSA_verify(0, digest_bin.data, SHA_DIGEST_LENGTH,  		    sign_bin.data, sign_bin.size, dsa);      DSA_free(dsa);      return(i > 0) ? atom_true : atom_false;  } - -static void md5_digest(unsigned char* in, unsigned int in_len, unsigned char* out) -{ -    MD5(in, in_len, out); -} -static void sha1_digest(unsigned char* in, unsigned int in_len, unsigned char* out) -{ -    SHA1(in, in_len, out); -} -#ifdef HAVE_SHA224 -static void sha224_digest(unsigned char* in, unsigned int in_len, unsigned char* out) -{ -    SHA224(in, in_len, out); -} -#endif -#ifdef HAVE_SHA256 -static void sha256_digest(unsigned char* in, unsigned int in_len, unsigned char* out) -{ -    SHA256(in, in_len, out); -} -#endif -#ifdef HAVE_SHA384 -static void sha384_digest(unsigned char* in, unsigned int in_len, unsigned char* out) -{ -    SHA384(in, in_len, out); -} -#endif -#ifdef HAVE_SHA512 -static void sha512_digest(unsigned char* in, unsigned int in_len, unsigned char* out) +static void init_digest_types(ErlNifEnv* env)  { -    SHA512(in, in_len, out); -} -#endif +    struct digest_type_t* p = digest_types; -struct digest_type_t { -    const char* type_str; -    unsigned len; /* 0 if notsup */ -    int NID_type; -    void (*funcp)(unsigned char* in, unsigned int in_len, unsigned char* out); -    ERL_NIF_TERM type_atom; -}; +    for (p = digest_types; p->type_str; p++) { +	p->type_atom = enif_make_atom(env, p->type_str); +    } -struct digest_type_t digest_types[] = -{ -    {"md5", MD5_DIGEST_LENGTH, NID_md5, md5_digest}, -    {"sha", SHA_DIGEST_LENGTH, NID_sha1, sha1_digest}, -    {"sha224", -#ifdef HAVE_SHA224 -     SHA224_LEN, NID_sha224, sha224_digest -#else -      0 -#endif -    }, -    {"sha256", -#ifdef HAVE_SHA256 -     SHA256_LEN, NID_sha256, sha256_digest -#else -      0 -#endif -    }, -    {"sha384", -#ifdef HAVE_SHA384 -     SHA384_LEN, NID_sha384, sha384_digest -#else -     0 -#endif -    }, -    {"sha512", -#ifdef HAVE_SHA512 -     SHA512_LEN, NID_sha512, sha512_digest -#else -     0 -#endif -    }, -    {NULL} -}; +} -static void init_digest_types(ErlNifEnv* env) +static void init_cipher_types(ErlNifEnv* env)  { -    struct digest_type_t* p = digest_types; +    struct cipher_type_t* p = cipher_types; -    for (p = digest_types; p->type_str; p++) { +    for (p = cipher_types; p->type_str; p++) {  	p->type_atom = enif_make_atom(env, p->type_str);      } @@ -2436,32 +2137,45 @@ static struct digest_type_t* get_digest_type(ERL_NIF_TERM type)      return NULL;  } -static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type, Data|{digest,Digest}, Signature, Key=[E,N]) */ -    ErlNifBinary data_bin, sign_bin; -    unsigned char hmacbuf[SHA512_LEN]; -    ERL_NIF_TERM head, tail, ret; -    int i; -    RSA* rsa; -    const ERL_NIF_TERM type = argv[0]; -    const ERL_NIF_TERM* tpl_terms; -    int tpl_arity; -    struct digest_type_t* digp = NULL; -    unsigned char* digest = NULL; +static 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_str; p++) { +	if (type == p->type_atom && (!p->key_len || key_len == p->key_len)) { +	    return p; +	} +    } +    return NULL; +} -    CHECK_OSE_CRYPTO(); +static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Type, Digest, Signature, Key=[E,N]) */ +    ErlNifBinary         digest_bin, sign_bin; +    ERL_NIF_TERM         head, tail, ret; +    int                  i; +    RSA                  *rsa; +#if OPENSSL_VERSION_NUMBER >= 0x1000000fL +    EVP_PKEY             *pkey; +    EVP_PKEY_CTX         *ctx; +#endif +    const EVP_MD         *md; +    const ERL_NIF_TERM   type = argv[0]; +    struct digest_type_t *digp = NULL;      digp = get_digest_type(type);      if (!digp) {  	return enif_make_badarg(env);      } -    if (!digp->len) { +    if (!digp->md_func) {  	return atom_notsup;      }      rsa = RSA_new(); +    md  = digp->md_func(); -    if (!enif_inspect_binary(env, argv[2], &sign_bin) +    if (!enif_inspect_binary(env, argv[1], &digest_bin) +        || digest_bin.size != EVP_MD_size(md) +        || !enif_inspect_binary(env, argv[2], &sign_bin)  	|| !enif_get_list_cell(env, argv[3], &head, &tail)  	|| !get_bn_from_bin(env, head, &rsa->e)  	|| !enif_get_list_cell(env, tail, &head, &tail) @@ -2471,27 +2185,24 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM  	ret = enif_make_badarg(env);  	goto done;      } -    if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { -	if (tpl_arity != 2 || tpl_terms[0] != atom_digest -	    || !enif_inspect_binary(env, tpl_terms[1], &data_bin) -	    || data_bin.size != digp->len) { -	    ret = enif_make_badarg(env); -	    goto done; -	} -	digest = data_bin.data; -    } -    else if (enif_inspect_binary(env, argv[1], &data_bin)) { -	digest = hmacbuf; -	digp->funcp(data_bin.data, data_bin.size, digest); -    } -    else { -	ret = enif_make_badarg(env); -	goto done; -    } - -    i = RSA_verify(digp->NID_type, digest, digp->len, +#if OPENSSL_VERSION_NUMBER >= 0x1000000fL +    pkey = EVP_PKEY_new(); +    EVP_PKEY_set1_RSA(pkey, rsa); + +    ctx = EVP_PKEY_CTX_new(pkey, NULL); +    EVP_PKEY_verify_init(ctx); +    EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING); +    EVP_PKEY_CTX_set_signature_md(ctx, md); + +    i = EVP_PKEY_verify(ctx, sign_bin.data, sign_bin.size, +                        digest_bin.data, digest_bin.size); +    EVP_PKEY_CTX_free(ctx); +    EVP_PKEY_free(pkey); +#else +    i = RSA_verify(md->type, digest_bin.data, EVP_MD_size(md),  		   sign_bin.data, sign_bin.size, rsa); +#endif      ret = (i==1 ? atom_true : atom_false); @@ -2500,109 +2211,6 @@ done:      return ret;  } - -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; -    unsigned char ivec[16]; -    int enc, i = 0, outlen = 0; -    EVP_CIPHER_CTX ctx; -    const EVP_CIPHER *cipher = NULL; -    unsigned char* ret_ptr; -    ERL_NIF_TERM ret; - -    CHECK_OSE_CRYPTO(); - -    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 != 16 -	|| !enif_inspect_iolist_as_binary(env, argv[2], &data_bin) -	|| data_bin.size % 16 != 0) { - -	return enif_make_badarg(env); -    } - -    if (argv[3] == atom_true) -	enc = 1; -    else -	enc = 0; - -    EVP_CIPHER_CTX_init(&ctx); - -    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_cleanup(&ctx); - -    CONSUME_REDS(env,data_bin); - -    /* 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[]) -{/* (Key, IVec, Data, IsEncrypt) */ -#ifdef HAVE_AES_IGE -    ErlNifBinary key_bin, ivec_bin, data_bin; -    AES_KEY aes_key; -    unsigned char ivec[32]; -    int i; -    unsigned char* ret_ptr; -    ERL_NIF_TERM ret; - -    CHECK_OSE_CRYPTO(); - -    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); -    } - -    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); -    } - -    ret_ptr = enif_make_new_binary(env, data_bin.size, &ret); -    memcpy(ivec, ivec_bin.data, 32); /* writable copy */ -    AES_ige_encrypt(data_bin.data, ret_ptr, data_bin.size, &aes_key, ivec, i); -    CONSUME_REDS(env,data_bin); -    return ret; -#else -    return atom_notsup; -#endif -} -  static ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])  {/* (Data1, Data2) */      ErlNifBinary d1, d2; @@ -2610,8 +2218,6 @@ static ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])      int i;      ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -      if (!enif_inspect_iolist_as_binary(env,argv[0], &d1)  	|| !enif_inspect_iolist_as_binary(env,argv[1], &d2)  	|| d1.size != d2.size) { @@ -2632,8 +2238,6 @@ static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg      RC4_KEY rc4_key;      ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -      if (!enif_inspect_iolist_as_binary(env,argv[0], &key)  	|| !enif_inspect_iolist_as_binary(env,argv[1], &data)) {  	return enif_make_badarg(env); @@ -2650,8 +2254,6 @@ static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg      ErlNifBinary key;      ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -      if (!enif_inspect_iolist_as_binary(env,argv[0], &key)) {  	return enif_make_badarg(env);      } @@ -2667,8 +2269,6 @@ static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_N      RC4_KEY* rc4_key;      ERL_NIF_TERM new_state, new_data; -    CHECK_OSE_CRYPTO(); -      if (!enif_inspect_iolist_as_binary(env,argv[0], &state)  	|| state.size != sizeof(RC4_KEY)  	|| !enif_inspect_iolist_as_binary(env,argv[1], &data)) { @@ -2682,35 +2282,6 @@ static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_N      return enif_make_tuple2(env,new_state,new_data);  }    -static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key,IVec,Data,IsEncrypt) */ -    ErlNifBinary key_bin, ivec_bin, data_bin; -    RC2_KEY rc2_key; -    ERL_NIF_TERM ret; -    unsigned char iv_copy[8]; - -    CHECK_OSE_CRYPTO(); -     -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin) -	|| (key_bin.size != 5 && key_bin.size != 8 && key_bin.size != 16) -	|| !enif_inspect_binary(env, argv[1], &ivec_bin) -	|| ivec_bin.size != 8 -	|| !enif_inspect_iolist_as_binary(env, argv[2], &data_bin) -	|| data_bin.size % 8 != 0) { -	return enif_make_badarg(env); -    } -     -    RC2_set_key(&rc2_key, key_bin.size, key_bin.data, key_bin.size*8); -    memcpy(iv_copy, ivec_bin.data, 8); -    RC2_cbc_encrypt(data_bin.data, -		    enif_make_new_binary(env, data_bin.size, &ret), -		    data_bin.size, &rc2_key, -		    iv_copy, -		    (argv[3] == atom_true)); -    CONSUME_REDS(env,data_bin); -    return ret; -} -  static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa)  {      /* key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C] */ @@ -2740,42 +2311,32 @@ static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa)  }  static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type, Data|{digest,Digest}, Key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C]) */ -    ErlNifBinary data_bin, ret_bin; -    unsigned char hmacbuf[SHA512_LEN]; -    unsigned rsa_s_len; -    RSA* rsa; -    int i; -    const ERL_NIF_TERM* tpl_terms; -    int tpl_arity; +{/* (Type, Digest, Key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C]) */ +    ErlNifBinary         digest_bin, ret_bin; +#if OPENSSL_VERSION_NUMBER >= 0x1000000fL +    EVP_PKEY             *pkey; +    EVP_PKEY_CTX         *ctx; +    size_t               rsa_s_len; +#else +    unsigned             rsa_s_len, len; +#endif +    RSA                  *rsa; +    int                  i;      struct digest_type_t *digp; -    unsigned char* digest; - -    CHECK_OSE_CRYPTO(); +    const EVP_MD         *md;      digp = get_digest_type(argv[0]);      if (!digp) {  	return enif_make_badarg(env);      } -    if (!digp->len) { +    if (!digp->md_func) {  	return atom_notsup;      } +    md = digp->md_func(); -    if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { -	if (tpl_arity != 2 || tpl_terms[0] != atom_digest -	    || !enif_inspect_binary(env, tpl_terms[1], &data_bin) -	    || data_bin.size != digp->len) { - -	    return enif_make_badarg(env); -	} -	digest = data_bin.data; -    } -    else { -	if (!enif_inspect_binary(env,argv[1],&data_bin)) { -	    return enif_make_badarg(env); -	} -	digest = hmacbuf; -	digp->funcp(data_bin.data, data_bin.size, digest); +    if (!enif_inspect_binary(env,argv[1],&digest_bin) +        || digest_bin.size != EVP_MD_size(md)) { +        return enif_make_badarg(env);      }      rsa = RSA_new(); @@ -2785,14 +2346,33 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar      } +#if OPENSSL_VERSION_NUMBER >= 0x1000000fL +    pkey = EVP_PKEY_new(); +    EVP_PKEY_set1_RSA(pkey, rsa); +    rsa_s_len=(size_t)EVP_PKEY_size(pkey); +    enif_alloc_binary(rsa_s_len, &ret_bin); + +    ctx = EVP_PKEY_CTX_new(pkey, NULL); +    EVP_PKEY_sign_init(ctx); +    EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING); +    EVP_PKEY_CTX_set_signature_md(ctx, md); + +    i = EVP_PKEY_sign(ctx, ret_bin.data, &rsa_s_len, +                      digest_bin.data, digest_bin.size); +    ASSERT(i<=0 || rsa_s_len <= ret_bin.size); +    EVP_PKEY_CTX_free(ctx); +    EVP_PKEY_free(pkey); +#else      enif_alloc_binary(RSA_size(rsa), &ret_bin); +    len = EVP_MD_size(md); -    ERL_VALGRIND_ASSERT_MEM_DEFINED(digest, digp->len); -    i =  RSA_sign(digp->NID_type, digest, digp->len, +    ERL_VALGRIND_ASSERT_MEM_DEFINED(digest_bin.data, len); +    i =  RSA_sign(md->type, digest_bin.data, len,  		  ret_bin.data, &rsa_s_len, rsa); +#endif      RSA_free(rsa); -    if (i) { +    if (i > 0) {  	ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, rsa_s_len);  	if (rsa_s_len != ret_bin.size) {  	    enif_realloc_binary(&ret_bin, rsa_s_len); @@ -2808,44 +2388,16 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar  static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (DigesType|none, Data|{digest,Digest}, Key=[P,Q,G,PrivKey]) */ -    ErlNifBinary data_bin, ret_bin; +{/* (sha, Digest, Key=[P,Q,G,PrivKey]) */ +    ErlNifBinary digest_bin, ret_bin;      ERL_NIF_TERM head, tail; -    unsigned char hmacbuf[SHA_DIGEST_LENGTH];      unsigned int dsa_s_len; -    const ERL_NIF_TERM* tpl_terms; -    int tpl_arity; -    unsigned char* digest = NULL;      DSA* dsa;      int i; -    CHECK_OSE_CRYPTO(); - -    if (argv[0] == atom_sha) { -	if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { -	    if (tpl_arity != 2 || tpl_terms[0] != atom_digest -		|| !enif_inspect_binary(env, tpl_terms[1], &data_bin) -		|| data_bin.size != SHA_DIGEST_LENGTH) { - -		return enif_make_badarg(env); -	    } -	    digest = data_bin.data; -	} -	else { -	    if (!enif_inspect_binary(env,argv[1],&data_bin)) { -		return enif_make_badarg(env); -	    } -	    SHA1(data_bin.data, data_bin.size, hmacbuf); -	    digest = hmacbuf; -	} -    } -    else if (argv[0] == atom_none -	     && enif_inspect_binary(env,argv[1],&data_bin) -	     && data_bin.size == SHA_DIGEST_LENGTH) { - -	digest = data_bin.data; -    } -    else { +    if (!argv[0] == atom_sha +        || !enif_inspect_binary(env, argv[1], &digest_bin) +        || digest_bin.size != SHA_DIGEST_LENGTH) {  	return enif_make_badarg(env);      } @@ -2866,7 +2418,7 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar      }      enif_alloc_binary(DSA_size(dsa), &ret_bin); -    i =  DSA_sign(NID_sha1, digest, SHA_DIGEST_LENGTH, +    i =  DSA_sign(NID_sha1, digest_bin.data, SHA_DIGEST_LENGTH,  		  ret_bin.data, &dsa_s_len, dsa);      DSA_free(dsa);      if (i) { @@ -2906,8 +2458,6 @@ static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TER      int padding, i;      RSA* rsa; -    CHECK_OSE_CRYPTO(); -      rsa = RSA_new();      if (!enif_inspect_binary(env, argv[0], &data_bin) @@ -2956,8 +2506,6 @@ static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TE      int padding, i;      RSA* rsa; -    CHECK_OSE_CRYPTO(); -      rsa = RSA_new();      if (!enif_inspect_binary(env, argv[0], &data_bin) @@ -3004,8 +2552,6 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E      unsigned char *p_ptr, *g_ptr;      ERL_NIF_TERM ret_p, ret_g; -    CHECK_OSE_CRYPTO(); -      if (!enif_get_int(env, argv[0], &prime_len)  	|| !enif_get_int(env, argv[1], &generator)) { @@ -3033,8 +2579,6 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]      int i;      ERL_NIF_TERM ret, head, tail; -    CHECK_OSE_CRYPTO(); -      dh_params = DH_new();      if (!enif_get_list_cell(env, argv[0], &head, &tail)    @@ -3069,8 +2613,6 @@ static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_      ERL_NIF_TERM ret, ret_pub, ret_prv, head, tail;      int mpint; /* 0 or 4 */ -    CHECK_OSE_CRYPTO(); -      dh_params = DH_new();      if (!(get_bn_from_bin(env, argv[0], &dh_params->priv_key) @@ -3115,8 +2657,6 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T      ErlNifBinary ret_bin;      ERL_NIF_TERM ret, head, tail; -    CHECK_OSE_CRYPTO(); -      dh_params = DH_new();      if (!get_bn_from_bin(env, argv[0], &pubkey) @@ -3139,7 +2679,7 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T  	    ret = enif_make_binary(env, &ret_bin);  	}  	else { -	    enif_release_binary(&ret_bin); +            enif_release_binary(&ret_bin);  	    ret = atom_error;  	}      } @@ -3157,8 +2697,6 @@ static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM      unsigned dlen;      ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -      if (!get_bn_from_bin(env, argv[0], &bn_multiplier)  	|| !get_bn_from_bin(env, argv[1], &bn_verifier)  	|| !get_bn_from_bin(env, argv[2], &bn_generator) @@ -3219,8 +2757,6 @@ static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_      unsigned dlen;      ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -      if (!get_bn_from_bin(env, argv[0], &bn_a)  	|| !get_bn_from_bin(env, argv[1], &bn_u)  	|| !get_bn_from_bin(env, argv[2], &bn_B) @@ -3300,8 +2836,6 @@ static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_      unsigned dlen;      ERL_NIF_TERM ret; -    CHECK_OSE_CRYPTO(); -      if (!get_bn_from_bin(env, argv[0], &bn_verifier)  	|| !get_bn_from_bin(env, argv[1], &bn_b)  	|| !get_bn_from_bin(env, argv[2], &bn_u) @@ -3354,103 +2888,6 @@ static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_      return ret;  } -static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])     -{/* (Key, Ivec, Data, IsEncrypt) */ -    ErlNifBinary key_bin, ivec_bin, data_bin; -    BF_KEY bf_key; /* blowfish key 8 */ -    unsigned char bf_tkey[8]; /* blowfish ivec */     -    int bf_n = 0; /* blowfish ivec pos */ -    ERL_NIF_TERM ret; - -    CHECK_OSE_CRYPTO(); - -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin) -	|| !enif_inspect_binary(env, argv[1], &ivec_bin) -	|| ivec_bin.size != 8  -	|| !enif_inspect_iolist_as_binary(env, argv[2], &data_bin)) { -	return enif_make_badarg(env); -    } - -    BF_set_key(&bf_key, key_bin.size, key_bin.data); -    memcpy(bf_tkey, ivec_bin.data, 8); -    BF_cfb64_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret), -		     data_bin.size, &bf_key, bf_tkey, &bf_n, -		     (argv[3] == atom_true ? BF_ENCRYPT : BF_DECRYPT)); -    CONSUME_REDS(env,data_bin); -    return ret; -} - -static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, Ivec, Data, IsEncrypt) */ -    ErlNifBinary key_bin, ivec_bin, data_bin; -    BF_KEY bf_key; /* blowfish key 8 */ -    unsigned char bf_tkey[8]; /* blowfish ivec */     -    ERL_NIF_TERM ret; - -    CHECK_OSE_CRYPTO(); - -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin) -	|| !enif_inspect_binary(env, argv[1], &ivec_bin) -	|| ivec_bin.size != 8  -	|| !enif_inspect_iolist_as_binary(env, argv[2], &data_bin) -	|| data_bin.size % 8 != 0) { -	return enif_make_badarg(env); -    } - -    BF_set_key(&bf_key, key_bin.size, key_bin.data); -    memcpy(bf_tkey, ivec_bin.data, 8); -    BF_cbc_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret), -		   data_bin.size, &bf_key, bf_tkey, -		   (argv[3] == atom_true ? BF_ENCRYPT : BF_DECRYPT)); -    CONSUME_REDS(env,data_bin); -    return ret; -} - -static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])     -{/* (Key, Data, IsEncrypt) */ -    ErlNifBinary key_bin, data_bin; -    BF_KEY bf_key; /* blowfish key 8 */ -    ERL_NIF_TERM ret; - -    CHECK_OSE_CRYPTO(); - -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin) -	|| !enif_inspect_iolist_as_binary(env, argv[1], &data_bin) -	|| data_bin.size < 8) { -	return enif_make_badarg(env); -    } -    BF_set_key(&bf_key, key_bin.size, key_bin.data); -    BF_ecb_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret), -		   &bf_key, (argv[2] == atom_true ? BF_ENCRYPT : BF_DECRYPT)); -    CONSUME_REDS(env,data_bin); -    return ret; -} - -static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])     -{/* (Key, IVec, Data) */ -    ErlNifBinary key_bin, ivec_bin, data_bin; -    BF_KEY bf_key; /* blowfish key 8 */ -    unsigned char bf_tkey[8]; /* blowfish ivec */     -    int bf_n = 0; /* blowfish ivec pos */ -    ERL_NIF_TERM ret; - -    CHECK_OSE_CRYPTO(); - -    if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin) -	|| !enif_inspect_binary(env, argv[1], &ivec_bin) -	|| ivec_bin.size != 8  -	|| !enif_inspect_iolist_as_binary(env, argv[2], &data_bin)) { -	return enif_make_badarg(env); -    } - -    BF_set_key(&bf_key, key_bin.size, key_bin.data); -    memcpy(bf_tkey, ivec_bin.data, 8); -    BF_ofb64_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret), -		     data_bin.size, &bf_key, bf_tkey, &bf_n); -    CONSUME_REDS(env,data_bin); -    return ret; -} -  #if defined(HAVE_EC)  static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg)  { @@ -3762,8 +3199,6 @@ static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM      ERL_NIF_TERM priv_key;      ERL_NIF_TERM pub_key = atom_undefined; -    CHECK_OSE_CRYPTO(); -      if (!get_ec_key(env, argv[0], argv[1], atom_undefined, &key))  	goto badarg; @@ -3793,51 +3228,33 @@ badarg:  }  static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type, Data|{digest,Digest}, Curve, Key) */ +{/* (Type, Digest, Curve, Key) */  #if defined(HAVE_EC) -    ErlNifBinary data_bin, ret_bin; -    unsigned char hmacbuf[SHA_DIGEST_LENGTH]; +    ErlNifBinary digest_bin, ret_bin;      unsigned int dsa_s_len;      EC_KEY* key = NULL; -    int i; -    const ERL_NIF_TERM* tpl_terms; -    int tpl_arity; +    int i, len;      struct digest_type_t *digp; -    unsigned char* digest; - -    CHECK_OSE_CRYPTO(); +    const EVP_MD         *md;      digp = get_digest_type(argv[0]);      if (!digp) {  	return enif_make_badarg(env);      } -    if (!digp->len) { +    if (!digp->md_func) {  	return atom_notsup;      } +    md  = digp->md_func(); +    len = EVP_MD_size(md); -    if (!get_ec_key(env, argv[2], argv[3], atom_undefined, &key)) +    if (!enif_inspect_binary(env,argv[1],&digest_bin) +        || digest_bin.size != len +        || !get_ec_key(env, argv[2], argv[3], atom_undefined, &key))        goto badarg; -    if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { -	if (tpl_arity != 2 || tpl_terms[0] != atom_digest -	    || !enif_inspect_binary(env, tpl_terms[1], &data_bin) -	    || data_bin.size != digp->len) { - -	    goto badarg; -	} -	digest = data_bin.data; -    } -    else { -	if (!enif_inspect_binary(env,argv[1],&data_bin)) { -	    goto badarg; -	} -	digest = hmacbuf; -	digp->funcp(data_bin.data, data_bin.size, digest); -    } -      enif_alloc_binary(ECDSA_size(key), &ret_bin); -    i = ECDSA_sign(digp->NID_type, digest, digp->len, +    i = ECDSA_sign(md->type, digest_bin.data, len,  		   ret_bin.data, &dsa_s_len, key);      EC_KEY_free(key); @@ -3862,50 +3279,32 @@ badarg:  }  static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type, Data|{digest,Digest}, Signature, Curve, Key) */ +{/* (Type, Digest, Signature, Curve, Key) */  #if defined(HAVE_EC) -    ErlNifBinary data_bin, sign_bin; -    unsigned char hmacbuf[SHA512_LEN]; -    int i; +    ErlNifBinary digest_bin, sign_bin; +    int i, len;      EC_KEY* key = NULL;      const ERL_NIF_TERM type = argv[0]; -    const ERL_NIF_TERM* tpl_terms; -    int tpl_arity; -    struct digest_type_t* digp = NULL; -    unsigned char* digest = NULL; - -    CHECK_OSE_CRYPTO(); +    struct digest_type_t *digp = NULL; +    const EVP_MD         *md;      digp = get_digest_type(type);      if (!digp) {  	return enif_make_badarg(env);      } -    if (!digp->len) { +    if (!digp->md_func) {  	return atom_notsup;      } +    md  = digp->md_func(); +    len = EVP_MD_size(md); -    if (!enif_inspect_binary(env, argv[2], &sign_bin) +    if (!enif_inspect_binary(env, argv[1], &digest_bin) +        || digest_bin.size != len +        || !enif_inspect_binary(env, argv[2], &sign_bin)  	|| !get_ec_key(env, argv[3], atom_undefined, argv[4], &key))  	goto badarg; -    if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) { -	if (tpl_arity != 2 || tpl_terms[0] != atom_digest -	    || !enif_inspect_binary(env, tpl_terms[1], &data_bin) -	    || data_bin.size != digp->len) { - -	    goto badarg; -	} -	digest = data_bin.data; -    } -    else if (enif_inspect_binary(env, argv[1], &data_bin)) { -	digest = hmacbuf; -	digp->funcp(data_bin.data, data_bin.size, digest); -    } -    else { -	goto badarg; -    } - -    i = ECDSA_verify(digp->NID_type, digest, digp->len, +    i = ECDSA_verify(md->type, digest_bin.data, len,  		     sign_bin.data, sign_bin.size, key);      EC_KEY_free(key); @@ -3939,8 +3338,6 @@ static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF      EC_POINT *my_ecpoint;      EC_KEY *other_ecdh = NULL; -    CHECK_OSE_CRYPTO(); -      if (!get_ec_key(env, argv[1], argv[2], atom_undefined, &key))  	return enif_make_badarg(env); @@ -3984,253 +3381,9 @@ out_err:  static ERL_NIF_TERM rand_seed_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])  {      ErlNifBinary seed_bin; -    CHECK_OSE_CRYPTO(); +      if (!enif_inspect_binary(env, argv[0], &seed_bin))          return enif_make_badarg(env);      RAND_seed(seed_bin.data,seed_bin.size);      return atom_ok;  } - - -/* HMAC */ - -static void hmac_md5(unsigned char *key, int klen, unsigned char *dbuf, int dlen, -		     unsigned char *hmacbuf) -{ -    MD5_CTX ctx; -    char ipad[HMAC_INT_LEN]; -    char opad[HMAC_INT_LEN]; -    unsigned char nkey[MD5_LEN]; -    int i; - -    /* Change key if longer than 64 bytes */ -    if (klen > HMAC_INT_LEN) { -	MD5(key, klen, nkey); -	key = nkey; -	klen = MD5_LEN; -    } - -    memset(ipad, '\0', sizeof(ipad)); -    memset(opad, '\0', sizeof(opad)); -    memcpy(ipad, key, klen); -    memcpy(opad, key, klen); - -    for (i = 0; i < HMAC_INT_LEN; i++) { -	ipad[i] ^= HMAC_IPAD; -	opad[i] ^= HMAC_OPAD; -    } - -    /* inner MD5 */ -    MD5_Init(&ctx); -    MD5_Update(&ctx, ipad, HMAC_INT_LEN); -    MD5_Update(&ctx, dbuf, dlen); -    MD5_Final((unsigned char *) hmacbuf, &ctx); -    /* outer MD5 */ -    MD5_Init(&ctx); -    MD5_Update(&ctx, opad, HMAC_INT_LEN); -    MD5_Update(&ctx, hmacbuf, MD5_LEN); -    MD5_Final((unsigned char *) hmacbuf, &ctx); -} - -static void hmac_sha1(unsigned char *key, int klen, -		      unsigned char *dbuf, int dlen,  -		      unsigned char *hmacbuf) -{ -    SHA_CTX ctx; -    char ipad[HMAC_INT_LEN]; -    char opad[HMAC_INT_LEN]; -    unsigned char nkey[SHA_LEN]; -    int i; - -    /* Change key if longer than 64 bytes */ -    if (klen > HMAC_INT_LEN) { -	SHA1(key, klen, nkey); -	key = nkey; -	klen = SHA_LEN; -    } - -    memset(ipad, '\0', sizeof(ipad)); -    memset(opad, '\0', sizeof(opad)); -    memcpy(ipad, key, klen); -    memcpy(opad, key, klen); - -    for (i = 0; i < HMAC_INT_LEN; i++) { -	ipad[i] ^= HMAC_IPAD; -	opad[i] ^= HMAC_OPAD; -    } - -    /* inner SHA */ -    SHA1_Init(&ctx); -    SHA1_Update(&ctx, ipad, HMAC_INT_LEN); -    SHA1_Update(&ctx, dbuf, dlen); -    SHA1_Final((unsigned char *) hmacbuf, &ctx); -    /* outer SHA */ -    SHA1_Init(&ctx); -    SHA1_Update(&ctx, opad, HMAC_INT_LEN); -    SHA1_Update(&ctx, hmacbuf, SHA_LEN); -    SHA1_Final((unsigned char *) hmacbuf, &ctx); -} - -#ifdef HAVE_SHA224 -static void hmac_sha224(unsigned char *key, int klen, -			unsigned char *dbuf, int dlen, -			unsigned char *hmacbuf) -{ -    SHA256_CTX ctx; -    char ipad[HMAC_INT_LEN]; -    char opad[HMAC_INT_LEN]; -    unsigned char nkey[SHA224_DIGEST_LENGTH]; -    int i; - -    /* Change key if longer than 64 bytes */ -    if (klen > HMAC_INT_LEN) { -	SHA224(key, klen, nkey); -	key = nkey; -	klen = SHA224_DIGEST_LENGTH; -    } - -    memset(ipad, '\0', sizeof(ipad)); -    memset(opad, '\0', sizeof(opad)); -    memcpy(ipad, key, klen); -    memcpy(opad, key, klen); - -    for (i = 0; i < HMAC_INT_LEN; i++) { -	ipad[i] ^= HMAC_IPAD; -	opad[i] ^= HMAC_OPAD; -    } - -    /* inner SHA */ -    SHA224_Init(&ctx); -    SHA224_Update(&ctx, ipad, HMAC_INT_LEN); -    SHA224_Update(&ctx, dbuf, dlen); -    SHA224_Final((unsigned char *) hmacbuf, &ctx); -    /* outer SHA */ -    SHA224_Init(&ctx); -    SHA224_Update(&ctx, opad, HMAC_INT_LEN); -    SHA224_Update(&ctx, hmacbuf, SHA224_DIGEST_LENGTH); -    SHA224_Final((unsigned char *) hmacbuf, &ctx); -} -#endif - -#ifdef HAVE_SHA256 -static void hmac_sha256(unsigned char *key, int klen, -			unsigned char *dbuf, int dlen, -			unsigned char *hmacbuf) -{ -    SHA256_CTX ctx; -    char ipad[HMAC_INT_LEN]; -    char opad[HMAC_INT_LEN]; -    unsigned char nkey[SHA256_DIGEST_LENGTH]; -    int i; - -    /* Change key if longer than 64 bytes */ -    if (klen > HMAC_INT_LEN) { -	SHA256(key, klen, nkey); -	key = nkey; -	klen = SHA256_DIGEST_LENGTH; -    } - -    memset(ipad, '\0', sizeof(ipad)); -    memset(opad, '\0', sizeof(opad)); -    memcpy(ipad, key, klen); -    memcpy(opad, key, klen); - -    for (i = 0; i < HMAC_INT_LEN; i++) { -	ipad[i] ^= HMAC_IPAD; -	opad[i] ^= HMAC_OPAD; -    } - -    /* inner SHA */ -    SHA256_Init(&ctx); -    SHA256_Update(&ctx, ipad, HMAC_INT_LEN); -    SHA256_Update(&ctx, dbuf, dlen); -    SHA256_Final((unsigned char *) hmacbuf, &ctx); -    /* outer SHA */ -    SHA256_Init(&ctx); -    SHA256_Update(&ctx, opad, HMAC_INT_LEN); -    SHA256_Update(&ctx, hmacbuf, SHA256_DIGEST_LENGTH); -    SHA256_Final((unsigned char *) hmacbuf, &ctx); -} -#endif - -#ifdef HAVE_SHA384 -static void hmac_sha384(unsigned char *key, int klen, -			unsigned char *dbuf, int dlen, -			unsigned char *hmacbuf) -{ -    SHA512_CTX ctx; -    char ipad[HMAC_INT2_LEN]; -    char opad[HMAC_INT2_LEN]; -    unsigned char nkey[SHA384_DIGEST_LENGTH]; -    int i; - -    /* Change key if longer than 64 bytes */ -    if (klen > HMAC_INT2_LEN) { -	SHA384(key, klen, nkey); -	key = nkey; -	klen = SHA384_DIGEST_LENGTH; -    } - -    memset(ipad, '\0', sizeof(ipad)); -    memset(opad, '\0', sizeof(opad)); -    memcpy(ipad, key, klen); -    memcpy(opad, key, klen); - -    for (i = 0; i < HMAC_INT2_LEN; i++) { -	ipad[i] ^= HMAC_IPAD; -	opad[i] ^= HMAC_OPAD; -    } - -    /* inner SHA */ -    SHA384_Init(&ctx); -    SHA384_Update(&ctx, ipad, HMAC_INT2_LEN); -    SHA384_Update(&ctx, dbuf, dlen); -    SHA384_Final((unsigned char *) hmacbuf, &ctx); -    /* outer SHA */ -    SHA384_Init(&ctx); -    SHA384_Update(&ctx, opad, HMAC_INT2_LEN); -    SHA384_Update(&ctx, hmacbuf, SHA384_DIGEST_LENGTH); -    SHA384_Final((unsigned char *) hmacbuf, &ctx); -} -#endif - -#ifdef HAVE_SHA512 -static void hmac_sha512(unsigned char *key, int klen, -			unsigned char *dbuf, int dlen, -			unsigned char *hmacbuf) -{ -    SHA512_CTX ctx; -    char ipad[HMAC_INT2_LEN]; -    char opad[HMAC_INT2_LEN]; -    unsigned char nkey[SHA512_DIGEST_LENGTH]; -    int i; - -    /* Change key if longer than 64 bytes */ -    if (klen > HMAC_INT2_LEN) { -	SHA512(key, klen, nkey); -	key = nkey; -	klen = SHA512_DIGEST_LENGTH; -    } - -    memset(ipad, '\0', sizeof(ipad)); -    memset(opad, '\0', sizeof(opad)); -    memcpy(ipad, key, klen); -    memcpy(opad, key, klen); - -    for (i = 0; i < HMAC_INT2_LEN; i++) { -	ipad[i] ^= HMAC_IPAD; -	opad[i] ^= HMAC_OPAD; -    } - -    /* inner SHA */ -    SHA512_Init(&ctx); -    SHA512_Update(&ctx, ipad, HMAC_INT2_LEN); -    SHA512_Update(&ctx, dbuf, dlen); -    SHA512_Final((unsigned char *) hmacbuf, &ctx); -    /* outer SHA */ -    SHA512_Init(&ctx); -    SHA512_Update(&ctx, opad, HMAC_INT2_LEN); -    SHA512_Update(&ctx, hmacbuf, SHA512_DIGEST_LENGTH); -    SHA512_Final((unsigned char *) hmacbuf, &ctx); -} -#endif  | 
