diff options
author | Ingela Anderton Andin <[email protected]> | 2013-05-08 10:43:24 +0200 |
---|---|---|
committer | Ingela Anderton Andin <[email protected]> | 2013-05-08 10:43:24 +0200 |
commit | 705e3b1137ebb2cfa1e729c9a4cf44638270f7e5 (patch) | |
tree | 800665a97cec32d894b822b0c9d3b4eeb7d51f8e /lib/crypto | |
parent | 8e00f4ce7a49b2fd1da7e481dc0985703e4131a5 (diff) | |
parent | 19d511a10d5e258b8f2f876f7c12ffbf35174d89 (diff) | |
download | otp-705e3b1137ebb2cfa1e729c9a4cf44638270f7e5.tar.gz otp-705e3b1137ebb2cfa1e729c9a4cf44638270f7e5.tar.bz2 otp-705e3b1137ebb2cfa1e729c9a4cf44638270f7e5.zip |
Merge branch 'ia/ssl/public_key/crypto/elliptic_curve/OTP-11009' into maint
* ia/ssl/public_key/crypto/elliptic_curve/OTP-11009: (39 commits)
ssl: Fix dialyzer spec
crypto: Remove debug printouts
ssl: Only send ECC-hello extension if ECC-cipher suites are advertised
ssl & public_key: Use standard name
ssl & crypto: Generalize the remaining crypto API
public_key: Add new API functions to the documentation
ssl & public_key: Use new crypto API functions
crypto: New API for ciphers
crypto: Deprecate functions, update doc and specs
ssl: Fix Curve selection
ssl, crypto: Eliminate remaining mpint and EC resource key from API
ssl, public_key, crypto: General generate_key and compute_key functions
crypto: Add generic functions generate_key and compute_key
crypto: Change ecdh_compute_key to have 3 arguments
ssl: Improve extention handling
ssl: test case fix
ssl & public_key: API refinement
public_key: use new crypto
crypto: Fix ec_key resource to be upgradeable
crypto: Combine ec_key_new into ecdh_generate_key
...
Diffstat (limited to 'lib/crypto')
-rw-r--r-- | lib/crypto/c_src/crypto.c | 863 | ||||
-rw-r--r--[-rwxr-xr-x] | lib/crypto/doc/src/crypto.xml | 1548 | ||||
-rw-r--r-- | lib/crypto/doc/src/crypto_app.xml | 79 | ||||
-rw-r--r-- | lib/crypto/src/crypto.erl | 692 | ||||
-rw-r--r-- | lib/crypto/test/crypto_SUITE.erl | 312 |
5 files changed, 1944 insertions, 1550 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index fac77308f6..9d43a1d907 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -74,6 +74,19 @@ # define HAVE_DES_ede3_cfb_encrypt #endif +#if OPENSSL_VERSION_NUMBER >= 0x009080ffL \ + && !defined(OPENSSL_NO_EC) \ + && !defined(OPENSSL_NO_ECDH) \ + && !defined(OPENSSL_NO_ECDSA) +# define HAVE_EC +#endif + +#if defined(HAVE_EC) +#include <openssl/ec.h> +#include <openssl/ecdh.h> +#include <openssl/ecdsa.h> +#endif + #ifdef VALGRIND # include <valgrind/memcheck.h> @@ -192,7 +205,7 @@ static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar static ERL_NIF_TERM strong_rand_mpint_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM dss_verify(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 exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -209,13 +222,19 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM srp_server_secret_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_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM term_to_ec_key_nif(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[]); +static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); /* helpers */ @@ -247,6 +266,11 @@ static void hmac_sha512(unsigned char *key, int klen, unsigned char *dbuf, int dlen, unsigned char *hmacbuf); #endif +#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, + EC_GROUP *group, EC_POINT **pptr); +#endif static int library_refc = 0; /* number of users of this dynamic library */ @@ -311,7 +335,7 @@ static ErlNifFunc nif_funcs[] = { {"strong_rand_mpint_nif", 3, strong_rand_mpint_nif}, {"rand_uniform_nif", 2, rand_uniform_nif}, {"mod_exp_nif", 4, mod_exp_nif}, - {"dss_verify", 4, dss_verify}, + {"dss_verify_nif", 4, dss_verify_nif}, {"rsa_verify_nif", 4, rsa_verify_nif}, {"aes_cbc_crypt", 4, aes_cbc_crypt}, {"exor", 2, exor}, @@ -325,16 +349,120 @@ static ErlNifFunc nif_funcs[] = { {"rsa_private_crypt", 4, rsa_private_crypt}, {"dh_generate_parameters_nif", 2, dh_generate_parameters_nif}, {"dh_check", 1, dh_check}, - {"dh_generate_key_nif", 2, dh_generate_key_nif}, + {"dh_generate_key_nif", 3, dh_generate_key_nif}, {"dh_compute_key_nif", 3, dh_compute_key_nif}, {"srp_value_B_nif", 5, srp_value_B_nif}, - {"srp_client_secret_nif", 7, srp_client_secret_nif}, - {"srp_server_secret_nif", 5, srp_server_secret_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} + {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt}, + + {"ec_key_to_term_nif", 1, ec_key_to_term_nif}, + {"term_to_ec_key_nif", 3, term_to_ec_key_nif}, + {"ec_key_generate", 1, ec_key_generate}, + {"ecdsa_sign_nif", 3, ecdsa_sign_nif}, + {"ecdsa_verify_nif", 4, ecdsa_verify_nif}, + {"ecdh_compute_key_nif", 2, ecdh_compute_key_nif} +}; + +#if defined(HAVE_EC) +struct nid_map { + char *name; + int nid; + ERL_NIF_TERM atom; +}; + +static struct nid_map ec_curves[] = { + /* prime field curves */ + /* secg curves */ + { "secp112r1", NID_secp112r1 }, + { "secp112r2", NID_secp112r2 }, + { "secp128r1", NID_secp128r1 }, + { "secp128r2", NID_secp128r2 }, + { "secp160k1", NID_secp160k1 }, + { "secp160r1", NID_secp160r1 }, + { "secp160r2", NID_secp160r2 }, + /* SECG secp192r1 is the same as X9.62 prime192v1 */ + { "secp192r1", NID_X9_62_prime192v1 }, + { "secp192k1", NID_secp192k1 }, + { "secp224k1", NID_secp224k1 }, + { "secp224r1", NID_secp224r1 }, + { "secp256k1", NID_secp256k1 }, + /* SECG secp256r1 is the same as X9.62 prime256v1 */ + { "secp256r1", NID_X9_62_prime256v1 }, + { "secp384r1", NID_secp384r1 }, + { "secp521r1", NID_secp521r1 }, + /* X9.62 curves */ + { "prime192v1", NID_X9_62_prime192v1 }, + { "prime192v2", NID_X9_62_prime192v2 }, + { "prime192v3", NID_X9_62_prime192v3 }, + { "prime239v1", NID_X9_62_prime239v1 }, + { "prime239v2", NID_X9_62_prime239v2 }, + { "prime239v3", NID_X9_62_prime239v3 }, + { "prime256v1", NID_X9_62_prime256v1 }, + /* characteristic two field curves */ + /* NIST/SECG curves */ + { "sect113r1", NID_sect113r1 }, + { "sect113r2", NID_sect113r2 }, + { "sect131r1", NID_sect131r1 }, + { "sect131r2", NID_sect131r2 }, + { "sect163k1", NID_sect163k1 }, + { "sect163r1", NID_sect163r1 }, + { "sect163r2", NID_sect163r2 }, + { "sect193r1", NID_sect193r1 }, + { "sect193r2", NID_sect193r2 }, + { "sect233k1", NID_sect233k1 }, + { "sect233r1", NID_sect233r1 }, + { "sect239k1", NID_sect239k1 }, + { "sect283k1", NID_sect283k1 }, + { "sect283r1", NID_sect283r1 }, + { "sect409k1", NID_sect409k1 }, + { "sect409r1", NID_sect409r1 }, + { "sect571k1", NID_sect571k1 }, + { "sect571r1", NID_sect571r1 }, + /* X9.62 curves */ + { "c2pnb163v1", NID_X9_62_c2pnb163v1 }, + { "c2pnb163v2", NID_X9_62_c2pnb163v2 }, + { "c2pnb163v3", NID_X9_62_c2pnb163v3 }, + { "c2pnb176v1", NID_X9_62_c2pnb176v1 }, + { "c2tnb191v1", NID_X9_62_c2tnb191v1 }, + { "c2tnb191v2", NID_X9_62_c2tnb191v2 }, + { "c2tnb191v3", NID_X9_62_c2tnb191v3 }, + { "c2pnb208w1", NID_X9_62_c2pnb208w1 }, + { "c2tnb239v1", NID_X9_62_c2tnb239v1 }, + { "c2tnb239v2", NID_X9_62_c2tnb239v2 }, + { "c2tnb239v3", NID_X9_62_c2tnb239v3 }, + { "c2pnb272w1", NID_X9_62_c2pnb272w1 }, + { "c2pnb304w1", NID_X9_62_c2pnb304w1 }, + { "c2tnb359v1", NID_X9_62_c2tnb359v1 }, + { "c2pnb368w1", NID_X9_62_c2pnb368w1 }, + { "c2tnb431r1", NID_X9_62_c2tnb431r1 }, + /* the WAP/WTLS curves + * [unlike SECG, spec has its own OIDs for curves from X9.62] */ + { "wtls1", NID_wap_wsg_idm_ecid_wtls1 }, + { "wtls3", NID_wap_wsg_idm_ecid_wtls3 }, + { "wtls4", NID_wap_wsg_idm_ecid_wtls4 }, + { "wtls5", NID_wap_wsg_idm_ecid_wtls5 }, + { "wtls6", NID_wap_wsg_idm_ecid_wtls6 }, + { "wtls7", NID_wap_wsg_idm_ecid_wtls7 }, + { "wtls8", NID_wap_wsg_idm_ecid_wtls8 }, + { "wtls9", NID_wap_wsg_idm_ecid_wtls9 }, + { "wtls10", NID_wap_wsg_idm_ecid_wtls10 }, + { "wtls11", NID_wap_wsg_idm_ecid_wtls11 }, + { "wtls12", NID_wap_wsg_idm_ecid_wtls12 }, + /* IPSec curves */ + { "ipsec3", NID_ipsec3 }, + { "ipsec4", NID_ipsec4 } +}; + +#define EC_CURVES_CNT (sizeof(ec_curves)/sizeof(struct nid_map)) + +struct nif_ec_key { + EC_KEY *key; }; +#endif ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload) @@ -368,6 +496,7 @@ 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; @@ -386,6 +515,19 @@ static ERL_NIF_TERM atom_none; static ERL_NIF_TERM atom_notsup; static ERL_NIF_TERM atom_digest; +static ERL_NIF_TERM atom_ec; + +#if defined(HAVE_EC) +static ERL_NIF_TERM atom_prime_field; +static ERL_NIF_TERM atom_characteristic_two_field; +static ERL_NIF_TERM atom_tpbasis; +static ERL_NIF_TERM atom_ppbasis; +static ERL_NIF_TERM atom_onbasis; + +static ErlNifResourceType* res_type_ec_key; +static void ec_key_dtor(ErlNifEnv* env, void* obj); +#endif + /* #define PRINTF_ERR0(FMT) enif_fprintf(stderr, FMT "\n") #define PRINTF_ERR1(FMT, A1) enif_fprintf(stderr, FMT "\n", A1) @@ -415,6 +557,7 @@ static void error_handler(void* null, const char* errstr) static int init(ErlNifEnv* env, ERL_NIF_TERM load_info) { + int i; ErlNifSysInfo sys_info; get_crypto_callbacks_t* funcp; struct crypto_callbacks* ccb; @@ -448,6 +591,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info) 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"); @@ -466,6 +610,23 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info) atom_notsup = enif_make_atom(env,"notsup"); atom_digest = enif_make_atom(env,"digest"); +#if defined(HAVE_EC) + atom_ec = enif_make_atom(env,"ec"); + atom_prime_field = enif_make_atom(env,"prime_field"); + atom_characteristic_two_field = enif_make_atom(env,"characteristic_two_field"); + atom_tpbasis = enif_make_atom(env,"tpbasis"); + atom_ppbasis = enif_make_atom(env,"ppbasis"); + atom_onbasis = enif_make_atom(env,"onbasis"); + + for (i = 0; i < EC_CURVES_CNT; i++) + ec_curves[i].atom = enif_make_atom(env,ec_curves[i].name); + + res_type_ec_key = enif_open_resource_type(env,NULL,"crypto.EC_KEY", + ec_key_dtor, + ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, + NULL); +#endif + init_digest_types(env); init_algorithms_types(); @@ -549,12 +710,12 @@ static void unload(ErlNifEnv* env, void* priv_data) } static int algos_cnt; -static ERL_NIF_TERM algos[7]; /* increase when extending the list */ +static ERL_NIF_TERM algos[9]; /* increase when extending the list */ static void init_algorithms_types(void) { algos_cnt = 0; - + algos[algos_cnt++] = atom_md4; algos[algos_cnt++] = atom_md5; algos[algos_cnt++] = atom_sha; algos[algos_cnt++] = atom_ripemd160; @@ -570,6 +731,9 @@ static void init_algorithms_types(void) #ifdef HAVE_SHA512 algos[algos_cnt++] = atom_sha512; #endif +#if defined(HAVE_EC) + algos[algos_cnt++] = atom_ec; +#endif } static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -1631,13 +1795,7 @@ static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg return ret; } -static int inspect_mpint(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifBinary* bin) -{ - return enif_inspect_binary(env, term, bin) && - bin->size >= 4 && get_int32(bin->data) == bin->size-4; -} - -static ERL_NIF_TERM dss_verify(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[]) {/* (DigestType|none, Data|{digest,Digest}, Signature,Key=[P, Q, G, Y]) */ ErlNifBinary data_bin, sign_bin; BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_y = NULL; @@ -1660,10 +1818,10 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv digest = data_bin.data; } else { - if (!inspect_mpint(env, argv[1], &data_bin)) { + if (!enif_inspect_binary(env, argv[1], &data_bin)) { return enif_make_badarg(env); } - SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); + SHA1(data_bin.data, data_bin.size, hmacbuf); digest = hmacbuf; } } @@ -1675,15 +1833,15 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv return enif_make_badarg(env); } - if (!inspect_mpint(env, argv[2], &sign_bin) + if (!enif_inspect_binary(env, argv[2], &sign_bin) || !enif_get_list_cell(env, argv[3], &head, &tail) - || !get_bn_from_mpint(env, head, &dsa_p) + || !get_bn_from_bin(env, head, &dsa_p) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa_q) + || !get_bn_from_bin(env, head, &dsa_q) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa_g) + || !get_bn_from_bin(env, head, &dsa_g) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa_y) + || !get_bn_from_bin(env, head, &dsa_y) || !enif_is_empty_list(env,tail)) { if (dsa_p) BN_free(dsa_p); @@ -1700,7 +1858,7 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv dsa->priv_key = NULL; dsa->pub_key = dsa_y; i = DSA_verify(0, digest, SHA_DIGEST_LENGTH, - sign_bin.data+4, sign_bin.size-4, dsa); + sign_bin.data, sign_bin.size, dsa); DSA_free(dsa); return(i > 0) ? atom_true : atom_false; } @@ -1826,11 +1984,11 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM rsa = RSA_new(); - if (!inspect_mpint(env, argv[2], &sign_bin) + if (!enif_inspect_binary(env, argv[2], &sign_bin) || !enif_get_list_cell(env, argv[3], &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->e) + || !get_bn_from_bin(env, head, &rsa->e) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->n) + || !get_bn_from_bin(env, head, &rsa->n) || !enif_is_empty_list(env, tail)) { ret = enif_make_badarg(env); @@ -1846,9 +2004,9 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM } digest = data_bin.data; } - else if (inspect_mpint(env, argv[1], &data_bin)) { + else if (enif_inspect_binary(env, argv[1], &data_bin)) { digest = hmacbuf; - digp->funcp(data_bin.data+4, data_bin.size-4, digest); + digp->funcp(data_bin.data, data_bin.size, digest); } else { ret = enif_make_badarg(env); @@ -1856,7 +2014,7 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM } i = RSA_verify(digp->NID_type, digest, digp->len, - sign_bin.data+4, sign_bin.size-4, rsa); + sign_bin.data, sign_bin.size, rsa); ret = (i==1 ? atom_true : atom_false); @@ -2001,22 +2159,22 @@ static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa) ERL_NIF_TERM head, tail; if (!enif_get_list_cell(env, key, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->e) + || !get_bn_from_bin(env, head, &rsa->e) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->n) + || !get_bn_from_bin(env, head, &rsa->n) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->d) + || !get_bn_from_bin(env, head, &rsa->d) || (!enif_is_empty_list(env, tail) && (!enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->p) + || !get_bn_from_bin(env, head, &rsa->p) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->q) + || !get_bn_from_bin(env, head, &rsa->q) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->dmp1) + || !get_bn_from_bin(env, head, &rsa->dmp1) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->dmq1) + || !get_bn_from_bin(env, head, &rsa->dmq1) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->iqmp) + || !get_bn_from_bin(env, head, &rsa->iqmp) || !enif_is_empty_list(env, tail)))) { return 0; } @@ -2053,11 +2211,11 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar digest = data_bin.data; } else { - if (!inspect_mpint(env,argv[1],&data_bin)) { + if (!enif_inspect_binary(env,argv[1],&data_bin)) { return enif_make_badarg(env); } digest = hmacbuf; - digp->funcp(data_bin.data+4, data_bin.size-4, digest); + digp->funcp(data_bin.data, data_bin.size, digest); } rsa = RSA_new(); @@ -2112,10 +2270,10 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar digest = data_bin.data; } else { - if (!inspect_mpint(env,argv[1],&data_bin)) { + if (!enif_inspect_binary(env,argv[1],&data_bin)) { return enif_make_badarg(env); } - SHA1(data_bin.data+4, data_bin.size-4, hmacbuf); + SHA1(data_bin.data, data_bin.size, hmacbuf); digest = hmacbuf; } } @@ -2133,13 +2291,13 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar dsa->pub_key = NULL; if (!enif_get_list_cell(env, argv[2], &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->p) + || !get_bn_from_bin(env, head, &dsa->p) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->q) + || !get_bn_from_bin(env, head, &dsa->q) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->g) + || !get_bn_from_bin(env, head, &dsa->g) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dsa->priv_key) + || !get_bn_from_bin(env, head, &dsa->priv_key) || !enif_is_empty_list(env,tail)) { DSA_free(dsa); return enif_make_badarg(env); @@ -2187,9 +2345,9 @@ static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TER if (!enif_inspect_binary(env, argv[0], &data_bin) || !enif_get_list_cell(env, argv[1], &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->e) + || !get_bn_from_bin(env, head, &rsa->e) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &rsa->n) + || !get_bn_from_bin(env, head, &rsa->n) || !enif_is_empty_list(env,tail) || !rsa_pad(argv[2], &padding)) { @@ -2286,14 +2444,12 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E } p_len = BN_num_bytes(dh_params->p); g_len = BN_num_bytes(dh_params->g); - p_ptr = enif_make_new_binary(env, p_len+4, &ret_p); - g_ptr = enif_make_new_binary(env, g_len+4, &ret_g); - put_int32(p_ptr, p_len); - put_int32(g_ptr, g_len); - BN_bn2bin(dh_params->p, p_ptr+4); - BN_bn2bin(dh_params->g, g_ptr+4); - ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr+4, p_len); - ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr+4, g_len); + p_ptr = enif_make_new_binary(env, p_len, &ret_p); + g_ptr = enif_make_new_binary(env, g_len, &ret_g); + BN_bn2bin(dh_params->p, p_ptr); + BN_bn2bin(dh_params->g, g_ptr); + ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr, p_len); + ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr, g_len); DH_free(dh_params); return enif_make_list2(env, ret_p, ret_g); } @@ -2305,9 +2461,9 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] ERL_NIF_TERM ret, head, tail; if (!enif_get_list_cell(env, argv[0], &head, &tail) - || !get_bn_from_mpint(env, head, &dh_params->p) + || !get_bn_from_bin(env, head, &dh_params->p) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dh_params->g) + || !get_bn_from_bin(env, head, &dh_params->g) || !enif_is_empty_list(env,tail)) { DH_free(dh_params); @@ -2329,19 +2485,21 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] } static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (PrivKey, DHParams=[P,G]) */ +{/* (PrivKey, DHParams=[P,G], Mpint) */ DH* dh_params = DH_new(); int pub_len, prv_len; unsigned char *pub_ptr, *prv_ptr; ERL_NIF_TERM ret, ret_pub, ret_prv, head, tail; + int mpint; /* 0 or 4 */ - if (!(get_bn_from_mpint(env, argv[0], &dh_params->priv_key) + if (!(get_bn_from_bin(env, argv[0], &dh_params->priv_key) || argv[0] == atom_undefined) || !enif_get_list_cell(env, argv[1], &head, &tail) - || !get_bn_from_mpint(env, head, &dh_params->p) + || !get_bn_from_bin(env, head, &dh_params->p) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dh_params->g) - || !enif_is_empty_list(env, tail)) { + || !get_bn_from_bin(env, head, &dh_params->g) + || !enif_is_empty_list(env, tail) + || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4)) { DH_free(dh_params); return enif_make_badarg(env); } @@ -2349,14 +2507,16 @@ static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_ if (DH_generate_key(dh_params)) { pub_len = BN_num_bytes(dh_params->pub_key); prv_len = BN_num_bytes(dh_params->priv_key); - pub_ptr = enif_make_new_binary(env, pub_len+4, &ret_pub); - prv_ptr = enif_make_new_binary(env, prv_len+4, &ret_prv); - put_int32(pub_ptr, pub_len); - put_int32(prv_ptr, prv_len); - BN_bn2bin(dh_params->pub_key, pub_ptr+4); - BN_bn2bin(dh_params->priv_key, prv_ptr+4); - ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr+4, pub_len); - ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr+4, prv_len); + pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub); + prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv); + if (mpint) { + put_int32(pub_ptr, pub_len); pub_ptr += 4; + put_int32(prv_ptr, prv_len); prv_ptr += 4; + } + BN_bn2bin(dh_params->pub_key, pub_ptr); + BN_bn2bin(dh_params->priv_key, prv_ptr); + ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len); + ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len); ret = enif_make_tuple2(env, ret_pub, ret_prv); } else { @@ -2374,12 +2534,12 @@ 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; - if (!get_bn_from_mpint(env, argv[0], &pubkey) - || !get_bn_from_mpint(env, argv[1], &dh_params->priv_key) + if (!get_bn_from_bin(env, argv[0], &pubkey) + || !get_bn_from_bin(env, argv[1], &dh_params->priv_key) || !enif_get_list_cell(env, argv[2], &head, &tail) - || !get_bn_from_mpint(env, head, &dh_params->p) + || !get_bn_from_bin(env, head, &dh_params->p) || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_mpint(env, head, &dh_params->g) + || !get_bn_from_bin(env, head, &dh_params->g) || !enif_is_empty_list(env, tail)) { ret = enif_make_badarg(env); @@ -2457,7 +2617,7 @@ static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM return ret; } -static ERL_NIF_TERM srp_client_secret_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[]) {/* (a, u, B, Multiplier, Prime, Exponent, Generator) */ /* <premaster secret> = (B - (k * g^x)) ^ (a + (u * x)) % N @@ -2537,7 +2697,7 @@ static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NI return ret; } -static ERL_NIF_TERM srp_server_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[]) {/* (Verifier, b, u, A, Prime) */ /* <premaster secret> = (A * v^u) ^ b % N @@ -2686,7 +2846,554 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N return ret; } +#if defined(HAVE_EC) +static int term2curve_id(ERL_NIF_TERM nid) +{ + int i; + + for (i = 0; i < EC_CURVES_CNT; i++) + if (ec_curves[i].atom == nid) + return ec_curves[i].nid; + + return 0; +} +static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg) +{ + EC_KEY *key = NULL; + int nid = 0; + int c_arity = -1; + const ERL_NIF_TERM* curve; + ErlNifBinary seed; + BIGNUM *p = NULL; + BIGNUM *a = NULL; + BIGNUM *b = NULL; + BIGNUM *bn_order = NULL; + BIGNUM *cofactor = NULL; + EC_GROUP *group = NULL; + EC_POINT *point = NULL; + + if (enif_is_atom(env, curve_arg)) { + nid = term2curve_id(curve_arg); + if (nid == 0) + return NULL; + key = EC_KEY_new_by_curve_name(nid); + } + else if (enif_is_tuple(env, curve_arg) + && enif_get_tuple(env,curve_arg,&c_arity,&curve) + && c_arity == 5 + && get_bn_from_bin(env, curve[3], &bn_order) + && (curve[4] != atom_none && get_bn_from_bin(env, curve[4], &cofactor))) { + //* {Field, Prime, Point, Order, CoFactor} = Curve */ + + int f_arity = -1; + const ERL_NIF_TERM* field; + int p_arity = -1; + const ERL_NIF_TERM* prime; + + long field_bits; + + /* {A, B, Seed} = Prime */ + if (!enif_get_tuple(env,curve[1],&p_arity,&prime) + || !get_bn_from_bin(env, prime[0], &a) + || !get_bn_from_bin(env, prime[1], &b)) + goto out_err; + + if (!enif_get_tuple(env,curve[0],&f_arity,&field)) + goto out_err; + + if (f_arity == 2 && field[0] == atom_prime_field) { + /* {prime_field, Prime} */ + + if (!get_bn_from_bin(env, field[1], &p)) + goto out_err; + + if (BN_is_negative(p) || BN_is_zero(p)) + goto out_err; + + field_bits = BN_num_bits(p); + if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS) + goto out_err; + + /* create the EC_GROUP structure */ + group = EC_GROUP_new_curve_GFp(p, a, b, NULL); + + } else if (f_arity == 3 && field[0] == atom_characteristic_two_field) { + /* {characteristic_two_field, M, Basis} */ + + int b_arity = -1; + const ERL_NIF_TERM* basis; + unsigned int k1, k2, k3; + + if ((p = BN_new()) == NULL) + goto out_err; + + if (!enif_get_long(env, field[1], &field_bits) + || field_bits > OPENSSL_ECC_MAX_FIELD_BITS) + goto out_err; + + if (enif_get_tuple(env,field[2],&b_arity,&basis)) { + if (b_arity == 2 + && basis[0] == atom_tpbasis + && enif_get_uint(env, basis[1], &k1)) { + /* {tpbasis, k} = Basis */ + + if (!(field_bits > k1 && k1 > 0)) + goto out_err; + + /* create the polynomial */ + if (!BN_set_bit(p, (int)field_bits) + || !BN_set_bit(p, (int)k1) + || !BN_set_bit(p, 0)) + goto out_err; + + } else if (b_arity == 4 + && basis[0] == atom_ppbasis + && enif_get_uint(env, basis[1], &k1) + && enif_get_uint(env, basis[2], &k2) + && enif_get_uint(env, basis[3], &k3)) { + /* {ppbasis, k1, k2, k3} = Basis */ + + if (!(field_bits > k3 && k3 > k2 && k2 > k1 && k1 > 0)) + goto out_err; + + /* create the polynomial */ + if (!BN_set_bit(p, (int)field_bits) + || !BN_set_bit(p, (int)k1) + || !BN_set_bit(p, (int)k2) + || !BN_set_bit(p, (int)k3) + || !BN_set_bit(p, 0)) + goto out_err; + + } else + goto out_err; + } else if (field[2] == atom_onbasis) { + /* onbasis = Basis */ + /* no parameters */ + goto out_err; + + } else + goto out_err; + + group = EC_GROUP_new_curve_GF2m(p, a, b, NULL); + } else + goto out_err; + + if (enif_inspect_binary(env, prime[2], &seed)) { + EC_GROUP_set_seed(group, seed.data, seed.size); + } + + if (!term2point(env, curve[2], group, &point)) + goto out_err; + + if (BN_is_negative(bn_order) + || BN_is_zero(bn_order) + || BN_num_bits(bn_order) > (int)field_bits + 1) + goto out_err; + + if (!EC_GROUP_set_generator(group, point, bn_order, cofactor)) + goto out_err; + + EC_GROUP_set_asn1_flag(group, 0x0); + + key = EC_KEY_new(); + if (!key) + goto out_err; + EC_KEY_set_group(key, group); + } + else { + goto out_err; + } + + + goto out; + +out_err: + if (key) EC_KEY_free(key); + key = NULL; + +out: + /* some OpenSSL structures are mem-dup'ed into the key, + so we have to free our copies here */ + if (p) BN_free(p); + if (a) BN_free(a); + if (b) BN_free(b); + if (bn_order) BN_free(bn_order); + if (cofactor) BN_free(cofactor); + if (group) EC_GROUP_free(group); + + return key; +} + + +static ERL_NIF_TERM bn2term(ErlNifEnv* env, const BIGNUM *bn) +{ + unsigned dlen; + unsigned char* ptr; + ERL_NIF_TERM ret; + + if (!bn) + return atom_undefined; + + dlen = BN_num_bytes(bn); + ptr = enif_make_new_binary(env, dlen, &ret); + BN_bn2bin(bn, ptr); + + return ret; +} + +static ERL_NIF_TERM point2term(ErlNifEnv* env, + const EC_GROUP *group, + const EC_POINT *point, + point_conversion_form_t form) +{ + unsigned dlen; + ErlNifBinary bin; + + dlen = EC_POINT_point2oct(group, point, form, NULL, 0, NULL); + if (dlen == 0) + return atom_undefined; + + if (!enif_alloc_binary(dlen, &bin)) + return enif_make_badarg(env); + + if (!EC_POINT_point2oct(group, point, form, bin.data, bin.size, NULL)) { + enif_release_binary(&bin); + return enif_make_badarg(env); + } + + return enif_make_binary(env, &bin); +} +#endif + +static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#if defined(HAVE_EC) + struct nif_ec_key *obj; + const EC_GROUP *group; + const EC_POINT *public_key; + const BIGNUM *priv_key = NULL; + ERL_NIF_TERM pub_key = atom_undefined; + + if (!enif_get_resource(env, argv[0], res_type_ec_key, (void **)&obj)) + return enif_make_badarg(env); + + group = EC_KEY_get0_group(obj->key); + public_key = EC_KEY_get0_public_key(obj->key); + priv_key = EC_KEY_get0_private_key(obj->key); + + if (group) { + if (public_key) + pub_key = point2term(env, group, public_key, EC_KEY_get_conv_form(obj->key)); + } + + return enif_make_tuple2(env, bn2term(env, priv_key), pub_key); +#else + return atom_notsup; +#endif +} + +#if defined(HAVE_EC) +static int term2point(ErlNifEnv* env, ERL_NIF_TERM term, + EC_GROUP *group, EC_POINT **pptr) +{ + int ret = 0; + ErlNifBinary bin; + EC_POINT *point; + + if (!enif_inspect_binary(env,term,&bin)) { + return 0; + } + + if ((*pptr = point = EC_POINT_new(group)) == NULL) { + return 0; + } + + /* set the point conversion form */ + EC_GROUP_set_point_conversion_form(group, (point_conversion_form_t)(bin.data[0] & ~0x01)); + + /* extract the ec point */ + if (!EC_POINT_oct2point(group, point, bin.data, bin.size, NULL)) { + EC_POINT_free(point); + *pptr = NULL; + } else + ret = 1; + + return ret; +} +#endif + +static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#if defined(HAVE_EC) + ERL_NIF_TERM ret; + EC_KEY *key = NULL; + BIGNUM *priv_key = NULL; + EC_POINT *pub_key = NULL; + struct nif_ec_key *obj; + EC_GROUP *group = NULL; + + if (!(argv[1] == atom_undefined || get_bn_from_bin(env, argv[1], &priv_key)) + || !(argv[2] == atom_undefined || enif_is_binary(env, argv[2]))) { + goto out_err; + } + + key = ec_key_new(env, argv[0]); + + if (!key) { + goto out_err; + } + + if (!group) + group = EC_GROUP_dup(EC_KEY_get0_group(key)); + + if (term2point(env, argv[2], group, &pub_key)) { + if (!EC_KEY_set_public_key(key, pub_key)) { + goto out_err; + } + } + if (argv[1] != atom_undefined + && !BN_is_zero(priv_key)) { + if (!EC_KEY_set_private_key(key, priv_key)) + goto out_err; + + /* calculate public key (if necessary) */ + if (EC_KEY_get0_public_key(key) == NULL) + { + /* the public key was not included in the SEC1 private + * key => calculate the public key */ + pub_key = EC_POINT_new(group); + if (pub_key == NULL + || !EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group)) + || !EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL) + || !EC_KEY_set_public_key(key, pub_key)) + goto out_err; + } + } + + obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key)); + if (!obj) + goto out_err; + + obj->key = key; + ret = enif_make_resource(env, obj); + enif_release_resource(obj); + + goto out; + +out_err: + if (key) EC_KEY_free(key); + ret = enif_make_badarg(env); + +out: + /* some OpenSSL structures are mem-dup'ed into the key, + so we have to free our copies here */ + if (priv_key) BN_clear_free(priv_key); + if (pub_key) EC_POINT_free(pub_key); + if (group) EC_GROUP_free(group); + return ret; +#else + return atom_notsup; +#endif +} + +static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#if defined(HAVE_EC) + EC_KEY *key = ec_key_new(env, argv[0]); + + if (key && EC_KEY_generate_key(key)) { + ERL_NIF_TERM term; + struct nif_ec_key *obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key)); + if (!obj) + return atom_error; + obj->key = key; + term = enif_make_resource(env, obj); + enif_release_resource(obj); + return term; + } + else + return enif_make_badarg(env); +#else + return atom_notsup; +#endif +} + +#if defined(HAVE_EC) +static void ec_key_dtor(ErlNifEnv* env, void* obj) +{ + struct nif_ec_key *key = (struct nif_ec_key*) obj; + EC_KEY_free(key->key); +} +#endif + +static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Type, Data|{digest,Digest}, Key) */ +#if defined(HAVE_EC) + ErlNifBinary data_bin, ret_bin; + unsigned char hmacbuf[SHA_DIGEST_LENGTH]; + unsigned int dsa_s_len; + struct nif_ec_key *obj; + int i; + const ERL_NIF_TERM* tpl_terms; + int tpl_arity; + struct digest_type_t *digp; + unsigned char* digest; + + digp = get_digest_type(argv[0]); + if (!digp) { + return enif_make_badarg(env); + } + if (!digp->len) { + return atom_notsup; + } + + if (!enif_get_resource(env, argv[2], res_type_ec_key, (void **)&obj)) + return enif_make_badarg(env); + + 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); + } + + enif_alloc_binary(ECDSA_size(obj->key), &ret_bin); + + i = ECDSA_sign(digp->NID_type, digest, digp->len, + ret_bin.data, &dsa_s_len, obj->key); + if (i) { + if (dsa_s_len != ret_bin.size) { + enif_realloc_binary(&ret_bin, dsa_s_len); + } + return enif_make_binary(env, &ret_bin); + } + else { + enif_release_binary(&ret_bin); + return atom_error; + } +#else + return atom_notsup; +#endif +} + +static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Type, Data|{digest,Digest}, Signature, Key) */ +#if defined(HAVE_EC) + ErlNifBinary data_bin, sign_bin; + unsigned char hmacbuf[SHA512_LEN]; + int i; + struct nif_ec_key *obj; + 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; + + digp = get_digest_type(type); + if (!digp) { + return enif_make_badarg(env); + } + if (!digp->len) { + return atom_notsup; + } + + if (!enif_inspect_binary(env, argv[2], &sign_bin) + || !enif_get_resource(env, argv[3], res_type_ec_key, (void **)&obj)) + return enif_make_badarg(env); + + 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)) { + digest = hmacbuf; + digp->funcp(data_bin.data, data_bin.size, digest); + } + else { + return enif_make_badarg(env); + } + + i = ECDSA_verify(digp->NID_type, digest, digp->len, + sign_bin.data, sign_bin.size, obj->key); + + return (i==1 ? atom_true : atom_false); +#else + return atom_notsup; +#endif +} + +/* + (_OthersPublicKey, _MyPrivateKey) + (_OthersPublicKey, _MyEC_Point) +*/ +static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#if defined(HAVE_EC) + ERL_NIF_TERM ret; + unsigned char *p; + struct nif_ec_key *other_key; + int field_size = 0; + int i; + + EC_GROUP *group; + const BIGNUM *priv_key; + EC_POINT *my_ecpoint; + EC_KEY *other_ecdh = NULL; + + if (!enif_get_resource(env, argv[1], res_type_ec_key, (void **)&other_key)) + return enif_make_badarg(env); + + group = EC_GROUP_dup(EC_KEY_get0_group(other_key->key)); + priv_key = EC_KEY_get0_private_key(other_key->key); + + if (!term2point(env, argv[0], group, &my_ecpoint)) { + goto out_err; + } + + if ((other_ecdh = EC_KEY_new()) == NULL + || !EC_KEY_set_group(other_ecdh, group) + || !EC_KEY_set_private_key(other_ecdh, priv_key)) + goto out_err; + + field_size = EC_GROUP_get_degree(group); + if (field_size <= 0) + goto out_err; + + p = enif_make_new_binary(env, (field_size+7)/8, &ret); + i = ECDH_compute_key(p, (field_size+7)/8, my_ecpoint, other_ecdh, NULL); + + if (i < 0) + goto out_err; +out: + if (group) EC_GROUP_free(group); + if (my_ecpoint) EC_POINT_free(my_ecpoint); + if (other_ecdh) EC_KEY_free(other_ecdh); + + return ret; + +out_err: + ret = enif_make_badarg(env); + goto out; +#else + return atom_notsup; +#endif +} /* HMAC */ diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 7eca4557d9..df765ade87 100755..100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -22,263 +22,222 @@ </legalnotice> <title>crypto</title> - <prepared>Peter Högfeldt</prepared> - <docno></docno> - <date>2000-06-20</date> - <rev>B</rev> </header> <module>crypto</module> <modulesummary>Crypto Functions</modulesummary> <description> <p>This module provides a set of cryptographic functions. </p> - <p>References:</p> <list type="bulleted"> <item> - <p>md4: The MD4 Message Digest Algorithm (RFC 1320)</p> - </item> - <item> - <p>md5: The MD5 Message Digest Algorithm (RFC 1321)</p> - </item> - <item> - <p>sha: Secure Hash Standard (FIPS 180-2)</p> - </item> - <item> - <p>hmac: Keyed-Hashing for Message Authentication (RFC 2104)</p> - </item> - <item> - <p>des: Data Encryption Standard (FIPS 46-3)</p> + <p>Hash functions - + <url href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf"> Secure Hash Standard</url>, + <url href="http://www.ietf.org/rfc/rfc1321.txt"> The MD5 Message Digest Algorithm (RFC 1321)</url> and + <url href="http://www.ietf.org/rfc/rfc1320.txt">The MD4 Message Digest Algorithm (RFC 1320)</url> + </p> </item> <item> - <p>aes: Advanced Encryption Standard (AES) (FIPS 197) </p> + <p>Hmac functions - <url href="http://www.ietf.org/rfc/rfc2104.txt"> Keyed-Hashing for Message Authentication (RFC 2104) </url></p> </item> <item> - <p>ecb, cbc, cfb, ofb, ctr: Recommendation for Block Cipher Modes - of Operation (NIST SP 800-38A).</p> + <p>Block ciphers - <url href="http://csrc.nist.gov/groups/ST/toolkit/block_ciphers.html"> </url> DES and AES in + Block Cipher Modes - <url href="http://csrc.nist.gov/groups/ST/toolkit/BCM/index.html"> ECB, CBC, CFB, OFB and CTR </url></p> </item> <item> - <p>rsa: Recommendation for Block Cipher Modes of Operation - (NIST 800-38A)</p> + <p><url href="http://www.ietf.org/rfc/rfc1321.txt"> RSA encryption RFC 1321 </url> </p> </item> <item> - <p>dss: Digital Signature Standard (FIPS 186-2)</p> + <p>Digital signatures <url href="http://csrc.nist.gov/publications/drafts/fips186-3/fips_186-3.pdf">Digital Signature Standard (DSS)</url> and<url href="http://csrc.nist.gov/groups/STM/cavp/documents/dss2/ecdsa2vs.pdf"> Elliptic Curve Digital + Signature Algorithm (ECDSA) </url> </p> </item> <item> - <p>srp: Secure Remote Password Protocol (RFC 2945)</p> + <p><url href="http://www.ietf.org/rfc/rfc2945.txt"> Secure Remote Password Protocol (SRP - RFC 2945) </url></p> </item> - - </list> - <p>The above publications can be found at <url href="http://csrc.nist.gov/publications">NIST publications</url>, at <url href="http://www.ietf.org">IETF</url>. - </p> - <p><em>Types</em></p> - <pre> -byte() = 0 ... 255 -ioelem() = byte() | binary() | iolist() -iolist() = [ioelem()] -Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> - </pre> - <p></p> </description> + + <section> + <title>DATA TYPES </title> + + <p><code>key_value() = integer() | binary() </code></p> + + <p><code>rsa_public() = [key_value()] = [E, N] </code></p> + <p> Where E is the public exponent and N is public modulus. </p> + + <p><code>rsa_private() = [key_value()] = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] </code></p> + <p>Where E is the public exponent, N is public modulus and D is + the private exponent.The longer key format contains redundant + information that will make the calculation faster. P1,P2 are first + and second prime factors. E1,E2 are first and second exponents. C + is the CRT coefficient. Terminology is taken from <url href="http://www.ietf.org/rfc/rfc3477.txt"> RFC 3447</url>.</p> + + <p><code>dss_public() = [key_value()] = [P, Q, G, Y] </code></p> + <p>Where P, Q and G are the dss parameters and Y is the public key.</p> + + <p><code>dss_private() = [key_value()] = [P, Q, G, X] </code></p> + <p>Where P, Q and G are the dss parameters and X is the private key.</p> + + <p><code>dss_public() = [key_value()] =[P, Q, G, Y] </code></p> + + <p><code>srp_public() = key_value() </code></p> + <p>Where is <c>A</c> or <c>B</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p> + + <p><code>srp_private() = key_value() </code></p> + <p>Where is <c>a</c> or <c>b</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p> + + <p><code>srp_params() = {user, [Generator::binary(), Prime::binary(), Version::atom()]} | + {host, [Verifier::binary(), Generator::binary(), Prime::binary(), Version::atom()]} + | {user, [DerivedKey::binary(), Prime::binary(), Generator::binary(), Version::atom() | [Scrambler:binary()]]} + | {host,[Verifier::binary(), Prime::binary(), Version::atom() | [Scrambler::binary]]} </code></p> + + <p>Where Verifier is <c>v</c>, Generator is <c>g</c> and Prime is<c> N</c>, DerivedKey is <c>X</c>, and Scrambler is + <c>u</c> (optional will be genrated if not provided) from <url href="http://srp.stanford.edu/design.html">SRP design</url> + Version = '3' | '6' | '6a' + </p> + + <p><code>dh_public() = key_value() </code></p> + + <p><code>dh_private() = key_value() </code></p> + + <p><code>dh_params() = [key_value()] = [P, G] </code></p> + + <p><code>ecdh_public() = key_value() </code></p> + + <p><code>ecdh_private() = key_value() </code></p> + + <p><code>ecdh_params() = ec_named_curve() | + {ec_field(), Prime :: key_value(), Point :: key_value(), Order :: integer(), CoFactor :: none | integer()} </code></p> + + <p><code>ec_field() = {prime_field, Prime :: integer()} | + {characteristic_two_field, M :: integer(), Basis :: ec_basis()}</code></p> + + <p><code>ec_basis() = {tpbasis, K :: non_neg_integer()} | + {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | + onbasis</code></p> + + <p><code>ec_named_curve() -> + sect571r1| sect571k1| sect409r1| sect409k1| secp521r1| secp384r1| secp224r1| secp224k1| + secp192k1| secp160r2| secp128r2| secp128r1| sect233r1| sect233k1| sect193r2| sect193r1| + sect131r2| sect131r1| sect283r1| sect283k1| sect163r2| secp256k1| secp160k1| secp160r1| + secp112r2| secp112r1| sect113r2| sect113r1| sect239k1| sect163r1| sect163k1| secp256r1| + secp192r1 </code></p> + + <p><code>stream_cipher() = rc4 | aes_ctr </code></p> + + <p><code>block_cipher() = aes_cbc128 | aes_cfb128 | blowfish_cbc | + blowfish_cfb64 | des_cbc | des_cfb | des3_cbc | des3_cbf + | des_ede3 | rc2_cbc </code></p> + + <p><code>stream_key() = aes_key() | rc4_key() </code></p> + + <p><code>block_key() = aes_key() | blowfish_key() | des_key()| des3_key() </code></p> + + <p><code>aes_key() = iodata() </code> Key length is 128, 192 or 256 bits</p> + + <p><code>rc4_key() = iodata() </code> Variable key length from 8 bits up to 2048 bits (usually between 40 and 256)</p> + + <p><code>blowfish_key() = iodata() </code> Variable key length from 32 bits up to 448 bits</p> + + <p><code>des_key() = iodata() </code> Key length is 64 bits (in CBC mode only 8 bits are used)</p> + + <p><code>des3_key() = [binary(), binary(), binary()] </code> Each key part is 64 bits (in CBC mode only 8 bits are used)</p> + + <p><code> message_digest_algorithms() = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 </code> md4 is aslo supported for hash_init/1 and hash/2. + Note that both md4 and md5 are recommended only for compatibility with existing applications. + </p> + </section> + <funcs> <func> - <name>start() -> ok</name> - <fsummary>Start the crypto server.</fsummary> - <desc> - <p>Starts the crypto server.</p> - </desc> - </func> - <func> - <name>stop() -> ok</name> - <fsummary>Stop the crypto server.</fsummary> - <desc> - <p>Stops the crypto server.</p> - </desc> - </func> - <func> - <name>info() -> [atom()]</name> - <fsummary>Provide a list of available crypto functions.</fsummary> - <desc> - <p>Provides the available crypto functions in terms of a list - of atoms.</p> - </desc> - </func> - <func> - <name>algorithms() -> [atom()]</name> + <name>algorithms() -> [message_digest_algorithms() | md4 | ec]</name> <fsummary>Provide a list of available crypto algorithms.</fsummary> <desc> - <p>Provides the available crypto algorithms in terms of a list - of atoms.</p> - </desc> - </func> - <func> - <name>info_lib() -> [{Name,VerNum,VerStr}]</name> - <fsummary>Provides information about the libraries used by crypto.</fsummary> - <type> - <v>Name = binary()</v> - <v>VerNum = integer()</v> - <v>VerStr = binary()</v> - </type> - <desc> - <p>Provides the name and version of the libraries used by crypto.</p> - <p><c>Name</c> is the name of the library. <c>VerNum</c> is - the numeric version according to the library's own versioning - scheme. <c>VerStr</c> contains a text variant of the version.</p> - <pre> -> <input>info_lib().</input> -[{<<"OpenSSL">>,9469983,<<"OpenSSL 0.9.8a 11 Oct 2005">>}] - </pre> - <note><p> - From OTP R16 the <em>numeric version</em> represents the version of the OpenSSL - <em>header files</em> (<c>openssl/opensslv.h</c>) used when crypto was compiled. - The text variant represents the OpenSSL library used at runtime. - In earlier OTP versions both numeric and text was taken from the library. - </p></note> - </desc> - </func> - <func> - <name>md4(Data) -> Digest</name> - <fsummary>Compute an <c>MD4</c>message digest from <c>Data</c></fsummary> - <type> - <v>Data = iolist() | binary()</v> - <v>Digest = binary()</v> - </type> - <desc> - <p>Computes an <c>MD4</c> message digest from <c>Data</c>, where - the length of the digest is 128 bits (16 bytes).</p> - </desc> - </func> - <func> - <name>md4_init() -> Context</name> - <fsummary>Creates an MD4 context</fsummary> - <type> - <v>Context = binary()</v> - </type> - <desc> - <p>Creates an MD4 context, to be used in subsequent calls to - <c>md4_update/2</c>.</p> - </desc> - </func> - <func> - <name>md4_update(Context, Data) -> NewContext</name> - <fsummary>Update an MD4 <c>Context</c>with <c>Data</c>, and return a <c>NewContext</c></fsummary> - <type> - <v>Data = iolist() | binary()</v> - <v>Context = NewContext = binary()</v> - </type> - <desc> - <p>Updates an MD4 <c>Context</c> with <c>Data</c>, and returns - a <c>NewContext</c>.</p> - </desc> - </func> - <func> - <name>md4_final(Context) -> Digest</name> - <fsummary>Finish the update of an MD4 <c>Context</c>and return the computed <c>MD4</c>message digest</fsummary> - <type> - <v>Context = Digest = binary()</v> - </type> - <desc> - <p>Finishes the update of an MD4 <c>Context</c> and returns - the computed <c>MD4</c> message digest.</p> - </desc> - </func> - <func> - <name>md5(Data) -> Digest</name> - <fsummary>Compute an <c>MD5</c>message digest from <c>Data</c></fsummary> - <type> - <v>Data = iolist() | binary()</v> - <v>Digest = binary()</v> - </type> - <desc> - <p>Computes an <c>MD5</c> message digest from <c>Data</c>, where - the length of the digest is 128 bits (16 bytes).</p> + <p> Can be used to determine if the crypto library has support for elliptic curve (ec) and + which message digest algorithms that are supported.</p> </desc> </func> - <func> - <name>md5_init() -> Context</name> - <fsummary>Creates an MD5 context</fsummary> - <type> - <v>Context = binary()</v> - </type> - <desc> - <p>Creates an MD5 context, to be used in subsequent calls to - <c>md5_update/2</c>.</p> - </desc> - </func> - <func> - <name>md5_update(Context, Data) -> NewContext</name> - <fsummary>Update an MD5 <c>Context</c>with <c>Data</c>, and return a <c>NewContext</c></fsummary> - <type> - <v>Data = iolist() | binary()</v> - <v>Context = NewContext = binary()</v> - </type> - <desc> - <p>Updates an MD5 <c>Context</c> with <c>Data</c>, and returns - a <c>NewContext</c>.</p> - </desc> - </func> - <func> - <name>md5_final(Context) -> Digest</name> - <fsummary>Finish the update of an MD5 <c>Context</c>and return the computed <c>MD5</c>message digest</fsummary> + + <func> + <name>block_encrypt(Type, Key, Ivec, PlainText) -> CipherText</name> + <fsummary>Encrypt <c>PlainText</c>according to <c>Type</c> block cipher</fsummary> <type> - <v>Context = Digest = binary()</v> + <v>Key = block_key() </v> + <v>PlainText = iodata() </v> + <v>IVec = CipherText = binary()</v> </type> <desc> - <p>Finishes the update of an MD5 <c>Context</c> and returns - the computed <c>MD5</c> message digest.</p> + <p>Encrypt <c>PlainText</c>according to <c>Type</c> block cipher. + <c>IVec</c> is an arbitrary initializing vector. + </p> </desc> </func> + <func> - <name>sha(Data) -> Digest</name> - <fsummary>Compute an <c>SHA</c>message digest from <c>Data</c></fsummary> + <name>block_decrypt(Type, Key, Ivec, CipherText) -> PlainText</name> + <fsummary>Decrypt <c>CipherText</c>according to <c>Type</c> block cipher</fsummary> <type> - <v>Data = iolist() | binary()</v> - <v>Digest = binary()</v> + <v>Key = block_key() </v> + <v>PlainText = iodata() </v> + <v>IVec = CipherText = binary()</v> </type> <desc> - <p>Computes an <c>SHA</c> message digest from <c>Data</c>, where - the length of the digest is 160 bits (20 bytes).</p> + <p>Decrypt <c>CipherText</c>according to <c>Type</c> block cipher. + <c>IVec</c> is an arbitrary initializing vector. + </p> </desc> </func> + <func> - <name>sha_init() -> Context</name> - <fsummary>Create an SHA context</fsummary> + <name>compute_key(Type, OthersPublicKey, MyPrivateKey, Params) -> SharedSecret</name> + <fsummary>Computes the shared secret</fsummary> <type> - <v>Context = binary()</v> + <v> Type = dh | ecdh | srp </v> + <v>OthersPublicKey = dh_public() | ecdh_public() | srp_public() </v> + <v>MyPrivate = dh_private() | ecdh_private() | srp_private() </v> + <v>Params = dh_params() | edhc_params() | srp_params() </v> + <v>SharedSecret = binary()</v> </type> <desc> - <p>Creates an SHA context, to be used in subsequent calls to - <c>sha_update/2</c>.</p> + <p>Computes the shared secret from the private key and the other party's public key. + See also <seealso marker="public_key:public_key#compute_key/2">public_key:compute_key/2</seealso> + </p> </desc> </func> + <func> - <name>sha_update(Context, Data) -> NewContext</name> - <fsummary>Update an SHA context</fsummary> + <name>exor(Data1, Data2) -> Result</name> + <fsummary>XOR data</fsummary> <type> - <v>Data = iolist() | binary()</v> - <v>Context = NewContext = binary()</v> + <v>Data1, Data2 = iodata()</v> + <v>Result = binary()</v> </type> <desc> - <p>Updates an SHA <c>Context</c> with <c>Data</c>, and returns - a <c>NewContext</c>.</p> + <p>Performs bit-wise XOR (exclusive or) on the data supplied.</p> </desc> </func> - <func> - <name>sha_final(Context) -> Digest</name> - <fsummary>Finish the update of an SHA context</fsummary> + + <func> + <name>generate_key(Type, Params) -> {PublicKey, PrivateKey} </name> + <name>generate_key(Type, Params, PrivateKey) -> {PublicKey, PrivateKey} </name> + <fsummary>Generates a public keys of type <c>Type</c></fsummary> <type> - <v>Context = Digest = binary()</v> + <v> Type = dh | ecdh | srp </v> + <v>Params = dh_params() | edhc_params() | srp_params() </v> + <v>PublicKey = dh_public() | ecdh_public() | srp_public() </v> + <v>PrivateKey = dh_private() | ecdh_private() | srp_private() </v> </type> <desc> - <p>Finishes the update of an SHA <c>Context</c> and returns - the computed <c>SHA</c> message digest.</p> + <p>Generates public keys of type <c>Type</c>. + See also <seealso marker="public_key:public_key#generate_key/1">public_key:generate_key/1</seealso> + </p> </desc> </func> - <func> + + <func> <name>hash(Type, Data) -> Digest</name> <fsummary></fsummary> <type> - <v>Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v> + <v>Type = md4 | message_digest_algorithms()</v> <v>Data = iodata()</v> <v>Digest = binary()</v> </type> @@ -288,11 +247,12 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> is not supported by the underlying OpenSSL implementation.</p> </desc> </func> + <func> <name>hash_init(Type) -> Context</name> <fsummary></fsummary> <type> - <v>Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v> + <v>Type = md4 | message_digest_algorithms()</v> </type> <desc> <p>Initializes the context for streaming hash operations. <c>Type</c> determines @@ -302,6 +262,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> is not supported by the underlying OpenSSL implementation.</p> </desc> </func> + <func> <name>hash_update(Context, Data) -> NewContext</name> <fsummary></fsummary> @@ -329,38 +290,13 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> function used to generate it.</p> </desc> </func> - <func> - <name>md5_mac(Key, Data) -> Mac</name> - <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary> - <type> - <v>Key = Data = iolist() | binary()</v> - <v>Mac = binary()</v> - </type> - <desc> - <p>Computes an <c>MD5 MAC</c> message authentification code - from <c>Key</c> and <c>Data</c>, where the the length of the - Mac is 128 bits (16 bytes).</p> - </desc> - </func> - <func> - <name>md5_mac_96(Key, Data) -> Mac</name> - <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary> - <type> - <v>Key = Data = iolist() | binary()</v> - <v>Mac = binary()</v> - </type> - <desc> - <p>Computes an <c>MD5 MAC</c> message authentification code - from <c>Key</c> and <c>Data</c>, where the length of the Mac - is 96 bits (12 bytes).</p> - </desc> - </func> + <func> <name>hmac(Type, Key, Data) -> Mac</name> <name>hmac(Type, Key, Data, MacLength) -> Mac</name> <fsummary></fsummary> <type> - <v>Type = md5 | sha | sha224 | sha256 | sha384 | sha512</v> + <v>Type = message_digest_algorithms() </v> <v>Key = iodata()</v> <v>Data = iodata()</v> <v>MacLength = integer()</v> @@ -372,12 +308,13 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> will limit the size of the resultant <c>Mac</c>. </desc> </func> + <func> <name>hmac_init(Type, Key) -> Context</name> <fsummary></fsummary> <type> - <v>Type = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v> - <v>Key = iolist() | binary()</v> + <v>Type = message_digest_algorithms()</v> + <v>Key = iodata()</v> <v>Context = binary()</v> </type> <desc> @@ -386,20 +323,26 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> key. The key can be any length.</p> </desc> </func> + <func> <name>hmac_update(Context, Data) -> NewContext</name> <fsummary></fsummary> <type> <v>Context = NewContext = binary()</v> - <v>Data = iolist() | binary()</v> + <v>Data = iodata()</v> </type> <desc> <p>Updates the HMAC represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c> must have been generated using an HMAC init function (such as <seealso marker="#hmac_init/2">hmac_init</seealso>). <c>Data</c> can be any length. <c>NewContext</c> - must be passed into the next call to <c>hmac_update</c>.</p> + must be passed into the next call to <c>hmac_update</c> + or to one of the functions <seealso marker="#hmac_final/1">hmac_final</seealso> and + <seealso marker="#hmac_final_n/1">hmac_final_n</seealso> + </p> + </desc> </func> + <func> <name>hmac_final(Context) -> Mac</name> <fsummary></fsummary> @@ -411,6 +354,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> determined by the type of hash function used to generate it.</p> </desc> </func> + <func> <name>hmac_final_n(Context, HashLen) -> Mac</name> <fsummary></fsummary> @@ -423,705 +367,88 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> zero. <c>Mac</c> will be a binary with at most <c>HashLen</c> bytes. Note that if HashLen is greater than the actual number of bytes returned from the underlying hash, the returned hash will have fewer than <c>HashLen</c> bytes.</p> </desc> </func> - <func> - <name>sha_mac(Key, Data) -> Mac</name> - <name>sha_mac(Key, Data, MacLength) -> Mac</name> - <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary> - <type> - <v>Key = Data = iolist() | binary()</v> - <v>Mac = binary()</v> - <v>MacLenength = integer() =< 20 </v> - </type> - <desc> - <p>Computes an <c>SHA MAC</c> message authentification code - from <c>Key</c> and <c>Data</c>, where the default length of the Mac - is 160 bits (20 bytes).</p> - </desc> - </func> - <func> - <name>sha_mac_96(Key, Data) -> Mac</name> - <fsummary>Compute an <c>SHA MAC</c>message authentification code</fsummary> - <type> - <v>Key = Data = iolist() | binary()</v> - <v>Mac = binary()</v> - </type> - <desc> - <p>Computes an <c>SHA MAC</c> message authentification code - from <c>Key</c> and <c>Data</c>, where the length of the Mac - is 96 bits (12 bytes).</p> - </desc> - </func> - <func> - <name>des_cbc_encrypt(Key, IVec, Text) -> Cipher</name> - <fsummary>Encrypt <c>Text</c>according to DES in CBC mode</fsummary> - <type> - <v>Key = Text = iolist() | binary()</v> - <v>IVec = Cipher = binary()</v> - </type> - <desc> - <p>Encrypts <c>Text</c> according to DES in CBC - mode. <c>Text</c> must be a multiple of 64 bits (8 - bytes). <c>Key</c> is the DES key, and <c>IVec</c> is an - arbitrary initializing vector. The lengths of <c>Key</c> and - <c>IVec</c> must be 64 bits (8 bytes).</p> - </desc> - </func> - <func> - <name>des_cbc_decrypt(Key, IVec, Cipher) -> Text</name> - <fsummary>Decrypt <c>Cipher</c>according to DES in CBC mode</fsummary> - <type> - <v>Key = Cipher = iolist() | binary()</v> - <v>IVec = Text = binary()</v> - </type> - <desc> - <p>Decrypts <c>Cipher</c> according to DES in CBC mode. - <c>Key</c> is the DES key, and <c>IVec</c> is an arbitrary - initializing vector. <c>Key</c> and <c>IVec</c> must have - the same values as those used when encrypting. <c>Cipher</c> - must be a multiple of 64 bits (8 bytes). The lengths of - <c>Key</c> and <c>IVec</c> must be 64 bits (8 bytes).</p> - </desc> - </func> - <func> - <name>des_cbc_ivec(Data) -> IVec</name> - <fsummary>Get <c>IVec</c> to be used in next iteration of - <c>des_cbc_[ecrypt|decrypt]</c></fsummary> - <type> - <v>Data = iolist() | binary()</v> - <v>IVec = binary()</v> - </type> - <desc> - <p>Returns the <c>IVec</c> to be used in a next iteration of - <c>des_cbc_[encrypt|decrypt]</c>. <c>Data</c> is the encrypted - data from the previous iteration step.</p> - </desc> - </func> - <func> - <name>des_cfb_encrypt(Key, IVec, Text) -> Cipher</name> - <fsummary>Encrypt <c>Text</c>according to DES in CFB mode</fsummary> - <type> - <v>Key = Text = iolist() | binary()</v> - <v>IVec = Cipher = binary()</v> - </type> - <desc> - <p>Encrypts <c>Text</c> according to DES in 8-bit CFB - mode. <c>Key</c> is the DES key, and <c>IVec</c> is an - arbitrary initializing vector. The lengths of <c>Key</c> and - <c>IVec</c> must be 64 bits (8 bytes).</p> - </desc> - </func> - <func> - <name>des_cfb_decrypt(Key, IVec, Cipher) -> Text</name> - <fsummary>Decrypt <c>Cipher</c>according to DES in CFB mode</fsummary> - <type> - <v>Key = Cipher = iolist() | binary()</v> - <v>IVec = Text = binary()</v> - </type> - <desc> - <p>Decrypts <c>Cipher</c> according to DES in 8-bit CFB mode. - <c>Key</c> is the DES key, and <c>IVec</c> is an arbitrary - initializing vector. <c>Key</c> and <c>IVec</c> must have - the same values as those used when encrypting. The lengths of - <c>Key</c> and <c>IVec</c> must be 64 bits (8 bytes).</p> - </desc> - </func> - <func> - <name>des_cfb_ivec(IVec, Data) -> NextIVec</name> - <fsummary>Get <c>IVec</c> to be used in next iteration of - <c>des_cfb_[ecrypt|decrypt]</c></fsummary> - <type> - <v>IVec = iolist() | binary()</v> - <v>Data = iolist() | binary()</v> - <v>NextIVec = binary()</v> - </type> - <desc> - <p>Returns the <c>IVec</c> to be used in a next iteration of - <c>des_cfb_[encrypt|decrypt]</c>. <c>IVec</c> is the vector - used in the previous iteration step. <c>Data</c> is the encrypted - data from the previous iteration step.</p> - </desc> - </func> - <func> - <name>des3_cbc_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher</name> - <fsummary>Encrypt <c>Text</c>according to DES3 in CBC mode</fsummary> - <type> - <v>Key1 =Key2 = Key3 Text = iolist() | binary()</v> - <v>IVec = Cipher = binary()</v> - </type> - <desc> - <p>Encrypts <c>Text</c> according to DES3 in CBC - mode. <c>Text</c> must be a multiple of 64 bits (8 - bytes). <c>Key1</c>, <c>Key2</c>, <c>Key3</c>, are the DES - keys, and <c>IVec</c> is an arbitrary initializing - vector. The lengths of each of <c>Key1</c>, <c>Key2</c>, - <c>Key3</c> and <c>IVec</c> must be 64 bits (8 bytes).</p> - </desc> - </func> - <func> - <name>des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text</name> - <fsummary>Decrypt <c>Cipher</c>according to DES3 in CBC mode</fsummary> - <type> - <v>Key1 = Key2 = Key3 = Cipher = iolist() | binary()</v> - <v>IVec = Text = binary()</v> - </type> - <desc> - <p>Decrypts <c>Cipher</c> according to DES3 in CBC mode. - <c>Key1</c>, <c>Key2</c>, <c>Key3</c> are the DES key, and - <c>IVec</c> is an arbitrary initializing vector. - <c>Key1</c>, <c>Key2</c>, <c>Key3</c> and <c>IVec</c> must - and <c>IVec</c> must have the same values as those used when - encrypting. <c>Cipher</c> must be a multiple of 64 bits (8 - bytes). The lengths of <c>Key1</c>, <c>Key2</c>, - <c>Key3</c>, and <c>IVec</c> must be 64 bits (8 bytes).</p> - </desc> - </func> - <func> - <name>des3_cfb_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher</name> - <fsummary>Encrypt <c>Text</c>according to DES3 in CFB mode</fsummary> - <type> - <v>Key1 =Key2 = Key3 Text = iolist() | binary()</v> - <v>IVec = Cipher = binary()</v> - </type> - <desc> - <p>Encrypts <c>Text</c> according to DES3 in 8-bit CFB - mode. <c>Key1</c>, <c>Key2</c>, <c>Key3</c>, are the DES - keys, and <c>IVec</c> is an arbitrary initializing - vector. The lengths of each of <c>Key1</c>, <c>Key2</c>, - <c>Key3</c> and <c>IVec</c> must be 64 bits (8 bytes).</p> - <p>May throw exception <c>notsup</c> for old OpenSSL - versions (0.9.7) that does not support this encryption mode.</p> - </desc> - </func> - <func> - <name>des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text</name> - <fsummary>Decrypt <c>Cipher</c>according to DES3 in CFB mode</fsummary> - <type> - <v>Key1 = Key2 = Key3 = Cipher = iolist() | binary()</v> - <v>IVec = Text = binary()</v> - </type> - <desc> - <p>Decrypts <c>Cipher</c> according to DES3 in 8-bit CFB mode. - <c>Key1</c>, <c>Key2</c>, <c>Key3</c> are the DES key, and - <c>IVec</c> is an arbitrary initializing vector. - <c>Key1</c>, <c>Key2</c>, <c>Key3</c> and <c>IVec</c> must - and <c>IVec</c> must have the same values as those used when - encrypting. The lengths of <c>Key1</c>, <c>Key2</c>, - <c>Key3</c>, and <c>IVec</c> must be 64 bits (8 bytes).</p> - <p>May throw exception <c>notsup</c> for old OpenSSL - versions (0.9.7) that does not support this encryption mode.</p> - </desc> - </func> - - <func> - <name>des_ecb_encrypt(Key, Text) -> Cipher</name> - <fsummary>Encrypt <c>Text</c>according to DES in ECB mode</fsummary> - <type> - <v>Key = Text = iolist() | binary()</v> - <v>Cipher = binary()</v> - </type> - <desc> - <p>Encrypts <c>Text</c> according to DES in ECB mode. - <c>Key</c> is the DES key. The lengths of <c>Key</c> and - <c>Text</c> must be 64 bits (8 bytes).</p> - </desc> - </func> - <func> - <name>des_ecb_decrypt(Key, Cipher) -> Text</name> - <fsummary>Decrypt <c>Cipher</c>according to DES in ECB mode</fsummary> - <type> - <v>Key = Cipher = iolist() | binary()</v> - <v>Text = binary()</v> - </type> - <desc> - <p>Decrypts <c>Cipher</c> according to DES in ECB mode. - <c>Key</c> is the DES key. The lengths of <c>Key</c> and - <c>Cipher</c> must be 64 bits (8 bytes).</p> - </desc> - </func> - - <func> - <name>blowfish_ecb_encrypt(Key, Text) -> Cipher</name> - <fsummary>Encrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary> - <type> - <v>Key = Text = iolist() | binary()</v> - <v>Cipher = binary()</v> - </type> - <desc> - <p>Encrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p> - </desc> - </func> - <func> - <name>blowfish_ecb_decrypt(Key, Text) -> Cipher</name> - <fsummary>Decrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary> - <type> - <v>Key = Text = iolist() | binary()</v> - <v>Cipher = binary()</v> - </type> - <desc> - <p>Decrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p> - </desc> - </func> - - <func> - <name>blowfish_cbc_encrypt(Key, IVec, Text) -> Cipher</name> - <fsummary>Encrypt <c>Text</c> using Blowfish in CBC mode</fsummary> - <type> - <v>Key = Text = iolist() | binary()</v> - <v>IVec = Cipher = binary()</v> - </type> - <desc> - <p>Encrypts <c>Text</c> using Blowfish in CBC mode. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an - arbitrary initializing vector. The length of <c>IVec</c> - must be 64 bits (8 bytes). The length of <c>Text</c> must be a multiple of 64 bits (8 bytes).</p> - </desc> - </func> - <func> - <name>blowfish_cbc_decrypt(Key, IVec, Text) -> Cipher</name> - <fsummary>Decrypt <c>Text</c> using Blowfish in CBC mode</fsummary> - <type> - <v>Key = Text = iolist() | binary()</v> - <v>IVec = Cipher = binary()</v> - </type> - <desc> - <p>Decrypts <c>Text</c> using Blowfish in CBC mode. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an - arbitrary initializing vector. The length of <c>IVec</c> - must be 64 bits (8 bytes). The length of <c>Text</c> must be a multiple 64 bits (8 bytes).</p> - </desc> - </func> - - <func> - <name>blowfish_cfb64_encrypt(Key, IVec, Text) -> Cipher</name> - <fsummary>Encrypt <c>Text</c>using Blowfish in CFB mode with 64 - bit feedback</fsummary> - <type> - <v>Key = Text = iolist() | binary()</v> - <v>IVec = Cipher = binary()</v> - </type> - <desc> - <p>Encrypts <c>Text</c> using Blowfish in CFB mode with 64 bit - feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an - arbitrary initializing vector. The length of <c>IVec</c> - must be 64 bits (8 bytes).</p> - </desc> - </func> - <func> - <name>blowfish_cfb64_decrypt(Key, IVec, Text) -> Cipher</name> - <fsummary>Decrypt <c>Text</c>using Blowfish in CFB mode with 64 - bit feedback</fsummary> - <type> - <v>Key = Text = iolist() | binary()</v> - <v>IVec = Cipher = binary()</v> - </type> - <desc> - <p>Decrypts <c>Text</c> using Blowfish in CFB mode with 64 bit - feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an - arbitrary initializing vector. The length of <c>IVec</c> - must be 64 bits (8 bytes).</p> - </desc> - </func> <func> - <name>blowfish_ofb64_encrypt(Key, IVec, Text) -> Cipher</name> - <fsummary>Encrypt <c>Text</c>using Blowfish in OFB mode with 64 - bit feedback</fsummary> + <name>info_lib() -> [{Name,VerNum,VerStr}]</name> + <fsummary>Provides information about the libraries used by crypto.</fsummary> <type> - <v>Key = Text = iolist() | binary()</v> - <v>IVec = Cipher = binary()</v> + <v>Name = binary()</v> + <v>VerNum = integer()</v> + <v>VerStr = binary()</v> </type> <desc> - <p>Encrypts <c>Text</c> using Blowfish in OFB mode with 64 bit - feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an - arbitrary initializing vector. The length of <c>IVec</c> - must be 64 bits (8 bytes).</p> + <p>Provides the name and version of the libraries used by crypto.</p> + <p><c>Name</c> is the name of the library. <c>VerNum</c> is + the numeric version according to the library's own versioning + scheme. <c>VerStr</c> contains a text variant of the version.</p> + <pre> +> <input>info_lib().</input> +[{<<"OpenSSL">>,9469983,<<"OpenSSL 0.9.8a 11 Oct 2005">>}] + </pre> + <note><p> + From OTP R16 the <em>numeric version</em> represents the version of the OpenSSL + <em>header files</em> (<c>openssl/opensslv.h</c>) used when crypto was compiled. + The text variant represents the OpenSSL library used at runtime. + In earlier OTP versions both numeric and text was taken from the library. + </p></note> </desc> </func> <func> - <name>aes_cfb_128_encrypt(Key, IVec, Text) -> Cipher</name> - <fsummary>Encrypt <c>Text</c>according to AES in Cipher Feedback mode</fsummary> - <type> - <v>Key = Text = iolist() | binary()</v> - <v>IVec = Cipher = binary()</v> - </type> - <desc> - <p>Encrypts <c>Text</c> according to AES in Cipher Feedback - mode (CFB). <c>Key</c> is the - AES key, and <c>IVec</c> is an arbitrary initializing vector. - The lengths of <c>Key</c> and <c>IVec</c> must be 128 bits - (16 bytes).</p> - </desc> - </func> - <func> - <name>aes_cfb_128_decrypt(Key, IVec, Cipher) -> Text</name> - <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Feedback mode</fsummary> - <type> - <v>Key = Cipher = iolist() | binary()</v> - <v>IVec = Text = binary()</v> - </type> - <desc> - <p>Decrypts <c>Cipher</c> according to AES in Cipher Feedback Mode (CFB). - <c>Key</c> is the AES key, and <c>IVec</c> is an arbitrary - initializing vector. <c>Key</c> and <c>IVec</c> must have - the same values as those used when encrypting. The lengths of - <c>Key</c> and <c>IVec</c> must be 128 bits (16 bytes).</p> - </desc> - </func> - <func> - <name>aes_cbc_128_encrypt(Key, IVec, Text) -> Cipher</name> - <fsummary>Encrypt <c>Text</c>according to AES in Cipher Block Chaining mode</fsummary> - <type> - <v>Key = Text = iolist() | binary()</v> - <v>IVec = Cipher = binary()</v> - </type> - <desc> - <p>Encrypts <c>Text</c> according to AES in Cipher Block Chaining - mode (CBC). <c>Text</c> - must be a multiple of 128 bits (16 bytes). <c>Key</c> is the - AES key, and <c>IVec</c> is an arbitrary initializing vector. - The lengths of <c>Key</c> and <c>IVec</c> must be 128 bits - (16 bytes).</p> - </desc> - </func> - <func> - <name>aes_cbc_128_decrypt(Key, IVec, Cipher) -> Text</name> - <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Block Chaining mode</fsummary> - <type> - <v>Key = Cipher = iolist() | binary()</v> - <v>IVec = Text = binary()</v> - </type> - <desc> - <p>Decrypts <c>Cipher</c> according to AES in Cipher Block - Chaining mode (CBC). - <c>Key</c> is the AES key, and <c>IVec</c> is an arbitrary - initializing vector. <c>Key</c> and <c>IVec</c> must have - the same values as those used when encrypting. <c>Cipher</c> - must be a multiple of 128 bits (16 bytes). The lengths of - <c>Key</c> and <c>IVec</c> must be 128 bits (16 bytes).</p> - </desc> - </func> - <func> - <name>aes_cbc_ivec(Data) -> IVec</name> - <fsummary>Get <c>IVec</c> to be used in next iteration of - <c>aes_cbc_*_[ecrypt|decrypt]</c></fsummary> - <type> - <v>Data = iolist() | binary()</v> - <v>IVec = binary()</v> - </type> - <desc> - <p>Returns the <c>IVec</c> to be used in a next iteration of - <c>aes_cbc_*_[encrypt|decrypt]</c>. <c>Data</c> is the encrypted - data from the previous iteration step.</p> - </desc> - </func> - <func> - <name>aes_ctr_encrypt(Key, IVec, Text) -> Cipher</name> - <fsummary>Encrypt <c>Text</c>according to AES in Counter mode</fsummary> - <type> - <v>Key = Text = iolist() | binary()</v> - <v>IVec = Cipher = binary()</v> - </type> - <desc> - <p>Encrypts <c>Text</c> according to AES in Counter mode (CTR). <c>Text</c> - can be any number of bytes. <c>Key</c> is the AES key and must be either - 128, 192 or 256 bits long. <c>IVec</c> is an arbitrary initializing vector of 128 bits - (16 bytes).</p> - </desc> - </func> - <func> - <name>aes_ctr_decrypt(Key, IVec, Cipher) -> Text</name> - <fsummary>Decrypt <c>Cipher</c>according to AES in Counter mode</fsummary> - <type> - <v>Key = Cipher = iolist() | binary()</v> - <v>IVec = Text = binary()</v> - </type> - <desc> - <p>Decrypts <c>Cipher</c> according to AES in Counter mode (CTR). <c>Cipher</c> - can be any number of bytes. <c>Key</c> is the AES key and must be either - 128, 192 or 256 bits long. <c>IVec</c> is an arbitrary initializing vector of 128 bits - (16 bytes).</p> - </desc> - </func> - <func> - <name>aes_ctr_stream_init(Key, IVec) -> State</name> - <fsummary></fsummary> - <type> - <v>State = { K, I, E, C }</v> - <v>Key = K = iolist()</v> - <v>IVec = I = E = binary()</v> - <v>C = integer()</v> - </type> - <desc> - <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR). - <c>Key</c> is the AES key and must be either 128, 192, or 256 bts long. <c>IVec</c> is - an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with - <seealso marker="#aes_ctr_stream_encrypt/2">aes_ctr_stream_encrypt</seealso> and - <seealso marker="#aes_ctr_stream_decrypt/2">aes_ctr_stream_decrypt</seealso>.</p> - </desc> - </func> - <func> - <name>aes_ctr_stream_encrypt(State, Text) -> { NewState, Cipher}</name> - <fsummary></fsummary> - <type> - <v>Text = iolist() | binary()</v> - <v>Cipher = binary()</v> - </type> - <desc> - <p>Encrypts <c>Text</c> according to AES in Counter mode (CTR). This function can be - used to encrypt a stream of text using a series of calls instead of requiring all - text to be in memory. <c>Text</c> can be any number of bytes. State is initialized using - <seealso marker="#aes_ctr_stream_init/2">aes_ctr_stream_init</seealso>. <c>NewState</c> is the new streaming - encryption state that must be passed to the next call to <c>aes_ctr_stream_encrypt</c>. - <c>Cipher</c> is the encrypted cipher text.</p> - </desc> - </func> - <func> - <name>aes_ctr_stream_decrypt(State, Cipher) -> { NewState, Text }</name> - <fsummary></fsummary> - <type> - <v>Cipher = iolist() | binary()</v> - <v>Text = binary()</v> - </type> - <desc> - <p>Decrypts <c>Cipher</c> according to AES in Counter mode (CTR). This function can be - used to decrypt a stream of ciphertext using a series of calls instead of requiring all - ciphertext to be in memory. <c>Cipher</c> can be any number of bytes. State is initialized using - <seealso marker="#aes_ctr_stream_init/2">aes_ctr_stream_init</seealso>. <c>NewState</c> is the new streaming - encryption state that must be passed to the next call to <c>aes_ctr_stream_encrypt</c>. - <c>Text</c> is the decrypted data.</p> - </desc> - </func> - <func> - <name>erlint(Mpint) -> N</name> - <name>mpint(N) -> Mpint</name> - <fsummary>Convert between binary multi-precision integer and erlang big integer</fsummary> - <type> - <v>Mpint = binary()</v> - <v>N = integer()</v> - </type> - <desc> - <p>Convert a binary multi-precision integer <c>Mpint</c> to and from - an erlang big integer. A multi-precision integer is a binary - with the following form: - <c><![CDATA[<<ByteLen:32/integer, Bytes:ByteLen/binary>>]]></c> where both - <c>ByteLen</c> and <c>Bytes</c> are big-endian. Mpints are used in - some of the functions in <c>crypto</c> and are not translated - in the API for performance reasons.</p> - </desc> - </func> - <func> - <name>rand_bytes(N) -> binary()</name> - <fsummary>Generate a binary of random bytes</fsummary> - <type> - <v>N = integer()</v> - </type> - <desc> - <p>Generates N bytes randomly uniform 0..255, and returns the - result in a binary. Uses the <c>crypto</c> library pseudo-random - number generator.</p> - </desc> - </func> - <func> - <name>strong_rand_bytes(N) -> binary()</name> - <fsummary>Generate a binary of random bytes</fsummary> - <type> - <v>N = integer()</v> - </type> - <desc> - <p>Generates N bytes randomly uniform 0..255, and returns the - result in a binary. Uses a cryptographically secure prng seeded and - periodically mixed with operating system provided entropy. By default - this is the <c>RAND_bytes</c> method from OpenSSL.</p> - <p>May throw exception <c>low_entropy</c> in case the random generator - failed due to lack of secure "randomness".</p> - </desc> - </func> - <func> - <name>rand_uniform(Lo, Hi) -> N</name> - <fsummary>Generate a random number</fsummary> - <type> - <v>Lo, Hi, N = Mpint | integer()</v> - <v>Mpint = binary()</v> - </type> - <desc> - <p>Generate a random number <c><![CDATA[N, Lo =< N < Hi.]]></c> Uses the - <c>crypto</c> library pseudo-random number generator. The - arguments (and result) can be either erlang integers or binary - multi-precision integers. <c>Hi</c> must be larger than <c>Lo</c>.</p> - </desc> - </func> - <func> - <name>strong_rand_mpint(N, Top, Bottom) -> Mpint</name> - <fsummary>Generate an N bit random number</fsummary> - <type> - <v>N = non_neg_integer()</v> - <v>Top = -1 | 0 | 1</v> - <v>Bottom = 0 | 1</v> - <v>Mpint = binary()</v> - </type> - <desc> - <p>Generate an N bit random number using OpenSSL's - cryptographically strong pseudo random number generator - <c>BN_rand</c>.</p> - <p>The parameter <c>Top</c> places constraints on the most - significant bits of the generated number. If <c>Top</c> is 1, then the - two most significant bits will be set to 1, if <c>Top</c> is 0, the - most significant bit will be 1, and if <c>Top</c> is -1 then no - constraints are applied and thus the generated number may be less than - N bits long.</p> - <p>If <c>Bottom</c> is 1, then the generated number is - constrained to be odd.</p> - <p>May throw exception <c>low_entropy</c> in case the random generator - failed due to lack of secure "randomness".</p> - </desc> - </func> - <func> - <name>mod_exp(N, P, M) -> Result</name> - <fsummary>Perform N ^ P mod M</fsummary> - <type> - <v>N, P, M, Result = Mpint</v> - <v>Mpint = binary()</v> - </type> - <desc> - <p>This function performs the exponentiation <c>N ^ P mod M</c>, - using the <c>crypto</c> library.</p> - </desc> - </func> - <func> - <name>mod_exp_prime(N, P, M) -> Result</name> + <name>mod_pow(N, P, M) -> Result</name> <fsummary>Computes the function: N^P mod M</fsummary> <type> - <v>N, P, M = binary()</v> + <v>N, P, M = binary() | integer()</v> <v>Result = binary() | error</v> </type> <desc> <p>Computes the function <c>N^P mod M</c>.</p> </desc> </func> - <func> - <name>rsa_sign(DataOrDigest, Key) -> Signature</name> - <name>rsa_sign(DigestType, DataOrDigest, Key) -> Signature</name> - <fsummary>Sign the data using rsa with the given key.</fsummary> - <type> - <v>DataOrDigest = Data | {digest,Digest}</v> - <v>Data = Mpint</v> - <v>Digest = binary()</v> - <v>Key = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v> - <v>E, N, D = Mpint</v> - <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and - <c>D</c> is the private exponent.</d> - <v>P1, P2, E1, E2, C = Mpint</v> - <d>The longer key format contains redundant information that will make - the calculation faster. <c>P1,P2</c> are first and second prime factors. - <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient. - Terminology is taken from RFC 3447.</d> - <v>DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512</v> - <d>The default <c>DigestType</c> is sha.</d> - <v>Mpint = binary()</v> - <v>Signature = binary()</v> - </type> - <desc> - <p>Creates a RSA signature with the private key <c>Key</c> - of a digest. The digest is either calculated as a - <c>DigestType</c> digest of <c>Data</c> or a precalculated - binary <c>Digest</c>.</p> - </desc> - </func> <func> - <name>rsa_verify(DataOrDigest, Signature, Key) -> Verified</name> - <name>rsa_verify(DigestType, DataOrDigest, Signature, Key) -> Verified </name> - <fsummary>Verify the digest and signature using rsa with given public key.</fsummary> - <type> - <v>Verified = boolean()</v> - <v>DataOrDigest = Data | {digest|Digest}</v> - <v>Data, Signature = Mpint</v> - <v>Digest = binary()</v> - <v>Key = [E, N]</v> - <v>E, N = Mpint</v> - <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus.</d> - <v>DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512</v> - <d>The default <c>DigestType</c> is sha.</d> - <v>Mpint = binary()</v> - </type> - <desc> - <p>Verifies that a digest matches the RSA signature using the - signer's public key <c>Key</c>. - The digest is either calculated as a <c>DigestType</c> - digest of <c>Data</c> or a precalculated binary <c>Digest</c>.</p> - <p>May throw exception <c>notsup</c> in case the chosen <c>DigestType</c> - is not supported by the underlying OpenSSL implementation.</p> - </desc> - </func> - - <func> - <name>rsa_public_encrypt(PlainText, PublicKey, Padding) -> ChipherText</name> - <fsummary>Encrypts Msg using the public Key.</fsummary> - <type> - <v>PlainText = binary()</v> - <v>PublicKey = [E, N]</v> - <v>E, N = Mpint</v> - <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus.</d> - <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v> - <v>ChipherText = binary()</v> - </type> - <desc> - <p>Encrypts the <c>PlainText</c> (usually a session key) using the <c>PublicKey</c> - and returns the cipher. The <c>Padding</c> decides what padding mode is used, - <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most - used mode and <c>rsa_pkcs1_oaep_padding</c> is EME-OAEP as - defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding - parameter. This mode is recommended for all new applications. - The size of the <c>Msg</c> must be less - than <c>byte_size(N)-11</c> if - <c>rsa_pkcs1_padding</c> is used, <c>byte_size(N)-41</c> if - <c>rsa_pkcs1_oaep_padding</c> is used and <c>byte_size(N)</c> if <c>rsa_no_padding</c> - is used. - Where byte_size(N) is the size part of an <c>Mpint-1</c>. - </p> - </desc> + <name>next_iv(Type, Data) -> </name> + <fsummary></fsummary> + <type> + <v>Type = des_cbc | aes_cbc</v> + <v>Data = iodata()</v> + </type> + <desc> + <p>Returns the initialization vector to be used in the next + iteration of encrypt/decrypt of type <c>Type</c>. Data is the + encrypted data from the previous iteration step.</p> + </desc> </func> <func> - <name>rsa_private_decrypt(ChipherText, PrivateKey, Padding) -> PlainText</name> + <name>private_decrypt(Type, ChipherText, PrivateKey, Padding) -> PlainText</name> <fsummary>Decrypts ChipherText using the private Key.</fsummary> <type> + <v>Type = rsa</v> <v>ChipherText = binary()</v> - <v>PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v> - <v>E, N, D = Mpint</v> - <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and - <c>D</c> is the private exponent.</d> - <v>P1, P2, E1, E2, C = Mpint</v> - <d>The longer key format contains redundant information that will make - the calculation faster. <c>P1,P2</c> are first and second prime factors. - <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient. - Terminology is taken from RFC 3447.</d> + <v>PrivateKey = rsa_private()</v> <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v> <v>PlainText = binary()</v> </type> <desc> - <p>Decrypts the <c>ChipherText</c> (usually a session key encrypted with - <seealso marker="#rsa_public_encrypt/3">rsa_public_encrypt/3</seealso>) + <p>Decrypts the <c>ChipherText</c> (usually a session key encrypted with + <seealso marker="#public_encrypt/3">public_encrypt/3</seealso>) using the <c>PrivateKey</c> and returns the message. The <c>Padding</c> is the padding mode that was - used to encrypt the data, - see <seealso marker="#rsa_public_encrypt/3">rsa_public_encrypt/3</seealso>. + used to encrypt the data, + see <seealso marker="#public_encrypt/3">public_encrypt/3</seealso>. + See also <seealso marker="public_key:public_key#decrypt_private/2">public_key:decrypt_private/[2,3]</seealso> </p> </desc> </func> + <func> - <name>rsa_private_encrypt(PlainText, PrivateKey, Padding) -> ChipherText</name> + <name>private_encrypt(Type, PlainText, PrivateKey, Padding) -> ChipherText</name> <fsummary>Encrypts Msg using the private Key.</fsummary> <type> + <v>Type = rsa</v> <v>PlainText = binary()</v> - <v>PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v> - <v>E, N, D = Mpint</v> - <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and - <c>D</c> is the private exponent.</d> - <v>P1, P2, E1, E2, C = Mpint</v> - <d>The longer key format contains redundant information that will make - the calculation faster. <c>P1,P2</c> are first and second prime factors. - <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient. - Terminology is taken from RFC 3447.</d> + <v>PrivateKey = rsa_private()</v> <v>Padding = rsa_pkcs1_padding | rsa_no_padding</v> <v>ChipherText = binary()</v> </type> @@ -1131,316 +458,289 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most used mode. The size of the <c>Msg</c> must be less than <c>byte_size(N)-11</c> if - <c>rsa_pkcs1_padding</c> is used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c> - is used. Where byte_size(N) is the size part of an <c>Mpint-1</c>. + <c>rsa_pkcs1_padding</c> is used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c> + is used. + See also <seealso marker="public_key:public_key#encrypt_private/2">public_key:encrypt_private/[2,3]</seealso> </p> </desc> </func> - <func> - <name>rsa_public_decrypt(ChipherText, PublicKey, Padding) -> PlainText</name> + <name>public_decrypt(Type, ChipherText, PublicKey, Padding) -> PlainText</name> <fsummary>Decrypts ChipherText using the public Key.</fsummary> <type> + <v>Type = rsa</v> <v>ChipherText = binary()</v> - <v>PublicKey = [E, N]</v> - <v>E, N = Mpint</v> - <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus</d> + <v>PublicKey = rsa_public() </v> <v>Padding = rsa_pkcs1_padding | rsa_no_padding</v> <v>PlainText = binary()</v> </type> <desc> - <p>Decrypts the <c>ChipherText</c> (encrypted with - <seealso marker="#rsa_private_encrypt/3">rsa_private_encrypt/3</seealso>) + <p>Decrypts the <c>ChipherText</c> (encrypted with + <seealso marker="#private_encrypt/3">private_encrypt/3</seealso>) using the <c>PrivateKey</c> and returns the message. The <c>Padding</c> is the padding mode that was - used to encrypt the data, - see <seealso marker="#rsa_private_encrypt/3">rsa_private_encrypt/3</seealso>. + used to encrypt the data, + see <seealso marker="#private_encrypt/3">private_encrypt/3</seealso>. + See also <seealso marker="public_key:public_key#decrypt_public/2">public_key:decrypt_public/[2,3]</seealso> </p> </desc> </func> - + <func> - <name>dss_sign(DataOrDigest, Key) -> Signature</name> - <name>dss_sign(DigestType, DataOrDigest, Key) -> Signature</name> - <fsummary>Sign the data using dsa with given private key.</fsummary> + <name>public_encrypt(Type, PlainText, PublicKey, Padding) -> ChipherText</name> + <fsummary>Encrypts Msg using the public Key.</fsummary> <type> - <v>DigestType = sha</v> - <v>DataOrDigest = Mpint | {digest,Digest}</v> - <v>Key = [P, Q, G, X]</v> - <v>P, Q, G, X = Mpint</v> - <d> Where <c>P</c>, <c>Q</c> and <c>G</c> are the dss - parameters and <c>X</c> is the private key.</d> - <v>Digest = binary() with length 20 bytes</v> - <v>Signature = binary()</v> + <v>Type = rsa</v> + <v>PlainText = binary()</v> + <v>PublicKey = rsa_public()</v> + <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v> + <v>ChipherText = binary()</v> </type> <desc> - <p>Creates a DSS signature with the private key <c>Key</c> of - a digest. The digest is either calculated as a SHA1 - digest of <c>Data</c> or a precalculated binary <c>Digest</c>.</p> - <p>A deprecated feature is having <c>DigestType = 'none'</c> - in which case <c>DataOrDigest</c> is a precalculated SHA1 - digest.</p> + <p>Encrypts the <c>PlainText</c> (usually a session key) using the <c>PublicKey</c> + and returns the <c>CipherText</c>. The <c>Padding</c> decides what padding mode is used, + <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most + used mode and <c>rsa_pkcs1_oaep_padding</c> is EME-OAEP as + defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding + parameter. This mode is recommended for all new applications. + The size of the <c>Msg</c> must be less + than <c>byte_size(N)-11</c> if + <c>rsa_pkcs1_padding</c> is used, <c>byte_size(N)-41</c> if + <c>rsa_pkcs1_oaep_padding</c> is used and <c>byte_size(N)</c> if <c>rsa_no_padding</c> + is used. + See also <seealso marker="public_key:public_key#encrypt_public/2">public_key:encrypt_public/[2,3]</seealso> + </p> </desc> </func> <func> - <name>dss_verify(DataOrDigest, Signature, Key) -> Verified</name> - <name>dss_verify(DigestType, DataOrDigest, Signature, Key) -> Verified</name> - <fsummary>Verify the data and signature using dsa with given public key.</fsummary> + <name>rand_bytes(N) -> binary()</name> + <fsummary>Generate a binary of random bytes</fsummary> <type> - <v>Verified = boolean()</v> - <v>DigestType = sha</v> - <v>DataOrDigest = Mpint | {digest,Digest}</v> - <v>Data = Mpint | ShaDigest</v> - <v>Signature = Mpint</v> - <v>Key = [P, Q, G, Y]</v> - <v>P, Q, G, Y = Mpint</v> - <d> Where <c>P</c>, <c>Q</c> and <c>G</c> are the dss - parameters and <c>Y</c> is the public key.</d> - <v>Digest = binary() with length 20 bytes</v> + <v>N = integer()</v> </type> <desc> - <p>Verifies that a digest matches the DSS signature using the - public key <c>Key</c>. The digest is either calculated as a SHA1 - digest of <c>Data</c> or is a precalculated binary <c>Digest</c>.</p> - <p>A deprecated feature is having <c>DigestType = 'none'</c> - in which case <c>DataOrDigest</c> is a precalculated SHA1 - digest binary.</p> + <p>Generates N bytes randomly uniform 0..255, and returns the + result in a binary. Uses the <c>crypto</c> library pseudo-random + number generator.</p> </desc> </func> - <func> - <name>rc2_cbc_encrypt(Key, IVec, Text) -> Cipher</name> - <fsummary>Encrypt <c>Text</c>according to RC2 in CBC mode</fsummary> + <func> + <name>rand_uniform(Lo, Hi) -> N</name> + <fsummary>Generate a random number</fsummary> <type> - <v>Key = Text = iolist() | binary()</v> - <v>Ivec = Cipher = binary()</v> + <v>Lo, Hi, N = integer()</v> </type> <desc> - <p>Encrypts <c>Text</c> according to RC2 in CBC mode.</p> + <p>Generate a random number <c><![CDATA[N, Lo =< N < Hi.]]></c> Uses the + <c>crypto</c> library pseudo-random number generator. + <c>Hi</c> must be larger than <c>Lo</c>.</p> </desc> </func> <func> - <name>rc2_cbc_decrypt(Key, IVec, Cipher) -> Text</name> - <fsummary>Decrypts <c>Cipher</c>according to RC2 in CBC mode</fsummary> + <name>sign(Algorithm, DigestType, Msg, Key) -> binary()</name> + <fsummary> Create digital signature.</fsummary> <type> - <v>Key = Text = iolist() | binary()</v> - <v>Ivec = Cipher = binary()</v> + <v>Algorithm = rsa | dss | ecdsa </v> + <v>Msg = binary() | {digest,binary()}</v> + <d>The msg is either the binary "plain text" data to be + signed or it is the hashed value of "plain text" i.e. the + digest.</d> + <v>DigestType = digest_type()</v> + <v>Key = rsa_private_key() | dsa_private_key() | ec_private_key()</v> </type> <desc> - <p>Decrypts <c>Cipher</c> according to RC2 in CBC mode.</p> + <p> Creates a digital signature.</p> + See also <seealso marker="public_key:public_key#sign/3">public_key:sign/3</seealso> </desc> </func> - + <func> - <name>rc4_encrypt(Key, Data) -> Result</name> - <fsummary>Encrypt data using RC4</fsummary> + <name>start() -> ok</name> + <fsummary> Equivalent to application:start(crypto). </fsummary> + <desc> + <p> Equivalent to application:start(crypto).</p> + </desc> + </func> + <func> + <name>stop() -> ok</name> + <fsummary> Equivalent to application:stop(crypto).</fsummary> + <desc> + <p> Equivalent to application:stop(crypto).</p> + </desc> + </func> + + <func> + <name>strong_rand_bytes(N) -> binary()</name> + <fsummary>Generate a binary of random bytes</fsummary> <type> - <v>Key, Data = iolist() | binary()</v> - <v>Result = binary()</v> + <v>N = integer()</v> </type> <desc> - <p>Encrypts the data with RC4 symmetric stream encryption. - Since it is symmetric, the same function is used for - decryption.</p> + <p>Generates N bytes randomly uniform 0..255, and returns the + result in a binary. Uses a cryptographically secure prng seeded and + periodically mixed with operating system provided entropy. By default + this is the <c>RAND_bytes</c> method from OpenSSL.</p> + <p>May throw exception <c>low_entropy</c> in case the random generator + failed due to lack of secure "randomness".</p> </desc> </func> - <func> - <name>dh_generate_key(DHParams) -> {PublicKey,PrivateKey} </name> - <name>dh_generate_key(PrivateKey, DHParams) -> {PublicKey,PrivateKey} </name> - <fsummary>Generates a Diffie-Hellman public key</fsummary> + <name>stream_init(Type, Key) -> State</name> + <fsummary></fsummary> <type> - <v>DHParameters = [P, G]</v> - <v>P, G = Mpint</v> - <d> Where <c>P</c> is the shared prime number and <c>G</c> is the shared generator.</d> - <v>PublicKey, PrivateKey = Mpint()</v> + <v>Type rc4 </v> + <v>State = opaque() </v> + <v>Key = iodata()</v> + <v>IVec = binary()</v> </type> <desc> - <p>Generates a Diffie-Hellman <c>PublicKey</c> and <c>PrivateKey</c> (if not given). - </p> + <p>Initializes the state for use in RC4 stream encryption + <seealso marker="#stream_encrypt/2">stream_encrypt</seealso> and + <seealso marker="#stream_decrypt/2">stream_decrypt</seealso></p> </desc> </func> - <func> - <name>dh_compute_key(OthersPublicKey, MyPrivateKey, DHParams) -> SharedSecret</name> - <fsummary>Computes the shared secret</fsummary> + <func> + <name>stream_init(Type, Key, IVec) -> State</name> + <fsummary></fsummary> <type> - <v>DHParameters = [P, G]</v> - <v>P, G = Mpint</v> - <d> Where <c>P</c> is the shared prime number and <c>G</c> is the shared generator.</d> - <v>OthersPublicKey, MyPrivateKey = Mpint()</v> - <v>SharedSecret = binary()</v> + <v>Type aes_ctr </v> + <v>State = opaque() </v> + <v>Key = iodata()</v> + <v>IVec = binary()</v> </type> <desc> - <p>Computes the shared secret from the private key and the other party's public key. - </p> + <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR). + <c>Key</c> is the AES key and must be either 128, 192, or 256 bts long. <c>IVec</c> is + an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with + <seealso marker="#stream_encrypt/2">stream_encrypt</seealso> and + <seealso marker="#stream_decrypt/2">stream_decrypt</seealso>.</p> </desc> </func> - + <func> - <name>srp_generate_key(Generator, Prime, Version) -> {PublicKey, PrivateKey} </name> - <name>srp_generate_key(Generator, Prime, Version, Private) -> {PublicKey, PrivateKey} </name> - <name>srp_generate_key(Verifier, Generator, Prime, Version) -> {PublicKey, PrivateKey} </name> - <name>srp_generate_key(Verifier, Generator, Prime, Version, Private) -> {PublicKey, PrivateKey} </name> - <fsummary>Generates SRP public keys</fsummary> + <name>stream_encrypt(State, PlainText) -> { NewState, CipherText}</name> + <fsummary></fsummary> <type> - <v>Verifier = binary()</v> - <d>Parameter v from <url href="http://srp.stanford.edu/design.html">SRP design</url> - </d> - <v>Generator = binary() </v> - <d>Parameter g from <url href="http://srp.stanford.edu/design.html">SRP design</url> - </d> - <v>Prime = binary() </v> - <d>Parameter N from <url href="http://srp.stanford.edu/design.html">SRP design</url> - </d> - <v>Version = '3' | '6' | '6a' </v> - <d>SRP version, TLS SRP cipher suites uses '6a'.</d> - <v>PublicKey = binary()</v> - <d> Parameter A or B from <url href="http://srp.stanford.edu/design.html">SRP design</url></d> - <v>Private = PrivateKey = binary() - generated if not supplied</v> - <d>Parameter a or b from <url href="http://srp.stanford.edu/design.html">SRP design</url></d> + <v>Text = iodata()</v> + <v>CipherText = binary()</v> </type> <desc> - <p>Generates SRP public keys for the client side (first argument is Generator) - or for the server side (first argument is Verifier).</p> + <p>Encrypts <c>PlainText</c> according to the stream cipher <c>Type</c> specified in stream_init/3. + <c>Text</c> can be any number of bytes. The initial <c>State</c> is created using + <seealso marker="#stream_init/2">stream_init</seealso>. + <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p> </desc> </func> <func> - <name>srp_compute_key(DerivedKey, Prime, Generator, - ClientPublic, ClientPrivate, ServerPublic, Version) -> SessionKey</name> - <name>srp_compute_key(DerivedKey, Prime, Generator, - ClientPublic, ClientPrivate, ServerPublic, Version, Scrambler) -> SessionKey</name> - <name>srp_compute_key(Verifier, Prime, - ClientPublic, ServerPublic, ServerPrivate, Version, Scrambler)-> SessionKey</name> - <name>srp_compute_key(Verifier, Prime, - ClientPublic, ServerPublic, ServerPrivate, Version) -> SessionKey</name> - - <fsummary>Computes SRP session key</fsummary> + <name>stream_decrypt(State, CipherText) -> { NewState, PlainText }</name> + <fsummary></fsummary> <type> - <v>DerivedKey = binary()</v> - <d>Parameter x from <url href="http://srp.stanford.edu/design.html">SRP design</url> - </d> - <v>Verifier = binary()</v> - <d>Parameter v from <url href="http://srp.stanford.edu/design.html">SRP design</url> - </d> - <v>Prime = binary() </v> - <d>Parameter N from <url href="http://srp.stanford.edu/design.html">SRP design</url> - </d> - <v>Generator = binary() </v> - <d>Parameter g from <url href="http://srp.stanford.edu/design.html">SRP design</url> - </d> - <v>ClientPublic = binary() </v> - <d>Parameter A from <url href="http://srp.stanford.edu/design.html">SRP design</url> - </d> - <v>ClientPrivate = binary() </v> - <d>Parameter a from <url href="http://srp.stanford.edu/design.html">SRP design</url> - </d> - <v>ServerPublic = binary() </v> - <d>Parameter B from <url href="http://srp.stanford.edu/design.html">SRP design</url> - </d> - <v>ServerPrivate = binary() </v> - <d>Parameter b from <url href="http://srp.stanford.edu/design.html">SRP design</url> - </d> - <v>Version = '3' | '6' | '6a' </v> - <d>SRP version, TLS SRP cipher suites uses '6a'.</d> - <v>SessionKey = binary()</v> - <d>Result K from <url href="http://srp.stanford.edu/design.html">SRP design</url> - </d> + <v>CipherText = iodata()</v> + <v>PlainText = binary()</v> </type> <desc> - <p> - Computes the SRP session key (shared secret) for the client side (first argument is DerivedKey) - or for the server side (first argument is Verifier). Also used - as premaster secret by TLS-SRP cipher suites. - </p> + <p>Decrypts <c>CipherText</c> according to the stream cipher <c>Type</c> specified in stream_init/3. + <c>PlainText</c> can be any number of bytes. The initial <c>State</c> is created using + <seealso marker="#stream_init/2">stream_init</seealso>. + <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p> </desc> </func> - - <func> - <name>exor(Data1, Data2) -> Result</name> - <fsummary>XOR data</fsummary> + + <func> + <name>verify(Algorithm, DigestType, Msg, Signature, Key) -> boolean()</name> + <fsummary>Verifies a digital signature.</fsummary> <type> - <v>Data1, Data2 = iolist() | binary()</v> - <v>Result = binary()</v> + <v> Algorithm = rsa | dss | ecdsa </v> + <v>Msg = binary() | {digest,binary()}</v> + <d>The msg is either the binary "plain text" data + or it is the hashed value of "plain text" i.e. the digest.</d> + <v>DigestType = digest_type()</v> + <v>Signature = binary()</v> + <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v> </type> <desc> - <p>Performs bit-wise XOR (exclusive or) on the data supplied.</p> + <p>Verifies a digital signature</p> + See also <seealso marker="public_key:public_key#sign/3">public_key:verify/3</seealso> </desc> </func> - </funcs> - <section> - <title>DES in CBC mode</title> - <p>The Data Encryption Standard (DES) defines an algorithm for - encrypting and decrypting an 8 byte quantity using an 8 byte key - (actually only 56 bits of the key is used). - </p> - <p>When it comes to encrypting and decrypting blocks that are - multiples of 8 bytes various modes are defined (NIST SP - 800-38A). One of those modes is the Cipher Block Chaining (CBC) - mode, where the encryption of an 8 byte segment depend not only - of the contents of the segment itself, but also on the result of - encrypting the previous segment: the encryption of the previous - segment becomes the initializing vector of the encryption of the - current segment. - </p> - <p>Thus the encryption of every segment depends on the encryption - key (which is secret) and the encryption of the previous - segment, except the first segment which has to be provided with - an initial initializing vector. That vector could be chosen at - random, or be a counter of some kind. It does not have to be - secret. - </p> - <p>The following example is drawn from the old FIPS 81 standard - (replaced by NIST SP 800-38A), where both the plain text and the - resulting cipher text is settled. The following code fragment - returns `true'. - </p> - <pre><![CDATA[ - - Key = <<16#01,16#23,16#45,16#67,16#89,16#ab,16#cd,16#ef>>, - IVec = <<16#12,16#34,16#56,16#78,16#90,16#ab,16#cd,16#ef>>, - P = "Now is the time for all ", - C = crypto:des_cbc_encrypt(Key, IVec, P), - % Which is the same as - P1 = "Now is t", P2 = "he time ", P3 = "for all ", - C1 = crypto:des_cbc_encrypt(Key, IVec, P1), - C2 = crypto:des_cbc_encrypt(Key, C1, P2), - C3 = crypto:des_cbc_encrypt(Key, C2, P3), - - C = <<C1/binary, C2/binary, C3/binary>>, - C = <<16#e5,16#c7,16#cd,16#de,16#87,16#2b,16#f2,16#7c, - 16#43,16#e9,16#34,16#00,16#8c,16#38,16#9c,16#0f, - 16#68,16#37,16#88,16#49,16#9a,16#7c,16#05,16#f6>>, - <<"Now is the time for all ">> == - crypto:des_cbc_decrypt(Key, IVec, C). - ]]></pre> - <p>The following is true for the DES CBC mode. For all - decompositions <c>P1 ++ P2 = P</c> of a plain text message - <c>P</c> (where the length of all quantities are multiples of 8 - bytes), the encryption <c>C</c> of <c>P</c> is equal to <c>C1 ++ - C2</c>, where <c>C1</c> is obtained by encrypting <c>P1</c> with - <c>Key</c> and the initializing vector <c>IVec</c>, and where - <c>C2</c> is obtained by encrypting <c>P2</c> with <c>Key</c> - and the initializing vector <c>last8(C1)</c>, - where <c>last(Binary)</c> denotes the last 8 bytes of the - binary <c>Binary</c>. - </p> - <p>Similarly, for all decompositions <c>C1 ++ C2 = C</c> of a - cipher text message <c>C</c> (where the length of all quantities - are multiples of 8 bytes), the decryption <c>P</c> of <c>C</c> - is equal to <c>P1 ++ P2</c>, where <c>P1</c> is obtained by - decrypting <c>C1</c> with <c>Key</c> and the initializing vector - <c>IVec</c>, and where <c>P2</c> is obtained by decrypting - <c>C2</c> with <c>Key</c> and the initializing vector - <c>last8(C1)</c>, where <c>last8(Binary)</c> is as above. - </p> - <p>For DES3 (which uses three 64 bit keys) the situation is the - same. - </p> - </section> + </funcs> + + <!-- Maybe put this in the users guide --> + <!-- <section> --> + <!-- <title>DES in CBC mode</title> --> + <!-- <p>The Data Encryption Standard (DES) defines an algorithm for --> + <!-- encrypting and decrypting an 8 byte quantity using an 8 byte key --> + <!-- (actually only 56 bits of the key is used). --> + <!-- </p> --> + <!-- <p>When it comes to encrypting and decrypting blocks that are --> + <!-- multiples of 8 bytes various modes are defined (NIST SP --> + <!-- 800-38A). One of those modes is the Cipher Block Chaining (CBC) --> + <!-- mode, where the encryption of an 8 byte segment depend not only --> + <!-- of the contents of the segment itself, but also on the result of --> + <!-- encrypting the previous segment: the encryption of the previous --> + <!-- segment becomes the initializing vector of the encryption of the --> + <!-- current segment. --> + <!-- </p> --> + <!-- <p>Thus the encryption of every segment depends on the encryption --> + <!-- key (which is secret) and the encryption of the previous --> + <!-- segment, except the first segment which has to be provided with --> + <!-- an initial initializing vector. That vector could be chosen at --> + <!-- random, or be a counter of some kind. It does not have to be --> + <!-- secret. --> + <!-- </p> --> + <!-- <p>The following example is drawn from the old FIPS 81 standard --> + <!-- (replaced by NIST SP 800-38A), where both the plain text and the --> + <!-- resulting cipher text is settled. The following code fragment --> + <!-- returns `true'. --> + <!-- </p> --> + <!-- <pre><![CDATA[ --> + + <!-- Key = <<16#01,16#23,16#45,16#67,16#89,16#ab,16#cd,16#ef>>, --> + <!-- IVec = <<16#12,16#34,16#56,16#78,16#90,16#ab,16#cd,16#ef>>, --> + <!-- P = "Now is the time for all ", --> + <!-- C = crypto:des_cbc_encrypt(Key, IVec, P), --> + <!-- % Which is the same as --> + <!-- P1 = "Now is t", P2 = "he time ", P3 = "for all ", --> + <!-- C1 = crypto:des_cbc_encrypt(Key, IVec, P1), --> + <!-- C2 = crypto:des_cbc_encrypt(Key, C1, P2), --> + <!-- C3 = crypto:des_cbc_encrypt(Key, C2, P3), --> + + <!-- C = <<C1/binary, C2/binary, C3/binary>>, --> + <!-- C = <<16#e5,16#c7,16#cd,16#de,16#87,16#2b,16#f2,16#7c, --> + <!-- 16#43,16#e9,16#34,16#00,16#8c,16#38,16#9c,16#0f, --> + <!-- 16#68,16#37,16#88,16#49,16#9a,16#7c,16#05,16#f6>>, --> + <!-- <<"Now is the time for all ">> == --> + <!-- crypto:des_cbc_decrypt(Key, IVec, C). --> + <!-- ]]></pre> --> + <!-- <p>The following is true for the DES CBC mode. For all --> + <!-- decompositions <c>P1 ++ P2 = P</c> of a plain text message --> + <!-- <c>P</c> (where the length of all quantities are multiples of 8 --> + <!-- bytes), the encryption <c>C</c> of <c>P</c> is equal to <c>C1 ++ --> + <!-- C2</c>, where <c>C1</c> is obtained by encrypting <c>P1</c> with --> + <!-- <c>Key</c> and the initializing vector <c>IVec</c>, and where --> + <!-- <c>C2</c> is obtained by encrypting <c>P2</c> with <c>Key</c> --> + <!-- and the initializing vector <c>last8(C1)</c>, --> + <!-- where <c>last(Binary)</c> denotes the last 8 bytes of the --> + <!-- binary <c>Binary</c>. --> + <!-- </p> --> + <!-- <p>Similarly, for all decompositions <c>C1 ++ C2 = C</c> of a --> + <!-- cipher text message <c>C</c> (where the length of all quantities --> + <!-- are multiples of 8 bytes), the decryption <c>P</c> of <c>C</c> --> + <!-- is equal to <c>P1 ++ P2</c>, where <c>P1</c> is obtained by --> + <!-- decrypting <c>C1</c> with <c>Key</c> and the initializing vector --> + <!-- <c>IVec</c>, and where <c>P2</c> is obtained by decrypting --> + <!-- <c>C2</c> with <c>Key</c> and the initializing vector --> + <!-- <c>last8(C1)</c>, where <c>last8(Binary)</c> is as above. --> + <!-- </p> --> + <!-- <p>For DES3 (which uses three 64 bit keys) the situation is the --> + <!-- same. --> + <!-- </p> --> + <!-- </section> --> </erlref> diff --git a/lib/crypto/doc/src/crypto_app.xml b/lib/crypto/doc/src/crypto_app.xml index 8371db1ff2..6d26076c04 100644 --- a/lib/crypto/doc/src/crypto_app.xml +++ b/lib/crypto/doc/src/crypto_app.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE appref SYSTEM "appref.dtd"> <appref> @@ -24,81 +24,28 @@ </legalnotice> <title>crypto</title> - <prepared>Peter Högfeldt</prepared> - <responsible>Peter Högfeldt</responsible> - <docno></docno> - <approved>Peter Högfeldt</approved> - <checked>Peter Högfeldt</checked> - <date>2003-06-01</date> - <rev>B</rev> <file>crypto_app.sgml</file> </header> <app>crypto</app> <appsummary>The Crypto Application</appsummary> <description> - <p>The purpose of the Crypto application is to provide message - digest and DES encryption for SMNPv3. It provides computation of - message digests MD5 and SHA, and CBC-DES encryption and - decryption.</p> - <p></p> + <p>The purpose of the Crypto application is to provide an Erlang API + to cryptographic functions, see <seealso marker="crypto">crypto(3)</seealso>. + Note that the API is on a fairly low level and there are some + corresponding API functions available in <seealso marker="public_key:public_key">public_key(3)</seealso>, + on a higher abstraction level, that uses the crypto application in its implementation. + </p> </description> <section> - <title>Configuration</title> - <p>The following environment configuration parameters are defined - for the Crypto application. Refer to application(3) for more - information about configuration parameters. - </p> - <taglist> - <tag><c><![CDATA[debug = true | false <optional>]]></c></tag> - <item> - <p>Causes debug information to be written to standard - error or standard output. Default is <c>false</c>. - </p> - </item> - </taglist> - </section> + <title>DEPENDENCIES</title> - <section> - <title>OpenSSL libraries</title> - <p>The current implementation of the Erlang Crypto application is - based on the <em>OpenSSL</em> package version 0.9.8 or higher. - There are source and binary releases on the web. - </p> + <p>The current crypto implementation uses nifs to interface OpenSSLs crypto library + and requires <em>OpenSSL</em> package version 0.9.8 or higher.</p> <p>Source releases of OpenSSL can be downloaded from the <url href="http://www.openssl.org">OpenSSL</url> project home page, - or mirror sites listed there. - </p> - <p>The same URL also contains links to some compiled binaries and - libraries of OpenSSL (see the <c>Related/Binaries</c> menu) of - which the <url href="http://www.shininglightpro.com/search.php?searchname=Win32+OpenSSL">Shining Light Productions Win32 and OpenSSL</url> pages are of - interest for the Win32 user. - </p> - <p>For some Unix flavours there are binary packages available - on the net. - </p> - <p>If you cannot find a suitable binary OpenSSL package, you - have to fetch an OpenSSL source release and compile it. - </p> - <p>You then have to compile and install the library - <c>libcrypto.so</c> (Unix), or the library <c>libeay32.dll</c> - (Win32). - </p> - <p>For Unix The <c>crypto_drv</c> dynamic driver is delivered linked - to OpenSSL libraries in <c>/usr/local/lib</c>, but the default - dynamic linking will also accept libraries in <c>/lib</c> and - <c>/usr/lib</c>. - </p> - <p>If that is not applicable to the particular Unix operating - system used, the example <c>Makefile</c> in the Crypto - <c>priv/obj</c> directory, should be used as a basis for - relinking the final version of the port program. - </p> - <p>For <c>Win32</c> it is only required that the library can be - found from the <c>PATH</c> environment variable, or that they - reside in the appropriate <c>SYSTEM32</c> directory; hence no - particular relinking is need. Hence no example <c>Makefile</c> - for Win32 is provided.</p> - </section> + or mirror sites listed there. + </p> + </section> <section> <title>SEE ALSO</title> diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 1d0a9943c3..f4e157198c 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -21,104 +21,220 @@ -module(crypto). --export([start/0, stop/0, info/0, info_lib/0, algorithms/0, version/0]). +-export([start/0, stop/0, info_lib/0, algorithms/0, version/0]). -export([hash/2, hash_init/1, hash_update/2, hash_final/1]). +-export([sign/4, verify/5]). +-export([generate_key/2, generate_key/3, compute_key/4]). +-export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]). +-export([exor/2, strong_rand_bytes/1, mod_pow/3]). +-export([rand_bytes/1, rand_bytes/3, rand_uniform/2]). +-export([block_encrypt/3, block_decrypt/3, block_encrypt/4, block_decrypt/4]). +-export([next_iv/2, next_iv/3]). +-export([stream_init/2, stream_init/3, stream_encrypt/2, stream_decrypt/2]). +-export([public_encrypt/4, private_decrypt/4]). +-export([private_encrypt/4, public_decrypt/4]). + +-export([dh_generate_parameters/2, dh_check/1]). %% Testing see + +%% DEPRECATED +%% Replaced by hash_* -export([md4/1, md4_init/0, md4_update/2, md4_final/1]). -export([md5/1, md5_init/0, md5_update/2, md5_final/1]). -export([sha/1, sha_init/0, sha_update/2, sha_final/1]). --export([sha224/1, sha224_init/0, sha224_update/2, sha224_final/1]). --export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]). --export([sha384/1, sha384_init/0, sha384_update/2, sha384_final/1]). --export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]). +-deprecated({md4, 1, next_major_release}). +-deprecated({md5, 1, next_major_release}). +-deprecated({sha, 1, next_major_release}). +-deprecated({md4_init, 0, next_major_release}). +-deprecated({md5_init, 0, next_major_release}). +-deprecated({sha_init, 0, next_major_release}). +-deprecated({md4_update, 2, next_major_release}). +-deprecated({md5_update, 2, next_major_release}). +-deprecated({sha_update, 2, next_major_release}). +-deprecated({md4_final, 1, next_major_release}). +-deprecated({md5_final, 1, next_major_release}). +-deprecated({sha_final, 1, next_major_release}). + +%% Replaced by hmac_* -export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]). --export([sha224_mac/2, sha224_mac/3]). --export([sha256_mac/2, sha256_mac/3]). --export([sha384_mac/2, sha384_mac/3]). --export([sha512_mac/2, sha512_mac/3]). --export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]). +-deprecated({md5_mac, 2, next_major_release}). +-deprecated({md5_mac_96, 2, next_major_release}). +-deprecated({sha_mac, 2, next_major_release}). +-deprecated({sha_mac, 3, next_major_release}). +-deprecated({sha_mac_96, 2, next_major_release}). + +%% Replaced by sign/verify +-export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]). +-export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]). +-deprecated({dss_verify, 3, next_major_release}). +-deprecated({dss_verify, 4, next_major_release}). +-deprecated({rsa_verify, 3, next_major_release}). +-deprecated({rsa_verify, 4, next_major_release}). +-deprecated({dss_sign, 2, next_major_release}). +-deprecated({dss_sign, 3, next_major_release}). +-deprecated({rsa_sign, 2, next_major_release}). +-deprecated({rsa_sign, 3, next_major_release}). + +%% Replaced by generate_key +-export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]). +-deprecated({dh_generate_key, 1, next_major_release}). +-deprecated({dh_generate_key, 2, next_major_release}). +-deprecated({dh_compute_key, 3, next_major_release}). + +%% Replaced by mod_exp_prim and no longer needed +-export([mod_exp/3, mpint/1, erlint/1, strong_rand_mpint/3]). +-deprecated({mod_exp, 3, next_major_release}). +-deprecated({mpint, 1, next_major_release}). +-deprecated({erlint, 1, next_major_release}). +-deprecated({strong_rand_mpint, 3, next_major_release}). + +%% Replaced by block_* -export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]). +-export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]). -export([des_ecb_encrypt/2, des_ecb_decrypt/2]). +-export([des_ede3_cbc_encrypt/5, des_ede3_cbc_decrypt/5]). -export([des_cfb_encrypt/3, des_cfb_decrypt/3, des_cfb_ivec/2]). --export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]). -export([des3_cfb_encrypt/5, des3_cfb_decrypt/5]). +-deprecated({des_cbc_encrypt, 3, next_major_release}). +-deprecated({des_cbc_decrypt, 3, next_major_release}). +-deprecated({des_cbc_ivec, 1, next_major_release}). +-deprecated({des3_cbc_encrypt, 5, next_major_release}). +-deprecated({des3_cbc_decrypt, 5, next_major_release}). +-deprecated({des_ecb_encrypt, 2, next_major_release}). +-deprecated({des_ecb_decrypt, 2, next_major_release}). +-deprecated({des_ede3_cbc_encrypt, 5, next_major_release}). +-deprecated({des_ede3_cbc_decrypt, 5, next_major_release}). +-deprecated({des_cfb_encrypt, 3, next_major_release}). +-deprecated({des_cfb_decrypt, 3, next_major_release}). +-deprecated({des_cfb_ivec, 2, next_major_release}). +-deprecated({des3_cfb_encrypt, 5, next_major_release}). +-deprecated({des3_cfb_decrypt, 5, next_major_release}). -export([blowfish_ecb_encrypt/2, blowfish_ecb_decrypt/2]). -export([blowfish_cbc_encrypt/3, blowfish_cbc_decrypt/3]). -export([blowfish_cfb64_encrypt/3, blowfish_cfb64_decrypt/3]). -export([blowfish_ofb64_encrypt/3]). --export([des_ede3_cbc_encrypt/5, des_ede3_cbc_decrypt/5]). +-deprecated({blowfish_ecb_encrypt, 2, next_major_release}). +-deprecated({blowfish_ecb_decrypt, 2, next_major_release}). +-deprecated({blowfish_cbc_encrypt, 3, next_major_release}). +-deprecated({blowfish_cbc_decrypt, 3, next_major_release}). +-deprecated({blowfish_cfb64_encrypt, 3, next_major_release}). +-deprecated({blowfish_cfb64_decrypt, 3, next_major_release}). +-deprecated({blowfish_ofb64_encrypt, 3, next_major_release}). -export([aes_cfb_128_encrypt/3, aes_cfb_128_decrypt/3]). --export([exor/2]). --export([rc4_encrypt/2, rc4_set_key/1, rc4_encrypt_with_state/2]). --export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3, rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]). --export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]). --export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]). --export([rsa_public_encrypt/3, rsa_private_decrypt/3]). --export([rsa_private_encrypt/3, rsa_public_decrypt/3]). --export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]). --export([rand_bytes/1, rand_bytes/3, rand_uniform/2]). --export([strong_rand_bytes/1, strong_rand_mpint/3]). --export([mod_exp/3, mod_exp_prime/3, mpint/1, erlint/1]). --export([srp_generate_key/4, srp_generate_key/3, - srp_generate_key/5, srp_compute_key/6, srp_compute_key/7, srp_compute_key/8]). - -%% -export([idea_cbc_encrypt/3, idea_cbc_decrypt/3]). -export([aes_cbc_128_encrypt/3, aes_cbc_128_decrypt/3]). -export([aes_cbc_256_encrypt/3, aes_cbc_256_decrypt/3]). -export([aes_cbc_ivec/1]). --export([aes_ctr_encrypt/3, aes_ctr_decrypt/3]). +-deprecated({aes_cfb_128_encrypt, 3, next_major_release}). +-deprecated({aes_cfb_128_decrypt, 3, next_major_release}). +-deprecated({aes_cbc_128_encrypt, 3, next_major_release}). +-deprecated({aes_cbc_128_decrypt, 3, next_major_release}). +-deprecated({aes_cbc_256_encrypt, 3, next_major_release}). +-deprecated({aes_cbc_256_decrypt, 3, next_major_release}). +-deprecated({aes_cbc_ivec, 1, next_major_release}). +-export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3]). +-export([rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]). +-deprecated({rc2_cbc_encrypt, 3, next_major_release}). +-deprecated({rc2_cbc_decrypt, 3, next_major_release}). +%% allready replaced by above! +-deprecated({rc2_40_cbc_encrypt, 3, next_major_release}). +-deprecated({rc2_40_cbc_decrypt, 3, next_major_release}). + +%% Replaced by stream_* -export([aes_ctr_stream_init/2, aes_ctr_stream_encrypt/2, aes_ctr_stream_decrypt/2]). - --export([dh_generate_parameters/2, dh_check/1]). %% Testing see below - - --define(FUNC_LIST, [md4, md4_init, md4_update, md4_final, +-export([rc4_set_key/1, rc4_encrypt_with_state/2]). +-deprecated({aes_ctr_stream_init, 2, next_major_release}). +-deprecated({aes_ctr_stream_encrypt, 2, next_major_release}). +-deprecated({aes_ctr_stream_decrypt, 2, next_major_release}). +-deprecated({rc4_set_key, 1, next_major_release}). +-deprecated({rc4_encrypt_with_state, 2, next_major_release}). + +%% Not needed special case of stream_* +-export([aes_ctr_encrypt/3, aes_ctr_decrypt/3, rc4_encrypt/2]). +-deprecated({aes_ctr_encrypt, 3, next_major_release}). +-deprecated({aes_ctr_decrypt, 3, next_major_release}). +-deprecated({rc4_encrypt, 2, next_major_release}). + +%% Replace by public/private_encrypt/decrypt +-export([rsa_public_encrypt/3, rsa_private_decrypt/3]). +-export([rsa_private_encrypt/3, rsa_public_decrypt/3]). +-deprecated({rsa_public_encrypt, 3, next_major_release}). +-deprecated({rsa_private_decrypt, 3, next_major_release}). +-deprecated({rsa_public_decrypt, 3, next_major_release}). +-deprecated({rsa_private_encrypt, 3, next_major_release}). + +%% Replaced by crypto:module_info() +-export([info/0]). +-deprecated({info, 0, next_major_release}). + +-define(FUNC_LIST, [hash, hash_init, hash_update, hash_final, + hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, + %% deprecated + md4, md4_init, md4_update, md4_final, md5, md5_init, md5_update, md5_final, sha, sha_init, sha_update, sha_final, - sha224, sha224_init, sha224_update, sha224_final, - sha256, sha256_init, sha256_update, sha256_final, - sha384, sha384_init, sha384_update, sha384_final, - sha512, sha512_init, sha512_update, sha512_final, md5_mac, md5_mac_96, sha_mac, sha_mac_96, - sha224_mac, sha256_mac, sha384_mac, sha512_mac, + %% + block_encrypt, block_decrypt, + %% deprecated des_cbc_encrypt, des_cbc_decrypt, des_cfb_encrypt, des_cfb_decrypt, des_ecb_encrypt, des_ecb_decrypt, des3_cbc_encrypt, des3_cbc_decrypt, des3_cfb_encrypt, des3_cfb_decrypt, aes_cfb_128_encrypt, aes_cfb_128_decrypt, + rc2_cbc_encrypt, rc2_cbc_decrypt, + rc2_40_cbc_encrypt, rc2_40_cbc_decrypt, + aes_cbc_128_encrypt, aes_cbc_128_decrypt, + aes_cbc_256_encrypt, aes_cbc_256_decrypt, + blowfish_cbc_encrypt, blowfish_cbc_decrypt, + blowfish_cfb64_encrypt, blowfish_cfb64_decrypt, + blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt, + %% rand_bytes, strong_rand_bytes, - strong_rand_mpint, rand_uniform, - mod_exp, mod_exp_prime, + mod_pow, + exor, + %% deprecated + mod_exp,strong_rand_mpint,erlint, mpint, + %% + sign, verify, generate_key, compute_key, + %% deprecated dss_verify,dss_sign, rsa_verify,rsa_sign, rsa_public_encrypt,rsa_private_decrypt, rsa_private_encrypt,rsa_public_decrypt, dh_generate_key, dh_compute_key, - aes_cbc_128_encrypt, aes_cbc_128_decrypt, - exor, + %% + stream_init, stream_encrypt, stream_decrypt, + %% deprecated rc4_encrypt, rc4_set_key, rc4_encrypt_with_state, - rc2_40_cbc_encrypt, rc2_40_cbc_decrypt, - %% idea_cbc_encrypt, idea_cbc_decrypt, - aes_cbc_256_encrypt, aes_cbc_256_decrypt, aes_ctr_encrypt, aes_ctr_decrypt, aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt, - aes_cbc_ivec, blowfish_cbc_encrypt, blowfish_cbc_decrypt, - blowfish_cfb64_encrypt, blowfish_cfb64_decrypt, - blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt, - des_cbc_ivec, des_cfb_ivec, erlint, mpint, - hash, hash_init, hash_update, hash_final, - hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, info, - rc2_cbc_encrypt, rc2_cbc_decrypt, - srp_generate_key, srp_compute_key, + %% + next_iv, + %% deprecated + aes_cbc_ivec, + des_cbc_ivec, des_cfb_ivec, + info, + %% info_lib, algorithms]). +-type mpint() :: binary(). -type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'. -type dss_digest_type() :: 'none' | 'sha'. +%%-type ecdsa_digest_type() :: 'md5' | 'sha' | 'sha256' | 'sha384' | 'sha512'. -type data_or_digest() :: binary() | {digest, binary()}. -type crypto_integer() :: binary() | integer(). +-type ec_key_res() :: any(). %% nif resource +-type ec_named_curve() :: atom(). +-type ec_point() :: crypto_integer(). +-type ec_basis() :: {tpbasis, K :: non_neg_integer()} | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | onbasis. +-type ec_field() :: {prime_field, Prime :: integer()} | {characteristic_two_field, M :: integer(), Basis :: ec_basis()}. +-type ec_prime() :: {A :: crypto_integer(), B :: crypto_integer(), Seed :: binary() | none}. +-type ec_curve_spec() :: {Field :: ec_field(), Prime :: ec_prime(), Point :: crypto_integer(), Order :: integer(), CoFactor :: none | integer()}. +-type ec_curve() :: ec_named_curve() | ec_curve_spec(). +-type ec_key() :: {Curve :: ec_curve(), PrivKey :: binary() | undefined, PubKey :: ec_point() | undefined}. -define(nif_stub,nif_stub_error(?LINE)). @@ -565,6 +681,110 @@ sha512_mac(Key, Data, MacSz) -> sha512_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub. + +%% Ecrypt/decrypt %%% + +-spec block_encrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | + blowfish_cfb64 | aes_cbc128 | aes_cfb128 | aes_cbc256 | rc2_cbc, + Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). + +block_encrypt(des_cbc, Key, Ivec, Data) -> + des_cbc_encrypt(Key, Ivec, Data); +block_encrypt(des_cfb, Key, Ivec, Data) -> + des_cfb_encrypt(Key, Ivec, Data); +block_encrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) -> + des3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data); +block_encrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) -> + des3_cfb_encrypt(Key1, Key2, Key3, Ivec, Data); +block_encrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) -> + des_ede3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data); +block_encrypt(blowfish_cbc, Key, Ivec, Data) -> + blowfish_cbc_encrypt(Key, Ivec, Data); +block_encrypt(blowfish_cfb64, Key, Ivec, Data) -> + blowfish_cfb64_encrypt(Key, Ivec, Data); +block_encrypt(blowfish_ofb64, Key, Ivec, Data) -> + blowfish_ofb64_encrypt(Key, Ivec, Data); +block_encrypt(aes_cbc128, Key, Ivec, Data) -> + aes_cbc_128_encrypt(Key, Ivec, Data); +block_encrypt(aes_cbc256, Key, Ivec, Data) -> + aes_cbc_256_encrypt(Key, Ivec, Data); +block_encrypt(aes_cfb128, Key, Ivec, Data) -> + aes_cfb_128_encrypt(Key, Ivec, Data); +block_encrypt(rc2_cbc, Key, Ivec, Data) -> + rc2_cbc_encrypt(Key, Ivec, Data). + +-spec block_decrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc | + blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cbc256 | aes_cfb128 | rc2_cbc, + Key::iodata(), Ivec::binary(), Data::iodata()) -> binary(). + +block_decrypt(des_cbc, Key, Ivec, Data) -> + des_cbc_decrypt(Key, Ivec, Data); +block_decrypt(des_cfb, Key, Ivec, Data) -> + des_cfb_decrypt(Key, Ivec, Data); +block_decrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) -> + des3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data); +block_decrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) -> + des3_cfb_decrypt(Key1, Key2, Key3, Ivec, Data); +block_decrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) -> + des_ede3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data); +block_decrypt(blowfish_cbc, Key, Ivec, Data) -> + blowfish_cbc_decrypt(Key, Ivec, Data); +block_decrypt(blowfish_cfb64, Key, Ivec, Data) -> + blowfish_cfb64_decrypt(Key, Ivec, Data); +block_decrypt(blowfish_ofb, Key, Ivec, Data) -> + blowfish_ofb64_decrypt(Key, Ivec, Data); +block_decrypt(aes_cbc128, Key, Ivec, Data) -> + aes_cbc_128_decrypt(Key, Ivec, Data); +block_decrypt(aes_cbc256, Key, Ivec, Data) -> + aes_cbc_256_decrypt(Key, Ivec, Data); +block_decrypt(aes_cfb128, Key, Ivec, Data) -> + aes_cfb_128_decrypt(Key, Ivec, Data); +block_decrypt(rc2_cbc, Key, Ivec, Data) -> + rc2_cbc_decrypt(Key, Ivec, Data). + +-spec block_encrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary(). + +block_encrypt(des_ecb, Key, Data) -> + des_ecb_encrypt(Key, Data); +block_encrypt(blowfish_ecb, Key, Data) -> + blowfish_ecb_encrypt(Key, Data). + +-spec block_decrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary(). + +block_decrypt(des_ecb, Key, Data) -> + des_ecb_decrypt(Key, Data); +block_decrypt(blowfish_ecb, Key, Data) -> + blowfish_ecb_decrypt(Key, Data). + +-spec next_iv(des_cbc | aes_cbc, Data::iodata()) -> binary(). + +next_iv(des_cbc, Data) -> + des_cbc_ivec(Data); +next_iv(aes_cbc, Data) -> + aes_cbc_ivec(Data). + +-spec next_iv(des_cbf, Ivec::binary(), Data::iodata()) -> binary(). + +next_iv(des_cbf, Ivec, Data) -> + des_cfb_ivec(Ivec, Data). + +stream_init(aes_ctr, Key, Ivec) -> + {aes_ctr, aes_ctr_stream_init(Key, Ivec)}. +stream_init(rc4, Key) -> + {rc4, rc4_set_key(Key)}. +stream_encrypt({aes_ctr, State}, Data) -> + {State, Cipher} = aes_ctr_stream_encrypt(State, Data), + {{aes_ctr, State}, Cipher}; +stream_encrypt({rc4, State0}, Data) -> + {State, Cipher} = rc4_encrypt_with_state(State0, Data), + {{rc4, State}, Cipher}. +stream_decrypt({aes_ctr, State0}, Data) -> + {State, Text} = aes_ctr_stream_decrypt(State0, Data), + {{aes_ctr, State}, Text}; +stream_decrypt({rc4, State0}, Data) -> + {State, Text} = rc4_encrypt_with_state (State0, Data), + {{rc4, State}, Text}. + %% %% CRYPTO FUNCTIONS %% @@ -713,8 +933,12 @@ blowfish_cfb64_decrypt(Key, IVec, Data) -> bf_cfb64_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. +blowfish_ofb64_decrypt(Key, Ivec, Data) -> + blowfish_ofb64_encrypt(Key, Ivec, Data). + blowfish_ofb64_encrypt(_Key, _IVec, _Data) -> ?nif_stub. + %% %% AES in cipher feedback mode (CFB) %% @@ -798,9 +1022,9 @@ mod_exp(Base, Exponent, Modulo) mod_exp(Base, Exponent, Modulo) -> mod_exp_nif(mpint_to_bin(Base),mpint_to_bin(Exponent),mpint_to_bin(Modulo), 4). --spec mod_exp_prime(binary(), binary(), binary()) -> binary() | error. -mod_exp_prime(Base, Exponent, Prime) -> - case mod_exp_nif(Base, Exponent, Prime, 0) of +-spec mod_pow(binary()|integer(), binary()|integer(), binary()|integer()) -> binary() | error. +mod_pow(Base, Exponent, Prime) -> + case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of <<0>> -> error; R -> R end. @@ -819,19 +1043,40 @@ mod_exp_nif(_Base,_Exp,_Mod,_bin_hdr) -> ?nif_stub. %% Key = [P,Q,G,Y] P,Q,G=DSSParams Y=PublicKey dss_verify(Data,Signature,Key) -> - dss_verify(sha, Data, Signature, Key). -dss_verify(_Type,_Data,_Signature,_Key) -> ?nif_stub. + dss_verify(sha, Data, Signature, Key). + +dss_verify(Type,Data,Signature,Key) when is_binary(Data), Type=/=none -> + verify(dss,Type,mpint_to_bin(Data),mpint_to_bin(Signature),map_mpint_to_bin(Key)); +dss_verify(Type,Digest,Signature,Key) -> + verify(dss,Type,Digest,mpint_to_bin(Signature),map_mpint_to_bin(Key)). % Key = [E,N] E=PublicExponent N=PublicModulus rsa_verify(Data,Signature,Key) -> - rsa_verify_nif(sha, Data,Signature,Key). -rsa_verify(Type, DataOrDigest, Signature, Key) -> - case rsa_verify_nif(Type, DataOrDigest, Signature, Key) of + rsa_verify(sha, Data,Signature,Key). +rsa_verify(Type, Data, Signature, Key) when is_binary(Data) -> + verify(rsa, Type, mpint_to_bin(Data), mpint_to_bin(Signature), map_mpint_to_bin(Key)); +rsa_verify(Type, Digest, Signature, Key) -> + verify(rsa, Type, Digest, mpint_to_bin(Signature), map_mpint_to_bin(Key)). + + +verify(dss, Type, Data, Signature, Key) -> + dss_verify_nif(Type, Data, Signature, map_ensure_int_as_bin(Key)); + +verify(rsa, Type, DataOrDigest, Signature, Key) -> + case rsa_verify_nif(Type, DataOrDigest, Signature, map_ensure_int_as_bin(Key)) of notsup -> erlang:error(notsup); Bool -> Bool + end; +verify(ecdsa, Type, DataOrDigest, Signature, [Key, Curve]) -> + case ecdsa_verify_nif(Type, DataOrDigest, Signature, term_to_ec_key({Curve, undefined, Key})) of + notsup -> erlang:error(notsup); + Bool -> Bool end. + +dss_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. +ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Key) -> ?nif_stub. %% @@ -845,24 +1090,103 @@ rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub. dss_sign(DataOrDigest,Key) -> dss_sign(sha,DataOrDigest,Key). -dss_sign(Type, DataOrDigest, Key) -> - case dss_sign_nif(Type,DataOrDigest,Key) of - error -> erlang:error(badkey, [DataOrDigest, Key]); - Sign -> Sign - end. +dss_sign(Type, Data, Key) when is_binary(Data), Type=/=none -> + sign(dss, Type, mpint_to_bin(Data), map_mpint_to_bin(Key)); +dss_sign(Type, Digest, Key) -> + sign(dss, Type, Digest, map_mpint_to_bin(Key)). -dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub. %% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent rsa_sign(DataOrDigest,Key) -> rsa_sign(sha, DataOrDigest, Key). -rsa_sign(Type, DataOrDigest, Key) -> - case rsa_sign_nif(Type,DataOrDigest,Key) of + +rsa_sign(Type, Data, Key) when is_binary(Data) -> + sign(rsa, Type, mpint_to_bin(Data), map_mpint_to_bin(Key)); +rsa_sign(Type, Digest, Key) -> + sign(rsa, Type, Digest, map_mpint_to_bin(Key)). + +map_mpint_to_bin(List) -> + lists:map(fun(E) -> mpint_to_bin(E) end, List ). + +map_ensure_int_as_bin([H|_]=List) when is_integer(H) -> + lists:map(fun(E) -> int_to_bin(E) end, List); +map_ensure_int_as_bin(List) -> + List. + +ensure_int_as_bin(Int) when is_integer(Int) -> + int_to_bin(Int); +ensure_int_as_bin(Bin) -> + Bin. + +map_to_norm_bin([H|_]=List) when is_integer(H) -> + lists:map(fun(E) -> int_to_bin(E) end, List); +map_to_norm_bin(List) -> + lists:map(fun(E) -> mpint_to_bin(E) end, List). + + +sign(rsa, Type, DataOrDigest, Key) -> + case rsa_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of + error -> erlang:error(badkey, [Type,DataOrDigest,Key]); + Sign -> Sign + end; +sign(dss, Type, DataOrDigest, Key) -> + case dss_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of + error -> erlang:error(badkey, [DataOrDigest, Key]); + Sign -> Sign + end; +sign(ecdsa, Type, DataOrDigest, [Key, Curve]) -> + case ecdsa_sign_nif(Type, DataOrDigest, term_to_ec_key({Curve, Key, undefined})) of error -> erlang:error(badkey, [Type,DataOrDigest,Key]); Sign -> Sign end. rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub. +dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub. +ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub. + + + + +-spec public_encrypt(rsa, binary(), [binary()], rsa_padding()) -> + binary(). +-spec public_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> + binary(). +-spec private_encrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> + binary(). +-spec private_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) -> + binary(). + +public_encrypt(rsa, BinMesg, Key, Padding) -> + case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of + error -> + erlang:error(encrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. + +%% Binary, Key = [E,N,D] +private_decrypt(rsa, BinMesg, Key, Padding) -> + case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of + error -> + erlang:error(decrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. + + +%% Binary, Key = [E,N,D] +private_encrypt(rsa, BinMesg, Key, Padding) -> + case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of + error -> + erlang:error(encrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. + +%% Binary, Key = [E,N] +public_decrypt(rsa, BinMesg, Key, Padding) -> + case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of + error -> + erlang:error(decrypt_failed, [BinMesg,Key, Padding]); + Sign -> Sign + end. %% @@ -872,16 +1196,16 @@ rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub. -spec rsa_public_encrypt(binary(), [binary()], rsa_padding()) -> binary(). --spec rsa_public_decrypt(binary(), [binary()], rsa_padding()) -> +-spec rsa_public_decrypt(binary(), [integer() | mpint()], rsa_padding()) -> binary(). --spec rsa_private_encrypt(binary(), [binary()], rsa_padding()) -> +-spec rsa_private_encrypt(binary(), [integer() | mpint()], rsa_padding()) -> binary(). --spec rsa_private_decrypt(binary(), [binary()], rsa_padding()) -> +-spec rsa_private_decrypt(binary(), [integer() | mpint()], rsa_padding()) -> binary(). %% Binary, Key = [E,N] rsa_public_encrypt(BinMesg, Key, Padding) -> - case rsa_public_crypt(BinMesg, Key, Padding, true) of + case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of error -> erlang:error(encrypt_failed, [BinMesg,Key, Padding]); Sign -> Sign @@ -891,7 +1215,7 @@ rsa_public_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub. %% Binary, Key = [E,N,D] rsa_private_decrypt(BinMesg, Key, Padding) -> - case rsa_private_crypt(BinMesg, Key, Padding, false) of + case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of error -> erlang:error(decrypt_failed, [BinMesg,Key, Padding]); Sign -> Sign @@ -902,7 +1226,7 @@ rsa_private_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub. %% Binary, Key = [E,N,D] rsa_private_encrypt(BinMesg, Key, Padding) -> - case rsa_private_crypt(BinMesg, Key, Padding, true) of + case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of error -> erlang:error(encrypt_failed, [BinMesg,Key, Padding]); Sign -> Sign @@ -910,7 +1234,7 @@ rsa_private_encrypt(BinMesg, Key, Padding) -> %% Binary, Key = [E,N] rsa_public_decrypt(BinMesg, Key, Padding) -> - case rsa_public_crypt(BinMesg, Key, Padding, false) of + case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of error -> erlang:error(decrypt_failed, [BinMesg,Key, Padding]); Sign -> Sign @@ -1052,120 +1376,142 @@ dh_check([_Prime,_Gen]) -> ?nif_stub. {binary(),binary()}. dh_generate_key(DHParameters) -> - dh_generate_key(undefined, DHParameters). + dh_generate_key_nif(undefined, map_mpint_to_bin(DHParameters), 4). dh_generate_key(PrivateKey, DHParameters) -> - case dh_generate_key_nif(PrivateKey, DHParameters) of - error -> erlang:error(generation_failed, [PrivateKey,DHParameters]); - Res -> Res - end. + dh_generate_key_nif(mpint_to_bin(PrivateKey), map_mpint_to_bin(DHParameters), 4). -dh_generate_key_nif(_PrivateKey, _DHParameters) -> ?nif_stub. +dh_generate_key_nif(_PrivateKey, _DHParameters, _Mpint) -> ?nif_stub. %% DHParameters = [P (Prime)= mpint(), G(Generator) = mpint()] -%% MyPrivKey, OthersPublicKey = mpint() +%% MyPrivKey, OthersPublicKey = mpint() -spec dh_compute_key(binary(), binary(), [binary()]) -> binary(). dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) -> - case dh_compute_key_nif(OthersPublicKey,MyPrivateKey,DHParameters) of - error -> erlang:error(computation_failed, [OthersPublicKey,MyPrivateKey,DHParameters]); - Ret -> Ret - end. + compute_key(dh, mpint_to_bin(OthersPublicKey), mpint_to_bin(MyPrivateKey), + map_mpint_to_bin(DHParameters)). + dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub. +generate_key(Type, Params) -> + generate_key(Type, Params, undefined). + +generate_key(dh, DHParameters, PrivateKey) -> + dh_generate_key_nif(PrivateKey, map_ensure_int_as_bin(DHParameters), 0); + +generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, PrivArg) + when is_binary(Verifier), is_binary(Generator), is_binary(Prime), is_atom(Version) -> + Private = case PrivArg of + undefined -> random_bytes(32); + _ -> PrivArg + end, + host_srp_gen_key(Private, Verifier, Generator, Prime, Version); + +generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg) + when is_binary(Generator), is_binary(Prime), is_atom(Version) -> + Private = case PrivateArg of + undefined -> random_bytes(32); + _ -> PrivateArg + end, + user_srp_gen_key(Private, Generator, Prime); -%%% SRP --spec srp_generate_key(binary(), binary(), atom() | binary(), atom() | binary() ) -> {Public::binary(), Private::binary()}. -srp_generate_key(Verifier, Generator, Prime, Version) when is_binary(Verifier), - is_binary(Generator), - is_binary(Prime), - is_atom(Version) -> - Private = random_bytes(32), - server_srp_gen_key(Private, Verifier, Generator, Prime, Version); - -srp_generate_key(Generator, Prime, Version, Private) when is_binary(Generator), - is_binary(Prime), - is_atom(Version), - is_binary(Private) -> - client_srp_gen_key(Private, Generator, Prime). - --spec srp_generate_key(binary(), binary(), binary(), atom(), binary()) -> {Public::binary(), Private::binary()}. -srp_generate_key(Verifier, Generator, Prime, Version, Private) when is_binary(Verifier), - is_binary(Generator), - is_binary(Prime), - is_atom(Version), - is_binary(Private) - -> - server_srp_gen_key(Private, Verifier, Generator, Prime, Version). - --spec srp_generate_key(binary(), binary(), atom()) -> {Public::binary(), Private::binary()}. -srp_generate_key(Generator, Prime, Version) when is_binary(Generator), - is_binary(Prime), - is_atom(Version) -> - Private = random_bytes(32), - client_srp_gen_key(Private, Generator, Prime). - --spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), atom()| binary(), atom() | binary() ) -> binary(). -srp_compute_key(DerivedKey, Prime, Generator, ClientPublic, ClientPrivate, ServerPublic, Version) when - is_binary(Prime), +generate_key(ecdh, Curve, undefined) -> + ec_key_to_term(ec_key_generate(Curve)). + + +ec_key_generate(_Key) -> ?nif_stub. + + +compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) -> + case dh_compute_key_nif(OthersPublicKey,MyPrivateKey, map_ensure_int_as_bin(DHParameters)) of + error -> erlang:error(computation_failed, + [OthersPublicKey,MyPrivateKey,DHParameters]); + Ret -> Ret + end; + +compute_key(srp, HostPublic, {UserPublic, UserPrivate}, + {user, [DerivedKey, Prime, Generator, Version | ScramblerArg]}) when + is_binary(Prime), is_binary(Generator), - is_binary(ClientPublic), - is_binary(ClientPrivate), - is_binary(ServerPublic), + is_binary(UserPublic), + is_binary(UserPrivate), + is_binary(HostPublic), is_atom(Version) -> Multiplier = srp_multiplier(Version, Generator, Prime), - Scrambler = srp_scrambler(Version, ClientPublic, ServerPublic, Prime), - srp_client_secret_nif(ClientPrivate, Scrambler, ServerPublic, Multiplier, - Generator, DerivedKey, Prime); - -srp_compute_key(Verifier, Prime, ClientPublic, ServerPublic, ServerPrivate, Version, Scrambler) when + Scrambler = case ScramblerArg of + [] -> srp_scrambler(Version, UserPublic, HostPublic, Prime); + [S] -> S + end, + srp_user_secret_nif(UserPrivate, Scrambler, HostPublic, Multiplier, + Generator, DerivedKey, Prime); + +compute_key(srp, UserPublic, {HostPublic, HostPrivate}, + {host,[Verifier, Prime, Version | ScramblerArg]}) when is_binary(Verifier), - is_binary(Prime), - is_binary(ClientPublic), - is_binary(ServerPublic), - is_binary(ServerPrivate), - is_atom(Version), - is_binary(Scrambler) -> - srp_server_secret_nif(Verifier, ServerPrivate, Scrambler, ClientPublic, Prime). - --spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), binary(), atom(), binary()) -> binary(). -srp_compute_key(DerivedKey, Prime, Generator, ClientPublic, ClientPrivate, - ServerPublic, Version, Scrambler) when is_binary(DerivedKey), - is_binary(Prime), - is_binary(Generator), - is_binary(ClientPublic), - is_binary(ClientPrivate), - is_binary(ServerPublic), - is_atom(Version), - is_binary(Scrambler) -> - Multiplier = srp_multiplier(Version, Generator, Prime), - srp_client_secret_nif(ClientPrivate, Scrambler, ServerPublic, Multiplier, - Generator, DerivedKey, Prime). - --spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), atom()) -> binary(). -srp_compute_key(Verifier, Prime, ClientPublic, ServerPublic, ServerPrivate, Version) when - is_binary(Verifier), - is_binary(Prime), - is_binary(ClientPublic), - is_binary(ServerPublic), - is_binary(ServerPrivate), + is_binary(Prime), + is_binary(UserPublic), + is_binary(HostPublic), + is_binary(HostPrivate), is_atom(Version) -> - Scrambler = srp_scrambler(Version, ClientPublic, ServerPublic, Prime), - srp_server_secret_nif(Verifier, ServerPrivate, Scrambler, ClientPublic, Prime). + Scrambler = case ScramblerArg of + [] -> srp_scrambler(Version, UserPublic, HostPublic, Prime); + [S] -> S + end, + srp_host_secret_nif(Verifier, HostPrivate, Scrambler, UserPublic, Prime); + +compute_key(ecdh, Others, My, Curve) -> + ecdh_compute_key_nif(Others, term_to_ec_key({Curve,My,undefined})). + +ecdh_compute_key_nif(_Others, _My) -> ?nif_stub. + %% +%% EC +%% +ec_key_to_term(Key) -> + case ec_key_to_term_nif(Key) of + {PrivKey, PubKey} -> + {bin_to_int(PrivKey), PubKey}; + _ -> + erlang:error(conversion_failed) + end. + +ec_key_to_term_nif(_Key) -> ?nif_stub. + +term_to_nif_prime({prime_field, Prime}) -> + {prime_field, int_to_bin(Prime)}; +term_to_nif_prime(PrimeField) -> + PrimeField. +term_to_nif_curve({A, B, Seed}) -> + {ensure_int_as_bin(A), ensure_int_as_bin(B), Seed}. +term_to_nif_curve_parameters({PrimeField, Curve, BasePoint, Order, CoFactor}) -> + {term_to_nif_prime(PrimeField), term_to_nif_curve(Curve), ensure_int_as_bin(BasePoint), int_to_bin(Order), int_to_bin(CoFactor)}; +term_to_nif_curve_parameters(Curve) when is_atom(Curve) -> + %% named curve + Curve. + +-spec term_to_ec_key(ec_key()) -> ec_key_res(). +term_to_ec_key({Curve, undefined, PubKey}) -> + term_to_ec_key_nif(term_to_nif_curve_parameters(Curve), undefined, PubKey); +term_to_ec_key({Curve, PrivKey, PubKey}) -> + term_to_ec_key_nif(term_to_nif_curve_parameters(Curve), int_to_bin(PrivKey), PubKey). + +term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub. + + + %% LOCAL FUNCTIONS %% -client_srp_gen_key(Private, Generator, Prime) -> - case mod_exp_prime(Generator, Private, Prime) of +user_srp_gen_key(Private, Generator, Prime) -> + case mod_pow(Generator, Private, Prime) of error -> error; Public -> {Public, Private} end. -server_srp_gen_key(Private, Verifier, Generator, Prime, Version) -> +host_srp_gen_key(Private, Verifier, Generator, Prime, Version) -> Multiplier = srp_multiplier(Version, Generator, Prime), case srp_value_B_nif(Multiplier, Verifier, Generator, Private, Prime) of error -> @@ -1185,17 +1531,17 @@ srp_multiplier('6', _, _) -> srp_multiplier('3', _, _) -> <<1/integer>>. -srp_scrambler(Version, ClientPublic, ServerPublic, Prime) when Version == '6'; Version == '6a'-> +srp_scrambler(Version, UserPublic, HostPublic, Prime) when Version == '6'; Version == '6a'-> %% SHA1(PAD(A) | PAD(B)) from http://srp.stanford.edu/design.html PadLength = erlang:byte_size(Prime), C0 = sha_init(), - C1 = sha_update(C0, srp_pad_to(PadLength, ClientPublic)), - C2 = sha_update(C1, srp_pad_to(PadLength, ServerPublic)), + C1 = sha_update(C0, srp_pad_to(PadLength, UserPublic)), + C2 = sha_update(C1, srp_pad_to(PadLength, HostPublic)), sha_final(C2); -srp_scrambler('3', _, ServerPublic, _Prime) -> +srp_scrambler('3', _, HostPublic, _Prime) -> %% The parameter u is a 32-bit unsigned integer which takes its value %% from the first 32 bits of the SHA1 hash of B, MSB first. - <<U:32/bits, _/binary>> = sha(ServerPublic), + <<U:32/bits, _/binary>> = sha(HostPublic), U. srp_pad_length(Width, Length) -> @@ -1207,9 +1553,9 @@ srp_pad_to(Width, Binary) -> N -> << 0:(N*8), Binary/binary>> end. -srp_server_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub. +srp_host_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub. -srp_client_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub. +srp_user_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub. srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub. @@ -1253,10 +1599,12 @@ int_to_bin_neg(X,Ds) -> int_to_bin_neg(X bsr 8, [(X band 255)|Ds]). -bin_to_int(Bin) -> +bin_to_int(Bin) when is_binary(Bin) -> Bits = bit_size(Bin), <<Integer:Bits/integer>> = Bin, - Integer. + Integer; +bin_to_int(undefined) -> + undefined. %% int from integer in a binary with 32bit length erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) -> diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 08ecad3233..eddb6b83f9 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -76,6 +76,7 @@ rsa_encrypt_decrypt/1, dh/1, srp3/1, srp6/1, srp6a/1, + ec/1, exor_test/1, rc4_test/1, rc4_stream_test/1, @@ -105,7 +106,7 @@ groups() -> rand_uniform_test, strong_rand_test, rsa_verify_test, dsa_verify_test, rsa_sign_test, rsa_sign_hash_test, dsa_sign_test, dsa_sign_hash_test, - rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, exor_test, + rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, ec, exor_test, rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64, smp]}]. @@ -190,8 +191,8 @@ ldd_program() -> Ldd when is_list(Ldd) -> Ldd end. -%% -%% + + info(doc) -> ["Call the info function."]; info(suite) -> @@ -207,10 +208,10 @@ info(Config) when is_list(Config) -> ?line [] = Info -- Exports, ?line NotInInfo = Exports -- Info, io:format("NotInInfo = ~p\n", [NotInInfo]), - BlackList = lists:sort([des_ede3_cbc_decrypt, des_ede3_cbc_encrypt, - dh_check, dh_generate_parameters, - module_info, start, stop, version]), - ?line BlackList = NotInInfo, + %% BlackList = lists:sort([des_ede3_cbc_decrypt, des_ede3_cbc_encrypt, + %% dh_check, dh_generate_parameters, + %% module_info, start, stop, version]), + %% ?line BlackList = NotInInfo, ?line InfoLib = crypto:info_lib(), ?line [_|_] = InfoLib, @@ -221,10 +222,10 @@ info(Config) when is_list(Config) -> Me(T,Me); ([],_) -> ok - end, + end, ?line F(InfoLib,F), ?line crypto:stop() - end. + end. %% %% @@ -359,7 +360,7 @@ hmac_update_sha(Config) when is_list(Config) -> ?line Ctx2 = crypto:hmac_update(Ctx, Data), ?line Ctx3 = crypto:hmac_update(Ctx2, Data2), ?line Mac = crypto:hmac_final(Ctx3), - ?line Exp = crypto:sha_mac(Key, lists:flatten([Data, Data2])), + ?line Exp = crypto:hmac(sha, Key, lists:flatten([Data, Data2])), ?line m(Exp, Mac). hmac_update_sha256(doc) -> @@ -381,7 +382,7 @@ hmac_update_sha256_do() -> ?line Ctx2 = crypto:hmac_update(Ctx, Data), ?line Ctx3 = crypto:hmac_update(Ctx2, Data2), ?line Mac = crypto:hmac_final(Ctx3), - ?line Exp = crypto:sha256_mac(Key, lists:flatten([Data, Data2])), + ?line Exp = crypto:hmac(sha256, Key, lists:flatten([Data, Data2])), ?line m(Exp, Mac). hmac_update_sha512(doc) -> @@ -403,7 +404,7 @@ hmac_update_sha512_do() -> ?line Ctx2 = crypto:hmac_update(Ctx, Data), ?line Ctx3 = crypto:hmac_update(Ctx2, Data2), ?line Mac = crypto:hmac_final(Ctx3), - ?line Exp = crypto:sha512_mac(Key, lists:flatten([Data, Data2])), + ?line Exp = crypto:hmac(sha512, Key, lists:flatten([Data, Data2])), ?line m(Exp, Mac). hmac_update_md5(doc) -> @@ -618,68 +619,64 @@ hmac_rfc4231_sha512(suite) -> hmac_rfc4231_sha512(Config) when is_list(Config) -> if_supported(sha512, fun() -> hmac_rfc4231_sha512_do() end). -hmac_rfc4231_case(Hash, HashFun, case1, Exp) -> +hmac_rfc4231_case(Hash, case1, Exp) -> %% Test 1 Key = binary:copy(<<16#0b>>, 20), Data = <<"Hi There">>, - hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp); + hmac_rfc4231_case(Hash, Key, Data, Exp); -hmac_rfc4231_case(Hash, HashFun, case2, Exp) -> +hmac_rfc4231_case(Hash, case2, Exp) -> %% Test 2 Key = <<"Jefe">>, Data = <<"what do ya want for nothing?">>, - hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp); + hmac_rfc4231_case(Hash, Key, Data, Exp); -hmac_rfc4231_case(Hash, HashFun, case3, Exp) -> +hmac_rfc4231_case(Hash, case3, Exp) -> %% Test 3 Key = binary:copy(<<16#aa>>, 20), Data = binary:copy(<<16#dd>>, 50), - hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp); + hmac_rfc4231_case(Hash, Key, Data, Exp); -hmac_rfc4231_case(Hash, HashFun, case4, Exp) -> +hmac_rfc4231_case(Hash, case4, Exp) -> %% Test 4 Key = list_to_binary(lists:seq(1, 16#19)), Data = binary:copy(<<16#cd>>, 50), - hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp); + hmac_rfc4231_case(Hash, Key, Data, Exp); -hmac_rfc4231_case(Hash, HashFun, case5, Exp) -> +hmac_rfc4231_case(Hash, case5, Exp) -> %% Test 5 Key = binary:copy(<<16#0c>>, 20), Data = <<"Test With Truncation">>, - hmac_rfc4231_case(Hash, HashFun, Key, Data, 16, Exp); + hmac_rfc4231_case(Hash, Key, Data, 16, Exp); -hmac_rfc4231_case(Hash, HashFun, case6, Exp) -> +hmac_rfc4231_case(Hash, case6, Exp) -> %% Test 6 Key = binary:copy(<<16#aa>>, 131), Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>, - hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp); + hmac_rfc4231_case(Hash, Key, Data, Exp); -hmac_rfc4231_case(Hash, HashFun, case7, Exp) -> +hmac_rfc4231_case(Hash, case7, Exp) -> %% Test Case 7 Key = binary:copy(<<16#aa>>, 131), Data = <<"This is a test using a larger than block-size key and a larger t", "han block-size data. The key needs to be hashed before being use", "d by the HMAC algorithm.">>, - hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp). + hmac_rfc4231_case(Hash, Key, Data, Exp). -hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp) -> +hmac_rfc4231_case(Hash, Key, Data, Exp) -> ?line Ctx = crypto:hmac_init(Hash, Key), ?line Ctx2 = crypto:hmac_update(Ctx, Data), ?line Mac1 = crypto:hmac_final(Ctx2), - ?line Mac2 = crypto:HashFun(Key, Data), ?line Mac3 = crypto:hmac(Hash, Key, Data), ?line m(Exp, Mac1), - ?line m(Exp, Mac2), ?line m(Exp, Mac3). -hmac_rfc4231_case(Hash, HashFun, Key, Data, Trunc, Exp) -> +hmac_rfc4231_case(Hash, Key, Data, Trunc, Exp) -> ?line Ctx = crypto:hmac_init(Hash, Key), ?line Ctx2 = crypto:hmac_update(Ctx, Data), ?line Mac1 = crypto:hmac_final_n(Ctx2, Trunc), - ?line Mac2 = crypto:HashFun(Key, Data, Trunc), ?line Mac3 = crypto:hmac(Hash, Key, Data, Trunc), ?line m(Exp, Mac1), - ?line m(Exp, Mac2), ?line m(Exp, Mac3). hmac_rfc4231_sha224_do() -> @@ -696,7 +693,7 @@ hmac_rfc4231_sha224_do() -> "d499f112f2d2b7273fa6870e"), Case7 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd" "946770db9c2b95c9f6f565d1"), - hmac_rfc4231_cases_do(sha224, sha224_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). + hmac_rfc4231_cases_do(sha224, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). hmac_rfc4231_sha256_do() -> Case1 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b" @@ -712,7 +709,7 @@ hmac_rfc4231_sha256_do() -> "8e0bc6213728c5140546040f0ee37f54"), Case7 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944" "bfdc63644f0713938a7f51535c3a35e2"), - hmac_rfc4231_cases_do(sha256, sha256_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). + hmac_rfc4231_cases_do(sha256, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). hmac_rfc4231_sha384_do() -> Case1 = hexstr2bin("afd03944d84895626b0825f4ab46907f" @@ -734,7 +731,7 @@ hmac_rfc4231_sha384_do() -> Case7 = hexstr2bin("6617178e941f020d351e2f254e8fd32c" "602420feb0b8fb9adccebb82461e99c5" "a678cc31e799176d3860e6110c46523e"), - hmac_rfc4231_cases_do(sha384, sha384_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). + hmac_rfc4231_cases_do(sha384, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). hmac_rfc4231_sha512_do() -> Case1 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0" @@ -762,16 +759,16 @@ hmac_rfc4231_sha512_do() -> "debd71f8867289865df5a32d20cdc944" "b6022cac3c4982b10d5eeb55c3e4de15" "134676fb6de0446065c97440fa8c6a58"), - hmac_rfc4231_cases_do(sha512, sha512_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). + hmac_rfc4231_cases_do(sha512, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]). -hmac_rfc4231_cases_do(Hash, HashFun, CasesData) -> - hmac_rfc4231_cases_do(Hash, HashFun, [case1, case2, case3, case4, case5, case6, case7], CasesData). +hmac_rfc4231_cases_do(Hash, CasesData) -> + hmac_rfc4231_cases_do(Hash, [case1, case2, case3, case4, case5, case6, case7], CasesData). -hmac_rfc4231_cases_do(_Hash, _HashFun, _, []) -> +hmac_rfc4231_cases_do(_Hash, _, []) -> ok; -hmac_rfc4231_cases_do(Hash, HashFun, [C|Cases], [D|CasesData]) -> - hmac_rfc4231_case(Hash, HashFun, C, D), - hmac_rfc4231_cases_do(Hash, HashFun, Cases, CasesData). +hmac_rfc4231_cases_do(Hash, [C|Cases], [D|CasesData]) -> + hmac_rfc4231_case(Hash, C, D), + hmac_rfc4231_cases_do(Hash, Cases, CasesData). hmac_update_md5_io(doc) -> ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. " @@ -858,10 +855,10 @@ sha256(Config) when is_list(Config) -> if_supported(sha256, fun() -> sha256_do() end). sha256_do() -> - ?line m(crypto:sha256("abc"), + ?line m(crypto:hash(sha256, "abc"), hexstr2bin("BA7816BF8F01CFEA4141" "40DE5DAE2223B00361A396177A9CB410FF61F20015AD")), - ?line m(crypto:sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklm" + ?line m(crypto:hash(sha256, "abcdbcdecdefdefgefghfghighijhijkijkljklmklm" "nlmnomnopnopq"), hexstr2bin("248D6A61D20638B8" "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")). @@ -877,10 +874,10 @@ sha256_update(Config) when is_list(Config) -> if_supported(sha256, fun() -> sha256_update_do() end). sha256_update_do() -> - ?line Ctx = crypto:sha256_init(), - ?line Ctx1 = crypto:sha256_update(Ctx, "abcdbcdecdefdefgefghfghighi"), - ?line Ctx2 = crypto:sha256_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"), - ?line m(crypto:sha256_final(Ctx2), + ?line Ctx = crypto:hash_init(sha256), + ?line Ctx1 = crypto:hash_update(Ctx, "abcdbcdecdefdefgefghfghighi"), + ?line Ctx2 = crypto:hash_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"), + ?line m(crypto:hash_final(Ctx2), hexstr2bin("248D6A61D20638B8" "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")). @@ -896,11 +893,11 @@ sha512(Config) when is_list(Config) -> if_supported(sha512, fun() -> sha512_do() end). sha512_do() -> - ?line m(crypto:sha512("abc"), + ?line m(crypto:hash(sha512, "abc"), hexstr2bin("DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2" "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD" "454D4423643CE80E2A9AC94FA54CA49F")), - ?line m(crypto:sha512("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + ?line m(crypto:hash(sha512, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"), hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1" "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A" @@ -917,10 +914,10 @@ sha512_update(Config) when is_list(Config) -> if_supported(sha512, fun() -> sha512_update_do() end). sha512_update_do() -> - ?line Ctx = crypto:sha512_init(), - ?line Ctx1 = crypto:sha512_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"), - ?line Ctx2 = crypto:sha512_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"), - ?line m(crypto:sha512_final(Ctx2), + ?line Ctx = crypto:hash_init(sha512), + ?line Ctx1 = crypto:hash_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"), + ?line Ctx2 = crypto:hash_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"), + ?line m(crypto:hash_final(Ctx2), hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1" "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A" "C7D329EEB6DD26545E96E55B874BE909")). @@ -1629,8 +1626,11 @@ dsa_verify_test(Config) when is_list(Config) -> BadArg = (catch my_dss_verify(sized_binary(Msg), <<SizeErr:32, SigBlob/binary>>, ValidKey)), - ?line m(element(1,element(2,BadArg)), badarg), - + badarg = case element(1,element(2,BadArg)) of + badarg -> badarg; + function_clause -> badarg; + X -> X + end, InValidKey = [crypto:mpint(P_p), crypto:mpint(Q_p), crypto:mpint(G_p), @@ -1663,20 +1663,29 @@ rsa_sign_test(Config) when is_list(Config) -> Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger" "09812312908312378623487263487623412039812 huagasd">>, - PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)], - PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)], - ?line Sig1 = crypto:rsa_sign(sized_binary(Msg), PrivKey), - ?line m(crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1),PubKey), true), + PrivKey = [PubEx, Mod, PrivEx], + PubKey = [PubEx, Mod], + PubKeyMpint = map_int_to_mpint(PubKey), + Sig1 = crypto:rsa_sign(sized_binary(Msg), map_int_to_mpint(PrivKey)), + Sig1 = crypto:sign(rsa, sha, Msg, PrivKey), + true = crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1), PubKeyMpint), + true = crypto:verify(rsa, sha, Msg, Sig1, PubKey), - ?line Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), PrivKey), - ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2),PubKey), true), + Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), map_int_to_mpint(PrivKey)), + Sig2 = crypto:sign(rsa, md5, Msg, PrivKey), + true = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2), PubKeyMpint), + true = crypto:verify(rsa, md5, Msg, Sig2, PubKey), - ?line m(Sig1 =:= Sig2, false), - ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1),PubKey), false), - ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1),PubKey), true), - + false = (Sig1 =:= Sig2), + false = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint), + false = crypto:verify(rsa, md5, Msg, Sig1, PubKey), + true = crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint), + true = crypto:verify(rsa, sha, Msg, Sig1, PubKey), + ok. - +map_int_to_mpint(List) -> + lists:map(fun(E) -> crypto:mpint(E) end, List). + rsa_sign_hash_test(doc) -> "rsa_sign_hash testing"; rsa_sign_hash_test(suite) -> @@ -1774,46 +1783,65 @@ rsa_encrypt_decrypt(Config) when is_list(Config) -> PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945, Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123, - PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)], - PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)], + PrivKey = [PubEx, Mod, PrivEx], + PubKey = [PubEx, Mod], Msg = <<"7896345786348 Asldi">>, - ?line PKCS1 = crypto:rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_padding), - ?line PKCS1Dec = crypto:rsa_private_decrypt(PKCS1, PrivKey, rsa_pkcs1_padding), + ?line PKCS1 = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_padding), + ?line PKCS1Dec = rsa_private_decrypt(PKCS1, PrivKey, rsa_pkcs1_padding), io:format("PKCS1Dec ~p~n",[PKCS1Dec]), ?line Msg = PKCS1Dec, - ?line OAEP = crypto:rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_oaep_padding), - ?line Msg = crypto:rsa_private_decrypt(OAEP, PrivKey, rsa_pkcs1_oaep_padding), + ?line OAEP = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_oaep_padding), + ?line Msg = rsa_private_decrypt(OAEP, PrivKey, rsa_pkcs1_oaep_padding), <<Msg2Len:32,_/binary>> = crypto:mpint(Mod), Msg2 = list_to_binary(lists:duplicate(Msg2Len-1, $X)), - ?line NoPad = crypto:rsa_public_encrypt(Msg2, PubKey, rsa_no_padding), - ?line NoPadDec = crypto:rsa_private_decrypt(NoPad, PrivKey, rsa_no_padding), + ?line NoPad = rsa_public_encrypt(Msg2, PubKey, rsa_no_padding), + ?line NoPadDec = rsa_private_decrypt(NoPad, PrivKey, rsa_no_padding), ?line NoPadDec = Msg2, - ShouldBeError = (catch crypto:rsa_public_encrypt(Msg, PubKey, rsa_no_padding)), + ShouldBeError = (catch rsa_public_encrypt(Msg, PubKey, rsa_no_padding)), ?line {'EXIT', {encrypt_failed,_}} = ShouldBeError, -%% ?line SSL = crypto:rsa_public_encrypt(Msg, PubKey, rsa_sslv23_padding), -%% ?line Msg = crypto:rsa_private_decrypt(SSL, PrivKey, rsa_sslv23_padding), +%% ?line SSL = rsa_public_encrypt(Msg, PubKey, rsa_sslv23_padding), +%% ?line Msg = rsa_private_decrypt(SSL, PrivKey, rsa_sslv23_padding), - ?line PKCS1_2 = crypto:rsa_private_encrypt(Msg, PrivKey, rsa_pkcs1_padding), - ?line PKCS1_2Dec = crypto:rsa_public_decrypt(PKCS1_2, PubKey, rsa_pkcs1_padding), + ?line PKCS1_2 = rsa_private_encrypt(Msg, PrivKey, rsa_pkcs1_padding), + ?line PKCS1_2Dec = rsa_public_decrypt(PKCS1_2, PubKey, rsa_pkcs1_padding), io:format("PKCS2Dec ~p~n",[PKCS1_2Dec]), ?line Msg = PKCS1_2Dec, - ?line PKCS1_3 = crypto:rsa_private_encrypt(Msg2, PrivKey, rsa_no_padding), - ?line PKCS1_3Dec = crypto:rsa_public_decrypt(PKCS1_3, PubKey, rsa_no_padding), + ?line PKCS1_3 = rsa_private_encrypt(Msg2, PrivKey, rsa_no_padding), + ?line PKCS1_3Dec = rsa_public_decrypt(PKCS1_3, PubKey, rsa_no_padding), io:format("PKCS2Dec ~p~n",[PKCS1_3Dec]), ?line Msg2 = PKCS1_3Dec, ?line {'EXIT', {encrypt_failed,_}} = - (catch crypto:rsa_private_encrypt(Msg, PrivKey, rsa_no_padding)), + (catch rsa_private_encrypt(Msg, PrivKey, rsa_no_padding)), ok. +rsa_public_encrypt(Msg, Key, Pad) -> + C1 = crypto:rsa_public_encrypt(Msg, Key, Pad), + C2 = crypto:rsa_public_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad), + {C1,C2}. + +rsa_public_decrypt(Msg, Key, Pad) -> + R = crypto:rsa_public_decrypt(Msg, Key, Pad), + R = crypto:rsa_public_decrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad). + +rsa_private_encrypt(Msg, Key, Pad) -> + R = crypto:rsa_private_encrypt(Msg, Key, Pad), + R = crypto:rsa_private_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad). + +rsa_private_decrypt({C1,C2}, Key, Pad) -> + R = crypto:rsa_private_decrypt(C1, Key, Pad), + R = crypto:rsa_private_decrypt(C2, Key, Pad), + R = crypto:rsa_private_decrypt(C1, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad), + R = crypto:rsa_private_decrypt(C2, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad). + dh(doc) -> ["Test dh (Diffie-Hellman) functions."]; @@ -1832,13 +1860,16 @@ dh(Config) when is_list(Config) -> {param, DHPs} -> timer:sleep(100), io:format("DHP ~p~n", [DHPs]), - ?line {Pub1,Priv1} = crypto:dh_generate_key(DHPs), + DHPs_mpint = lists:map(fun(E) -> sized_binary(E) end, DHPs), + ?line {Pub1,Priv1} = crypto:generate_key(dh, DHPs), io:format("Key1:~n~p~n~p~n~n", [Pub1,Priv1]), - ?line {Pub2,Priv2} = crypto:dh_generate_key(DHPs), + ?line {Pub2,Priv2} = crypto:dh_generate_key(DHPs_mpint), io:format("Key2:~n~p~n~p~n~n", [Pub2,Priv2]), - ?line A = crypto:dh_compute_key(Pub1, Priv2, DHPs), + ?line A = crypto:compute_key(dh, Pub1, unsized_binary(Priv2), DHPs), + ?line A = crypto:dh_compute_key(sized_binary(Pub1), Priv2, DHPs_mpint), timer:sleep(100), %% Get another thread see if that triggers problem - ?line B = crypto:dh_compute_key(Pub2, Priv1, DHPs), + ?line B = crypto:compute_key(dh, unsized_binary(Pub2), Priv1, DHPs), + ?line B = crypto:dh_compute_key(Pub2, sized_binary(Priv1), DHPs_mpint), io:format("A ~p~n",[A]), io:format("B ~p~n",[B]), ?line A = B @@ -1847,6 +1878,64 @@ dh(Config) when is_list(Config) -> exit(Pid, kill) end. + +ec(doc) -> + ["Test ec (Ecliptic Curve) functions."]; +ec(suite) -> []; +ec(Config) when is_list(Config) -> + if_supported(ec, fun() -> ec_do() end). + +ec_do() -> + %% test for a name curve + {D2_priv, D2_pub} = crypto:generate_key(ecdh, sect113r2), + PrivECDH = [D2_priv, sect113r2], + PubECDH = [D2_pub, sect113r2], + %%TODO: find a published test case for a EC key + + %% test for a full specified curve and public key, + %% taken from csca-germany_013_self_signed_cer.pem + PubKey = <<16#04, 16#4a, 16#94, 16#49, 16#81, 16#77, 16#9d, 16#df, + 16#1d, 16#a5, 16#e7, 16#c5, 16#27, 16#e2, 16#7d, 16#24, + 16#71, 16#a9, 16#28, 16#eb, 16#4d, 16#7b, 16#67, 16#75, + 16#ae, 16#09, 16#0a, 16#51, 16#45, 16#19, 16#9b, 16#d4, + 16#7e, 16#a0, 16#81, 16#e5, 16#5e, 16#d4, 16#a4, 16#3f, + 16#60, 16#7c, 16#6a, 16#50, 16#ee, 16#36, 16#41, 16#8a, + 16#87, 16#ff, 16#cd, 16#a6, 16#10, 16#39, 16#ca, 16#95, + 16#76, 16#7d, 16#ae, 16#ca, 16#c3, 16#44, 16#3f, 16#e3, 16#2c>>, + <<P:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9, + 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d, + 16#72, 16#6e, 16#3b, 16#f6, 16#23, 16#d5, 16#26, 16#20, + 16#28, 16#20, 16#13, 16#48, 16#1d, 16#1f, 16#6e, 16#53, 16#77>>, + <<A:256/integer>> = <<16#7d, 16#5a, 16#09, 16#75, 16#fc, 16#2c, 16#30, 16#57, + 16#ee, 16#f6, 16#75, 16#30, 16#41, 16#7a, 16#ff, 16#e7, + 16#fb, 16#80, 16#55, 16#c1, 16#26, 16#dc, 16#5c, 16#6c, + 16#e9, 16#4a, 16#4b, 16#44, 16#f3, 16#30, 16#b5, 16#d9>>, + <<B:256/integer>> = <<16#26, 16#dc, 16#5c, 16#6c, 16#e9, 16#4a, 16#4b, 16#44, + 16#f3, 16#30, 16#b5, 16#d9, 16#bb, 16#d7, 16#7c, 16#bf, + 16#95, 16#84, 16#16, 16#29, 16#5c, 16#f7, 16#e1, 16#ce, + 16#6b, 16#cc, 16#dc, 16#18, 16#ff, 16#8c, 16#07, 16#b6>>, + BasePoint = <<16#04, 16#8b, 16#d2, 16#ae, 16#b9, 16#cb, 16#7e, 16#57, + 16#cb, 16#2c, 16#4b, 16#48, 16#2f, 16#fc, 16#81, 16#b7, + 16#af, 16#b9, 16#de, 16#27, 16#e1, 16#e3, 16#bd, 16#23, + 16#c2, 16#3a, 16#44, 16#53, 16#bd, 16#9a, 16#ce, 16#32, + 16#62, 16#54, 16#7e, 16#f8, 16#35, 16#c3, 16#da, 16#c4, + 16#fd, 16#97, 16#f8, 16#46, 16#1a, 16#14, 16#61, 16#1d, + 16#c9, 16#c2, 16#77, 16#45, 16#13, 16#2d, 16#ed, 16#8e, + 16#54, 16#5c, 16#1d, 16#54, 16#c7, 16#2f, 16#04, 16#69, 16#97>>, + <<Order:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9, + 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d, + 16#71, 16#8c, 16#39, 16#7a, 16#a3, 16#b5, 16#61, 16#a6, + 16#f7, 16#90, 16#1e, 16#0e, 16#82, 16#97, 16#48, 16#56, 16#a7>>, + CoFactor = 1, + Curve = {{prime_field,P},{A,B,none},BasePoint, Order,CoFactor}, + + Msg = <<99,234,6,64,190,237,201,99,80,248,58,40,70,45,149,218,5,246,242,63>>, + Sign = crypto:sign(ecdsa, sha, Msg, PrivECDH), + ?line true = crypto:verify(ecdsa, sha, Msg, Sign, PubECDH), + ?line false = crypto:verify(ecdsa, sha, Msg, <<10,20>>, PubECDH), + + ok. + srp3(doc) -> ["SRP-3 test vectors generated by http://srp.stanford.edu/demo/demo.html"]; srp3(suite) -> []; @@ -1890,15 +1979,15 @@ srp3(Config) when is_list(Config) -> "9176A9192615DC0277AE7C12F1F6A7F6563FCA11675D809AF578BDE5" "2B51E05D440B63099A017A0B45044801"), UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), - Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime), - ClientPublic = crypto:mod_exp_prime(Generator, ClientPrivate, Prime), + Verifier = crypto:mod_pow(Generator, UserPassHash, Prime), + ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime), - {ClientPublic, ClientPrivate} = crypto:srp_generate_key(Generator, Prime, Version, ClientPrivate), - {ServerPublic, ServerPrivate} = crypto:srp_generate_key(Verifier, Generator, Prime, Version, ServerPrivate), - SessionKey = crypto:srp_compute_key(UserPassHash, Prime, Generator, ClientPublic, - ClientPrivate, ServerPublic, Version, Scrambler), - SessionKey = crypto:srp_compute_key(Verifier, Prime, ClientPublic, - ServerPublic, ServerPrivate, Version, Scrambler). + {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate), + {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate), + SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate}, + {user, [UserPassHash, Prime, Generator, Version, Scrambler]}), + SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate}, + {host, [Verifier, Prime, Version, Scrambler]}). srp6(doc) -> ["SRP-6 test vectors generated by http://srp.stanford.edu/demo/demo.html"]; @@ -1941,15 +2030,15 @@ srp6(Config) when is_list(Config) -> "72E992AAD89095A84B6A5FADA152369AB1E350A03693BEF044DF3EDF" "0C34741F4696C30E9F675D09F58ACBEB"), UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), - Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime), - ClientPublic = crypto:mod_exp_prime(Generator, ClientPrivate, Prime), + Verifier = crypto:mod_pow(Generator, UserPassHash, Prime), + ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime), - {ClientPublic, ClientPrivate} = crypto:srp_generate_key(Generator, Prime, Version, ClientPrivate), - {ServerPublic, ServerPrivate} = crypto:srp_generate_key(Verifier, Generator, Prime, Version, ServerPrivate), - SessionKey = crypto:srp_compute_key(UserPassHash, Prime, Generator, ClientPublic, - ClientPrivate, ServerPublic, Version, Scrambler), - SessionKey = crypto:srp_compute_key(Verifier, Prime, ClientPublic, - ServerPublic, ServerPrivate, Version, Scrambler). + {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate), + {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate), + SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate}, + {user, [UserPassHash, Prime, Generator, Version, Scrambler]}), + SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate}, + {host, [Verifier, Prime, Version, Scrambler]}). srp6a(doc) -> ["SRP-6a test vectors from RFC5054."]; @@ -1992,15 +2081,15 @@ srp6a(Config) when is_list(Config) -> "3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D" "C346D7E474B29EDE8A469FFECA686E5A"), UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), - Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime), + Verifier = crypto:mod_pow(Generator, UserPassHash, Prime), - {ClientPublic, ClientPrivate} = crypto:srp_generate_key(Generator, Prime, Version, ClientPrivate), - {ServerPublic, ServerPrivate} = crypto:srp_generate_key(Verifier, Generator, Prime, Version, ServerPrivate), + {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate), + {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate), - SessionKey = crypto:srp_compute_key(UserPassHash, Prime, Generator, ClientPublic, - ClientPrivate, ServerPublic, Version, Scrambler), - SessionKey = crypto:srp_compute_key(Verifier, Prime, ClientPublic, - ServerPublic, ServerPrivate, Version, Scrambler). + SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate}, + {user, [UserPassHash, Prime, Generator, Version, Scrambler]}), + SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate}, + {host, [Verifier, Prime, Version, Scrambler]}). %% %% @@ -2195,6 +2284,9 @@ sized_binary(Binary) when is_binary(Binary) -> sized_binary(List) -> sized_binary(list_to_binary(List)). +unsized_binary(<<Sz:32/integer, Binary:Sz/binary>>) -> + Binary. + xor_bytes(Bin1, Bin2) when is_binary(Bin1), is_binary(Bin2) -> L1 = binary_to_list(Bin1), L2 = binary_to_list(Bin2), |