aboutsummaryrefslogtreecommitdiffstats
path: root/lib/crypto/c_src/crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/crypto/c_src/crypto.c')
-rw-r--r--lib/crypto/c_src/crypto.c836
1 files changed, 722 insertions, 114 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 4dc62421d2..a24747a872 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2010-2012. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -53,6 +53,10 @@
#include <openssl/evp.h>
#include <openssl/hmac.h>
+#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_SHA224) && defined(NID_sha224)\
+ && !defined(OPENSSL_NO_SHA256) /* disabled like this in my sha.h (?) */
+# define HAVE_SHA224
+#endif
#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_SHA256) && defined(NID_sha256)
# define HAVE_SHA256
#endif
@@ -135,10 +139,18 @@ static ERL_NIF_TERM sha(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM sha_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM sha_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM sha_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha224_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha224_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha224_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha224_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM sha256_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM sha256_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM sha256_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM sha256_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha384_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha384_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha384_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha384_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM sha512_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM sha512_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM sha512_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -149,6 +161,10 @@ static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha224_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha384_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM hmac_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -201,12 +217,33 @@ static void dyn_destroy_function(struct CRYPTO_dynlock_value *ptr,
#endif /* OPENSSL_THREADS */
/* helpers */
+static void init_digest_types(ErlNifEnv* env);
static void hmac_md5(unsigned char *key, int klen,
unsigned char *dbuf, int dlen,
unsigned char *hmacbuf);
static void hmac_sha1(unsigned char *key, int klen,
unsigned char *dbuf, int dlen,
unsigned char *hmacbuf);
+#ifdef HAVE_SHA224
+static void hmac_sha224(unsigned char *key, int klen,
+ unsigned char *dbuf, int dlen,
+ unsigned char *hmacbuf);
+#endif
+#ifdef HAVE_SHA256
+static void hmac_sha256(unsigned char *key, int klen,
+ unsigned char *dbuf, int dlen,
+ unsigned char *hmacbuf);
+#endif
+#ifdef HAVE_SHA384
+static void hmac_sha384(unsigned char *key, int klen,
+ unsigned char *dbuf, int dlen,
+ unsigned char *hmacbuf);
+#endif
+#ifdef HAVE_SHA512
+static void hmac_sha512(unsigned char *key, int klen,
+ unsigned char *dbuf, int dlen,
+ unsigned char *hmacbuf);
+#endif
static int library_refc = 0; /* number of users of this dynamic library */
@@ -220,10 +257,18 @@ static ErlNifFunc nif_funcs[] = {
{"sha_init", 0, sha_init},
{"sha_update", 2, sha_update},
{"sha_final", 1, sha_final},
+ {"sha224_nif", 1, sha224_nif},
+ {"sha224_init_nif", 0, sha224_init_nif},
+ {"sha224_update_nif", 2, sha224_update_nif},
+ {"sha224_final_nif", 1, sha224_final_nif},
{"sha256_nif", 1, sha256_nif},
{"sha256_init_nif", 0, sha256_init_nif},
{"sha256_update_nif", 2, sha256_update_nif},
{"sha256_final_nif", 1, sha256_final_nif},
+ {"sha384_nif", 1, sha384_nif},
+ {"sha384_init_nif", 0, sha384_init_nif},
+ {"sha384_update_nif", 2, sha384_update_nif},
+ {"sha384_final_nif", 1, sha384_final_nif},
{"sha512_nif", 1, sha512_nif},
{"sha512_init_nif", 0, sha512_init_nif},
{"sha512_update_nif", 2, sha512_update_nif},
@@ -234,6 +279,10 @@ static ErlNifFunc nif_funcs[] = {
{"md4_final", 1, md4_final},
{"md5_mac_n", 3, md5_mac_n},
{"sha_mac_n", 3, sha_mac_n},
+ {"sha224_mac_nif", 3, sha224_mac_nif},
+ {"sha256_mac_nif", 3, sha256_mac_nif},
+ {"sha384_mac_nif", 3, sha384_mac_nif},
+ {"sha512_mac_nif", 3, sha512_mac_nif},
{"hmac_init", 2, hmac_init},
{"hmac_update", 2, hmac_update},
{"hmac_final", 1, hmac_final},
@@ -287,10 +336,12 @@ ERL_NIF_INIT(crypto,nif_funcs,load,reload,upgrade,unload)
#define SHA_CTX_LEN (sizeof(SHA_CTX))
#define SHA_LEN 20
#define SHA_LEN_96 12
+#define SHA224_LEN (224/8)
#define SHA256_LEN (256/8)
#define SHA384_LEN (384/8)
#define SHA512_LEN (512/8)
#define HMAC_INT_LEN 64
+#define HMAC_INT2_LEN 128
#define HMAC_IPAD 0x36
#define HMAC_OPAD 0x5c
@@ -300,6 +351,7 @@ static ErlNifRWLock** lock_vec = NULL; /* Static locks used by openssl */
static ERL_NIF_TERM atom_true;
static ERL_NIF_TERM atom_false;
static ERL_NIF_TERM atom_sha;
+static ERL_NIF_TERM atom_sha224;
static ERL_NIF_TERM atom_sha256;
static ERL_NIF_TERM atom_sha384;
static ERL_NIF_TERM atom_sha512;
@@ -320,6 +372,7 @@ static ERL_NIF_TERM atom_check_failed;
static ERL_NIF_TERM atom_unknown;
static ERL_NIF_TERM atom_none;
static ERL_NIF_TERM atom_notsup;
+static ERL_NIF_TERM atom_digest;
static int is_ok_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info)
@@ -374,6 +427,7 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
atom_true = enif_make_atom(env,"true");
atom_false = enif_make_atom(env,"false");
atom_sha = enif_make_atom(env,"sha");
+ atom_sha224 = enif_make_atom(env,"sha224");
atom_sha256 = enif_make_atom(env,"sha256");
atom_sha384 = enif_make_atom(env,"sha384");
atom_sha512 = enif_make_atom(env,"sha512");
@@ -393,6 +447,9 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
atom_unknown = enif_make_atom(env,"unknown");
atom_none = enif_make_atom(env,"none");
atom_notsup = enif_make_atom(env,"notsup");
+ atom_digest = enif_make_atom(env,"digest");
+
+ init_digest_types(env);
*priv_data = NULL;
library_refc++;
@@ -557,6 +614,67 @@ static ERL_NIF_TERM sha_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
return ret;
}
+static ERL_NIF_TERM sha224_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Data) */
+#ifdef HAVE_SHA224
+ ErlNifBinary ibin;
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) {
+ return enif_make_badarg(env);
+ }
+ SHA224((unsigned char *) ibin.data, ibin.size,
+ enif_make_new_binary(env,SHA224_LEN, &ret));
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+static ERL_NIF_TERM sha224_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* () */
+#ifdef HAVE_SHA224
+ ERL_NIF_TERM ret;
+ SHA224_Init((SHA256_CTX *) enif_make_new_binary(env, sizeof(SHA256_CTX), &ret));
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+static ERL_NIF_TERM sha224_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context, Data) */
+#ifdef HAVE_SHA224
+ SHA256_CTX* new_ctx;
+ ErlNifBinary ctx_bin, data_bin;
+ ERL_NIF_TERM ret;
+ if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA256_CTX)
+ || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
+ return enif_make_badarg(env);
+ }
+ new_ctx = (SHA256_CTX*) enif_make_new_binary(env,sizeof(SHA256_CTX), &ret);
+ memcpy(new_ctx, ctx_bin.data, sizeof(SHA256_CTX));
+ SHA224_Update(new_ctx, data_bin.data, data_bin.size);
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+static ERL_NIF_TERM sha224_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context) */
+#ifdef HAVE_SHA224
+ ErlNifBinary ctx_bin;
+ SHA256_CTX ctx_clone;
+ ERL_NIF_TERM ret;
+ if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA256_CTX)) {
+ return enif_make_badarg(env);
+ }
+ memcpy(&ctx_clone, ctx_bin.data, sizeof(SHA256_CTX)); /* writable */
+ SHA224_Final(enif_make_new_binary(env, SHA224_LEN, &ret), &ctx_clone);
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+
static ERL_NIF_TERM sha256_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Data) */
#ifdef HAVE_SHA256
@@ -618,6 +736,67 @@ static ERL_NIF_TERM sha256_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER
#endif
}
+static ERL_NIF_TERM sha384_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Data) */
+#ifdef HAVE_SHA384
+ ErlNifBinary ibin;
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) {
+ return enif_make_badarg(env);
+ }
+ SHA384((unsigned char *) ibin.data, ibin.size,
+ enif_make_new_binary(env,SHA384_LEN, &ret));
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+static ERL_NIF_TERM sha384_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* () */
+#ifdef HAVE_SHA384
+ ERL_NIF_TERM ret;
+ SHA384_Init((SHA512_CTX *) enif_make_new_binary(env, sizeof(SHA512_CTX), &ret));
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+static ERL_NIF_TERM sha384_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context, Data) */
+#ifdef HAVE_SHA384
+ SHA512_CTX* new_ctx;
+ ErlNifBinary ctx_bin, data_bin;
+ ERL_NIF_TERM ret;
+ if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA512_CTX)
+ || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
+ return enif_make_badarg(env);
+ }
+ new_ctx = (SHA512_CTX*) enif_make_new_binary(env,sizeof(SHA512_CTX), &ret);
+ memcpy(new_ctx, ctx_bin.data, sizeof(SHA512_CTX));
+ SHA384_Update(new_ctx, data_bin.data, data_bin.size);
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+static ERL_NIF_TERM sha384_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Context) */
+#ifdef HAVE_SHA384
+ ErlNifBinary ctx_bin;
+ SHA512_CTX ctx_clone;
+ ERL_NIF_TERM ret;
+ if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != sizeof(SHA512_CTX)) {
+ return enif_make_badarg(env);
+ }
+ memcpy(&ctx_clone, ctx_bin.data, sizeof(SHA512_CTX)); /* writable */
+ SHA384_Final(enif_make_new_binary(env, SHA384_LEN, &ret), &ctx_clone);
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+
static ERL_NIF_TERM sha512_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Data) */
#ifdef HAVE_SHA512
@@ -760,6 +939,95 @@ static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
return ret;
}
+static ERL_NIF_TERM sha224_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, Data, MacSize) */
+#ifdef HAVE_SHA224
+ unsigned char hmacbuf[SHA224_DIGEST_LENGTH];
+ ErlNifBinary key, data;
+ unsigned mac_sz;
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
+ || !enif_inspect_iolist_as_binary(env, argv[1], &data)
+ || !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA224_DIGEST_LENGTH) {
+ return enif_make_badarg(env);
+ }
+ hmac_sha224(key.data, key.size, data.data, data.size, hmacbuf);
+ memcpy(enif_make_new_binary(env, mac_sz, &ret),
+ hmacbuf, mac_sz);
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, Data, MacSize) */
+#ifdef HAVE_SHA256
+ unsigned char hmacbuf[SHA256_DIGEST_LENGTH];
+ ErlNifBinary key, data;
+ unsigned mac_sz;
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
+ || !enif_inspect_iolist_as_binary(env, argv[1], &data)
+ || !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA256_DIGEST_LENGTH) {
+ return enif_make_badarg(env);
+ }
+ hmac_sha256(key.data, key.size, data.data, data.size, hmacbuf);
+ memcpy(enif_make_new_binary(env, mac_sz, &ret),
+ hmacbuf, mac_sz);
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM sha384_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, Data, MacSize) */
+#ifdef HAVE_SHA384
+ unsigned char hmacbuf[SHA384_DIGEST_LENGTH];
+ ErlNifBinary key, data;
+ unsigned mac_sz;
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
+ || !enif_inspect_iolist_as_binary(env, argv[1], &data)
+ || !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA384_DIGEST_LENGTH) {
+ return enif_make_badarg(env);
+ }
+ hmac_sha384(key.data, key.size, data.data, data.size, hmacbuf);
+ memcpy(enif_make_new_binary(env, mac_sz, &ret),
+ hmacbuf, mac_sz);
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+
+
+static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, Data, MacSize) */
+#ifdef HAVE_SHA512
+ unsigned char hmacbuf[SHA512_DIGEST_LENGTH];
+ ErlNifBinary key, data;
+ unsigned mac_sz;
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
+ || !enif_inspect_iolist_as_binary(env, argv[1], &data)
+ || !enif_get_uint(env,argv[2],&mac_sz) || mac_sz > SHA512_DIGEST_LENGTH) {
+ return enif_make_badarg(env);
+ }
+ hmac_sha512(key.data, key.size, data.data, data.size, hmacbuf);
+ memcpy(enif_make_new_binary(env, mac_sz, &ret),
+ hmacbuf, mac_sz);
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+
static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Type, Key) */
ErlNifBinary key;
@@ -768,6 +1036,18 @@ static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
const EVP_MD *md;
if (argv[0] == atom_sha) md = EVP_sha1();
+#ifdef HAVE_SHA224
+ else if (argv[0] == atom_sha224) md = EVP_sha224();
+#endif
+#ifdef HAVE_SHA256
+ else if (argv[0] == atom_sha256) md = EVP_sha256();
+#endif
+#ifdef HAVE_SHA384
+ else if (argv[0] == atom_sha384) md = EVP_sha384();
+#endif
+#ifdef HAVE_SHA512
+ else if (argv[0] == atom_sha512) md = EVP_sha512();
+#endif
else if (argv[0] == atom_md5) md = EVP_md5();
else if (argv[0] == atom_ripemd160) md = EVP_ripemd160();
else goto badarg;
@@ -954,8 +1234,7 @@ static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TE
if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 16
|| !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16
- || !enif_inspect_iolist_as_binary(env, argv[2], &text)
- || text.size % 16 != 0) {
+ || !enif_inspect_iolist_as_binary(env, argv[2], &text)) {
return enif_make_badarg(env);
}
@@ -1208,14 +1487,43 @@ static int inspect_mpint(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifBinary* bin)
}
static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (DigestType,Data,Signature,Key=[P, Q, G, Y]) */
+{/* (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;
unsigned char hmacbuf[SHA_DIGEST_LENGTH];
+ unsigned char* digest;
ERL_NIF_TERM head, tail;
+ const ERL_NIF_TERM* tpl_terms;
+ int tpl_arity;
DSA *dsa;
int i;
+ if (argv[0] == atom_sha) {
+ if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2 || tpl_terms[0] != atom_digest
+ || !enif_inspect_binary(env, tpl_terms[1], &data_bin)
+ || data_bin.size != SHA_DIGEST_LENGTH) {
+
+ return enif_make_badarg(env);
+ }
+ digest = data_bin.data;
+ }
+ else {
+ if (!inspect_mpint(env, argv[1], &data_bin)) {
+ return enif_make_badarg(env);
+ }
+ SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+ digest = hmacbuf;
+ }
+ }
+ else if (argv[0] == atom_none && enif_inspect_binary(env, argv[1], &data_bin)
+ && data_bin.size == SHA_DIGEST_LENGTH) {
+ digest = data_bin.data;
+ }
+ else {
+ return enif_make_badarg(env);
+ }
+
if (!inspect_mpint(env, argv[2], &sign_bin)
|| !enif_get_list_cell(env, argv[3], &head, &tail)
|| !get_bn_from_mpint(env, head, &dsa_p)
@@ -1226,23 +1534,13 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
|| !enif_get_list_cell(env, tail, &head, &tail)
|| !get_bn_from_mpint(env, head, &dsa_y)
|| !enif_is_empty_list(env,tail)) {
- badarg:
+
if (dsa_p) BN_free(dsa_p);
if (dsa_q) BN_free(dsa_q);
if (dsa_g) BN_free(dsa_g);
if (dsa_y) BN_free(dsa_y);
return enif_make_badarg(env);
}
- if (argv[0] == atom_sha && inspect_mpint(env, argv[1], &data_bin)) {
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
- }
- else if (argv[0] == atom_none && enif_inspect_binary(env, argv[1], &data_bin)
- && data_bin.size == SHA_DIGEST_LENGTH) {
- memcpy(hmacbuf, data_bin.data, SHA_DIGEST_LENGTH);
- }
- else {
- goto badarg;
- }
dsa = DSA_new();
dsa->p = dsa_p;
@@ -1250,23 +1548,134 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
dsa->g = dsa_g;
dsa->priv_key = NULL;
dsa->pub_key = dsa_y;
- i = DSA_verify(0, hmacbuf, SHA_DIGEST_LENGTH,
+ i = DSA_verify(0, digest, SHA_DIGEST_LENGTH,
sign_bin.data+4, sign_bin.size-4, dsa);
DSA_free(dsa);
return(i > 0) ? atom_true : atom_false;
}
+
+static void md5_digest(unsigned char* in, unsigned int in_len, unsigned char* out)
+{
+ MD5(in, in_len, out);
+}
+static void sha1_digest(unsigned char* in, unsigned int in_len, unsigned char* out)
+{
+ SHA1(in, in_len, out);
+}
+#ifdef HAVE_SHA224
+static void sha224_digest(unsigned char* in, unsigned int in_len, unsigned char* out)
+{
+ SHA224(in, in_len, out);
+}
+#endif
+#ifdef HAVE_SHA256
+static void sha256_digest(unsigned char* in, unsigned int in_len, unsigned char* out)
+{
+ SHA256(in, in_len, out);
+}
+#endif
+#ifdef HAVE_SHA384
+static void sha384_digest(unsigned char* in, unsigned int in_len, unsigned char* out)
+{
+ SHA384(in, in_len, out);
+}
+#endif
+#ifdef HAVE_SHA512
+static void sha512_digest(unsigned char* in, unsigned int in_len, unsigned char* out)
+{
+ SHA512(in, in_len, out);
+}
+#endif
+
+struct digest_type_t {
+ const char* type_str;
+ unsigned len; /* 0 if notsup */
+ int NID_type;
+ void (*funcp)(unsigned char* in, unsigned int in_len, unsigned char* out);
+ ERL_NIF_TERM type_atom;
+};
+
+struct digest_type_t digest_types[] =
+{
+ {"md5", MD5_DIGEST_LENGTH, NID_md5, md5_digest},
+ {"sha", SHA_DIGEST_LENGTH, NID_sha1, sha1_digest},
+ {"sha224",
+#ifdef HAVE_SHA224
+ SHA224_LEN, NID_sha224, sha224_digest
+#else
+ 0
+#endif
+ },
+ {"sha256",
+#ifdef HAVE_SHA256
+ SHA256_LEN, NID_sha256, sha256_digest
+#else
+ 0
+#endif
+ },
+ {"sha384",
+#ifdef HAVE_SHA384
+ SHA384_LEN, NID_sha384, sha384_digest
+#else
+ 0
+#endif
+ },
+ {"sha512",
+#ifdef HAVE_SHA512
+ SHA512_LEN, NID_sha512, sha512_digest
+#else
+ 0
+#endif
+ },
+ {NULL}
+};
+
+static void init_digest_types(ErlNifEnv* env)
+{
+ struct digest_type_t* p = digest_types;
+
+ for (p = digest_types; p->type_str; p++) {
+ p->type_atom = enif_make_atom(env, p->type_str);
+ }
+
+}
+
+static struct digest_type_t* get_digest_type(ERL_NIF_TERM type)
+{
+ struct digest_type_t* p = NULL;
+ for (p = digest_types; p->type_str; p++) {
+ if (type == p->type_atom) {
+ return p;
+ }
+ }
+ return NULL;
+}
+
static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type, Data, Signature, Key=[E,N]) */
+{/* (Type, Data|{digest,Digest}, Signature, Key=[E,N]) */
ErlNifBinary data_bin, sign_bin;
unsigned char hmacbuf[SHA512_LEN];
ERL_NIF_TERM head, tail, ret;
int i;
- RSA* rsa = RSA_new();
+ RSA* rsa;
const ERL_NIF_TERM type = argv[0];
+ const ERL_NIF_TERM* tpl_terms;
+ int tpl_arity;
+ struct digest_type_t* digp = NULL;
+ unsigned char* digest = NULL;
+
+ digp = get_digest_type(type);
+ if (!digp) {
+ return enif_make_badarg(env);
+ }
+ if (!digp->len) {
+ return atom_notsup;
+ }
- if (!inspect_mpint(env, argv[1], &data_bin)
- || !inspect_mpint(env, argv[2], &sign_bin)
+ rsa = RSA_new();
+
+ if (!inspect_mpint(env, argv[2], &sign_bin)
|| !enif_get_list_cell(env, argv[3], &head, &tail)
|| !get_bn_from_mpint(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
@@ -1274,59 +1683,38 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
|| !enif_is_empty_list(env, tail)) {
ret = enif_make_badarg(env);
+ goto done;
}
- else {
- if (type == atom_sha) {
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
- i = RSA_verify(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH,
- sign_bin.data+4, sign_bin.size-4, rsa);
- }
- else if (type == atom_sha256) {
- #ifdef HAVE_SHA256
- SHA256(data_bin.data+4, data_bin.size-4, hmacbuf);
- i = RSA_verify(NID_sha256, hmacbuf, SHA256_LEN,
- sign_bin.data+4, sign_bin.size-4, rsa);
- #else
- ret = atom_notsup;
- goto done;
- #endif
- }
- else if (type == atom_sha384) {
- #ifdef HAVE_SHA384
- SHA384(data_bin.data+4, data_bin.size-4, hmacbuf);
- i = RSA_verify(NID_sha384, hmacbuf, SHA384_LEN,
- sign_bin.data+4, sign_bin.size-4, rsa);
- #else
- ret = atom_notsup;
- goto done;
- #endif
- }
- else if (type == atom_sha512) {
- #ifdef HAVE_SHA512
- SHA512(data_bin.data+4, data_bin.size-4, hmacbuf);
- i = RSA_verify(NID_sha512, hmacbuf, SHA512_LEN,
- sign_bin.data+4, sign_bin.size-4, rsa);
- #else
- ret = atom_notsup;
- goto done;
- #endif
- }
- else if (type == atom_md5) {
- MD5(data_bin.data+4, data_bin.size-4, hmacbuf);
- i = RSA_verify(NID_md5, hmacbuf, MD5_DIGEST_LENGTH,
- sign_bin.data+4, sign_bin.size-4, rsa);
- }
- else {
+ if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2 || tpl_terms[0] != atom_digest
+ || !enif_inspect_binary(env, tpl_terms[1], &data_bin)
+ || data_bin.size != digp->len) {
+
ret = enif_make_badarg(env);
goto done;
}
- ret = (i==1 ? atom_true : atom_false);
- }
+ digest = data_bin.data;
+ }
+ else if (inspect_mpint(env, argv[1], &data_bin)) {
+ digest = hmacbuf;
+ digp->funcp(data_bin.data+4, data_bin.size-4, digest);
+ }
+ else {
+ ret = enif_make_badarg(env);
+ goto done;
+ }
+
+ i = RSA_verify(digp->NID_type, digest, digp->len,
+ sign_bin.data+4, sign_bin.size-4, rsa);
+
+ ret = (i==1 ? atom_true : atom_false);
+
done:
RSA_free(rsa);
return ret;
}
+
static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, IVec, Data, IsEncrypt) */
ErlNifBinary key_bin, ivec_bin, data_bin;
@@ -1456,48 +1844,88 @@ static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
return ret;
}
-static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Type,Data,Key=[E,N,D]) */
- ErlNifBinary data_bin, ret_bin;
+static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa)
+{
+ /* key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C] */
ERL_NIF_TERM head, tail;
- unsigned char hmacbuf[SHA_DIGEST_LENGTH];
- unsigned rsa_s_len;
- RSA *rsa = RSA_new();
- int i, is_sha;
- if (argv[0] == atom_sha) is_sha = 1;
- else if (argv[0] == atom_md5) is_sha = 0;
- else goto badarg;
-
- if (!inspect_mpint(env,argv[1],&data_bin)
- || !enif_get_list_cell(env, argv[2], &head, &tail)
+ if (!enif_get_list_cell(env, key, &head, &tail)
|| !get_bn_from_mpint(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
|| !get_bn_from_mpint(env, head, &rsa->n)
|| !enif_get_list_cell(env, tail, &head, &tail)
|| !get_bn_from_mpint(env, head, &rsa->d)
- || !enif_is_empty_list(env,tail)) {
- badarg:
- RSA_free(rsa);
+ || (!enif_is_empty_list(env, tail) &&
+ (!enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &rsa->p)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &rsa->q)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &rsa->dmp1)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &rsa->dmq1)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_mpint(env, head, &rsa->iqmp)
+ || !enif_is_empty_list(env, tail)))) {
+ return 0;
+ }
+ return 1;
+}
+
+static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Data|{digest,Digest}, Key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C]) */
+ ErlNifBinary data_bin, ret_bin;
+ unsigned char hmacbuf[SHA_DIGEST_LENGTH];
+ unsigned rsa_s_len;
+ RSA* rsa;
+ 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);
}
- enif_alloc_binary(RSA_size(rsa), &ret_bin);
- if (is_sha) {
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
- ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, SHA_DIGEST_LENGTH);
- i = RSA_sign(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH,
- ret_bin.data, &rsa_s_len, rsa);
+ if (!digp->len) {
+ return atom_notsup;
+ }
+
+ 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 {
- MD5(data_bin.data+4, data_bin.size-4, hmacbuf);
- ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, MD5_DIGEST_LENGTH);
- i = RSA_sign(NID_md5, hmacbuf,MD5_DIGEST_LENGTH,
- ret_bin.data, &rsa_s_len, rsa);
+ if (!inspect_mpint(env,argv[1],&data_bin)) {
+ return enif_make_badarg(env);
+ }
+ digest = hmacbuf;
+ digp->funcp(data_bin.data+4, data_bin.size-4, digest);
}
+
+ rsa = RSA_new();
+ if (!get_rsa_private_key(env, argv[2], rsa)) {
+ RSA_free(rsa);
+ return enif_make_badarg(env);
+ }
+
+
+ enif_alloc_binary(RSA_size(rsa), &ret_bin);
+
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(digest, digp->len);
+ i = RSA_sign(digp->NID_type, digest, digp->len,
+ ret_bin.data, &rsa_s_len, rsa);
+
RSA_free(rsa);
if (i) {
ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, rsa_s_len);
- if (rsa_s_len != data_bin.size) {
+ if (rsa_s_len != ret_bin.size) {
enif_realloc_binary(&ret_bin, rsa_s_len);
ERL_VALGRIND_ASSERT_MEM_DEFINED(ret_bin.data, rsa_s_len);
}
@@ -1509,15 +1937,49 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
}
}
+
static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (DigesType, Data, Key=[P,Q,G,PrivKey]) */
+{/* (DigesType|none, Data|{digest,Digest}, Key=[P,Q,G,PrivKey]) */
ErlNifBinary data_bin, ret_bin;
ERL_NIF_TERM head, tail;
unsigned char hmacbuf[SHA_DIGEST_LENGTH];
unsigned int dsa_s_len;
- DSA* dsa = DSA_new();
+ const ERL_NIF_TERM* tpl_terms;
+ int tpl_arity;
+ unsigned char* digest = NULL;
+ DSA* dsa;
int i;
+ if (argv[0] == atom_sha) {
+ if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2 || tpl_terms[0] != atom_digest
+ || !enif_inspect_binary(env, tpl_terms[1], &data_bin)
+ || data_bin.size != SHA_DIGEST_LENGTH) {
+
+ return enif_make_badarg(env);
+ }
+ digest = data_bin.data;
+ }
+ else {
+ if (!inspect_mpint(env,argv[1],&data_bin)) {
+ return enif_make_badarg(env);
+ }
+ SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+ digest = hmacbuf;
+ }
+ }
+ else if (argv[0] == atom_none
+ && enif_inspect_binary(env,argv[1],&data_bin)
+ && data_bin.size == SHA_DIGEST_LENGTH) {
+
+ digest = data_bin.data;
+ }
+ else {
+ return enif_make_badarg(env);
+ }
+
+ dsa = DSA_new();
+
dsa->pub_key = NULL;
if (!enif_get_list_cell(env, argv[2], &head, &tail)
|| !get_bn_from_mpint(env, head, &dsa->p)
@@ -1528,23 +1990,12 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
|| !enif_get_list_cell(env, tail, &head, &tail)
|| !get_bn_from_mpint(env, head, &dsa->priv_key)
|| !enif_is_empty_list(env,tail)) {
- goto badarg;
- }
- if (argv[0] == atom_sha && inspect_mpint(env, argv[1], &data_bin)) {
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
- }
- else if (argv[0] == atom_none && enif_inspect_binary(env,argv[1],&data_bin)
- && data_bin.size == SHA_DIGEST_LENGTH) {
- memcpy(hmacbuf, data_bin.data, SHA_DIGEST_LENGTH);
- }
- else {
- badarg:
DSA_free(dsa);
return enif_make_badarg(env);
}
enif_alloc_binary(DSA_size(dsa), &ret_bin);
- i = DSA_sign(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH,
+ i = DSA_sign(NID_sha1, digest, SHA_DIGEST_LENGTH,
ret_bin.data, &dsa_s_len, dsa);
DSA_free(dsa);
if (i) {
@@ -1558,6 +2009,7 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
}
}
+
static int rsa_pad(ERL_NIF_TERM term, int* padding)
{
if (term == atom_rsa_pkcs1_padding) {
@@ -1623,20 +2075,13 @@ static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TER
}
static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Data, PublKey=[E,N,D], Padding, IsEncrypt) */
+{/* (Data, Key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C], Padding, IsEncrypt) */
ErlNifBinary data_bin, ret_bin;
- ERL_NIF_TERM head, tail;
int padding, i;
RSA* rsa = RSA_new();
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)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->d)
- || !enif_is_empty_list(env,tail)
+ || !get_rsa_private_key(env, argv[1], rsa)
|| !rsa_pad(argv[2], &padding)) {
RSA_free(rsa);
@@ -2026,3 +2471,166 @@ static void hmac_sha1(unsigned char *key, int klen,
SHA1_Final((unsigned char *) hmacbuf, &ctx);
}
+#ifdef HAVE_SHA224
+static void hmac_sha224(unsigned char *key, int klen,
+ unsigned char *dbuf, int dlen,
+ unsigned char *hmacbuf)
+{
+ SHA256_CTX ctx;
+ char ipad[HMAC_INT_LEN];
+ char opad[HMAC_INT_LEN];
+ unsigned char nkey[SHA224_DIGEST_LENGTH];
+ int i;
+
+ /* Change key if longer than 64 bytes */
+ if (klen > HMAC_INT_LEN) {
+ SHA224(key, klen, nkey);
+ key = nkey;
+ klen = SHA224_DIGEST_LENGTH;
+ }
+
+ memset(ipad, '\0', sizeof(ipad));
+ memset(opad, '\0', sizeof(opad));
+ memcpy(ipad, key, klen);
+ memcpy(opad, key, klen);
+
+ for (i = 0; i < HMAC_INT_LEN; i++) {
+ ipad[i] ^= HMAC_IPAD;
+ opad[i] ^= HMAC_OPAD;
+ }
+
+ /* inner SHA */
+ SHA224_Init(&ctx);
+ SHA224_Update(&ctx, ipad, HMAC_INT_LEN);
+ SHA224_Update(&ctx, dbuf, dlen);
+ SHA224_Final((unsigned char *) hmacbuf, &ctx);
+ /* outer SHA */
+ SHA224_Init(&ctx);
+ SHA224_Update(&ctx, opad, HMAC_INT_LEN);
+ SHA224_Update(&ctx, hmacbuf, SHA224_DIGEST_LENGTH);
+ SHA224_Final((unsigned char *) hmacbuf, &ctx);
+}
+#endif
+
+#ifdef HAVE_SHA256
+static void hmac_sha256(unsigned char *key, int klen,
+ unsigned char *dbuf, int dlen,
+ unsigned char *hmacbuf)
+{
+ SHA256_CTX ctx;
+ char ipad[HMAC_INT_LEN];
+ char opad[HMAC_INT_LEN];
+ unsigned char nkey[SHA256_DIGEST_LENGTH];
+ int i;
+
+ /* Change key if longer than 64 bytes */
+ if (klen > HMAC_INT_LEN) {
+ SHA256(key, klen, nkey);
+ key = nkey;
+ klen = SHA256_DIGEST_LENGTH;
+ }
+
+ memset(ipad, '\0', sizeof(ipad));
+ memset(opad, '\0', sizeof(opad));
+ memcpy(ipad, key, klen);
+ memcpy(opad, key, klen);
+
+ for (i = 0; i < HMAC_INT_LEN; i++) {
+ ipad[i] ^= HMAC_IPAD;
+ opad[i] ^= HMAC_OPAD;
+ }
+
+ /* inner SHA */
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, ipad, HMAC_INT_LEN);
+ SHA256_Update(&ctx, dbuf, dlen);
+ SHA256_Final((unsigned char *) hmacbuf, &ctx);
+ /* outer SHA */
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, opad, HMAC_INT_LEN);
+ SHA256_Update(&ctx, hmacbuf, SHA256_DIGEST_LENGTH);
+ SHA256_Final((unsigned char *) hmacbuf, &ctx);
+}
+#endif
+
+#ifdef HAVE_SHA384
+static void hmac_sha384(unsigned char *key, int klen,
+ unsigned char *dbuf, int dlen,
+ unsigned char *hmacbuf)
+{
+ SHA512_CTX ctx;
+ char ipad[HMAC_INT2_LEN];
+ char opad[HMAC_INT2_LEN];
+ unsigned char nkey[SHA384_DIGEST_LENGTH];
+ int i;
+
+ /* Change key if longer than 64 bytes */
+ if (klen > HMAC_INT2_LEN) {
+ SHA384(key, klen, nkey);
+ key = nkey;
+ klen = SHA384_DIGEST_LENGTH;
+ }
+
+ memset(ipad, '\0', sizeof(ipad));
+ memset(opad, '\0', sizeof(opad));
+ memcpy(ipad, key, klen);
+ memcpy(opad, key, klen);
+
+ for (i = 0; i < HMAC_INT2_LEN; i++) {
+ ipad[i] ^= HMAC_IPAD;
+ opad[i] ^= HMAC_OPAD;
+ }
+
+ /* inner SHA */
+ SHA384_Init(&ctx);
+ SHA384_Update(&ctx, ipad, HMAC_INT2_LEN);
+ SHA384_Update(&ctx, dbuf, dlen);
+ SHA384_Final((unsigned char *) hmacbuf, &ctx);
+ /* outer SHA */
+ SHA384_Init(&ctx);
+ SHA384_Update(&ctx, opad, HMAC_INT2_LEN);
+ SHA384_Update(&ctx, hmacbuf, SHA384_DIGEST_LENGTH);
+ SHA384_Final((unsigned char *) hmacbuf, &ctx);
+}
+#endif
+
+#ifdef HAVE_SHA512
+static void hmac_sha512(unsigned char *key, int klen,
+ unsigned char *dbuf, int dlen,
+ unsigned char *hmacbuf)
+{
+ SHA512_CTX ctx;
+ char ipad[HMAC_INT2_LEN];
+ char opad[HMAC_INT2_LEN];
+ unsigned char nkey[SHA512_DIGEST_LENGTH];
+ int i;
+
+ /* Change key if longer than 64 bytes */
+ if (klen > HMAC_INT2_LEN) {
+ SHA512(key, klen, nkey);
+ key = nkey;
+ klen = SHA512_DIGEST_LENGTH;
+ }
+
+ memset(ipad, '\0', sizeof(ipad));
+ memset(opad, '\0', sizeof(opad));
+ memcpy(ipad, key, klen);
+ memcpy(opad, key, klen);
+
+ for (i = 0; i < HMAC_INT2_LEN; i++) {
+ ipad[i] ^= HMAC_IPAD;
+ opad[i] ^= HMAC_OPAD;
+ }
+
+ /* inner SHA */
+ SHA512_Init(&ctx);
+ SHA512_Update(&ctx, ipad, HMAC_INT2_LEN);
+ SHA512_Update(&ctx, dbuf, dlen);
+ SHA512_Final((unsigned char *) hmacbuf, &ctx);
+ /* outer SHA */
+ SHA512_Init(&ctx);
+ SHA512_Update(&ctx, opad, HMAC_INT2_LEN);
+ SHA512_Update(&ctx, hmacbuf, SHA512_DIGEST_LENGTH);
+ SHA512_Final((unsigned char *) hmacbuf, &ctx);
+}
+#endif