summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Schultz <aschultz@tpip.net>2012-09-12 20:57:01 +0200
committerAndreas Schultz <aschultz@tpip.net>2013-02-27 19:24:13 +0100
commitfff8db022229ed049539fbbd3cf894303d963288 (patch)
tree0559de0a1ea4dd63e5c31787eee3293f6dd1c4fd
parent522bbf7053358d6c150a04a4bbf2ea539797f315 (diff)
downloaderlang-fff8db022229ed049539fbbd3cf894303d963288.tar.gz
CRYPTO: add support for RFC-2945 SRP-3 and RFC-5054 SRP-6a authentication
-rw-r--r--lib/crypto/c_src/crypto.c216
-rwxr-xr-xlib/crypto/doc/src/crypto.xml89
-rw-r--r--lib/crypto/src/crypto.erl77
-rw-r--r--lib/crypto/test/crypto_SUITE.erl154
4 files changed, 535 insertions, 1 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index e77e5fb8f0..e040310c58 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -207,6 +207,9 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E
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(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[]);
@@ -321,6 +324,9 @@ static ErlNifFunc nif_funcs[] = {
{"dh_check", 1, dh_check},
{"dh_generate_key_nif", 2, 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", 5, srp_server_secret},
{"bf_cfb64_crypt", 4, bf_cfb64_crypt},
{"bf_cbc_crypt", 4, bf_cbc_crypt},
{"bf_ecb_crypt", 3, bf_ecb_crypt},
@@ -1515,6 +1521,17 @@ static int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
return 1;
}
+static int get_bn_from_bin(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
+{
+ ErlNifBinary bin;
+ if (!enif_inspect_binary(env,term,&bin)) {
+ return 0;
+ }
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(bin.data, bin.size);
+ *bnp = BN_bin2bn(bin.data, bin.size, NULL);
+ return 1;
+}
+
static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Lo,Hi) */
BIGNUM *bn_from = NULL, *bn_to, *bn_rand;
@@ -2344,6 +2361,205 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
return ret;
}
+static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Multiplier, Verifier, Generator, Exponent, Prime) */
+ BIGNUM *bn_verifier = NULL;
+ BIGNUM *bn_exponent, *bn_generator, *bn_prime, *bn_multiplier, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ if (!get_bn_from_mpint(env, argv[0], &bn_multiplier)
+ || !get_bn_from_bin(env, argv[1], &bn_verifier)
+ || !get_bn_from_bin(env, argv[2], &bn_generator)
+ || !get_bn_from_bin(env, argv[3], &bn_exponent)
+ || !get_bn_from_bin(env, argv[4], &bn_prime)) {
+ if (bn_multiplier) BN_free(bn_multiplier);
+ if (bn_verifier) BN_free(bn_verifier);
+ if (bn_verifier) BN_free(bn_generator);
+ if (bn_verifier) BN_free(bn_exponent);
+ if (bn_verifier) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_result = BN_new();
+ bn_ctx = BN_CTX_new();
+
+ /* B = k*v + g^b % N */
+
+ /* k * v */
+ BN_mod_mul(bn_multiplier, bn_multiplier, bn_verifier, bn_prime, bn_ctx);
+
+ /* g^b % N */
+ BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx);
+
+ /* k*v + g^b % N */
+ BN_mod_add(bn_result, bn_result, bn_multiplier, bn_prime, bn_ctx);
+
+ /* check that B % N != 0, reuse bn_multiplier */
+ BN_nnmod(bn_multiplier, bn_result, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_multiplier)) {
+ ret = atom_error;
+ } else {
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ }
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+ BN_free(bn_prime);
+ BN_free(bn_generator);
+ BN_free(bn_multiplier);
+ BN_free(bn_exponent);
+ BN_free(bn_verifier);
+ return ret;
+}
+
+static ERL_NIF_TERM srp_client_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
+*/
+ BIGNUM *bn_exponent = NULL, *bn_a = NULL;
+ BIGNUM *bn_u, *bn_multiplier, *bn_exp2, *bn_base,
+ *bn_prime, *bn_generator, *bn_B, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ if (!get_bn_from_bin(env, argv[0], &bn_a)
+ || !get_bn_from_bin(env, argv[1], &bn_u)
+ || !get_bn_from_bin(env, argv[2], &bn_B)
+ || !get_bn_from_mpint(env, argv[3], &bn_multiplier)
+ || !get_bn_from_bin(env, argv[4], &bn_generator)
+ || !get_bn_from_bin(env, argv[5], &bn_exponent)
+ || !get_bn_from_bin(env, argv[6], &bn_prime))
+ {
+ if (bn_exponent) BN_free(bn_exponent);
+ if (bn_a) BN_free(bn_a);
+ if (bn_u) BN_free(bn_u);
+ if (bn_B) BN_free(bn_B);
+ if (bn_multiplier) BN_free(bn_multiplier);
+ if (bn_generator) BN_free(bn_generator);
+ if (bn_prime) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_ctx = BN_CTX_new();
+ bn_result = BN_new();
+
+ /* check that B % N != 0 */
+ BN_nnmod(bn_result, bn_B, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_result)) {
+ BN_free(bn_exponent);
+ BN_free(bn_a);
+ BN_free(bn_generator);
+ BN_free(bn_prime);
+ BN_free(bn_u);
+ BN_free(bn_B);
+ BN_CTX_free(bn_ctx);
+
+ return atom_error;
+ }
+
+ /* (B - (k * g^x)) */
+ bn_base = BN_new();
+ BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx);
+ BN_mod_mul(bn_result, bn_multiplier, bn_result, bn_prime, bn_ctx);
+ BN_mod_sub(bn_base, bn_B, bn_result, bn_prime, bn_ctx);
+
+ /* a + (u * x) */
+ bn_exp2 = BN_new();
+ BN_mod_mul(bn_result, bn_u, bn_exponent, bn_prime, bn_ctx);
+ BN_mod_add(bn_exp2, bn_a, bn_result, bn_prime, bn_ctx);
+
+ /* (B - (k * g^x)) ^ (a + (u * x)) % N */
+ BN_mod_exp(bn_result, bn_base, bn_exp2, bn_prime, bn_ctx);
+
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+
+ BN_free(bn_multiplier);
+ BN_free(bn_exp2);
+ BN_free(bn_u);
+ BN_free(bn_exponent);
+ BN_free(bn_a);
+ BN_free(bn_B);
+ BN_free(bn_base);
+ BN_free(bn_generator);
+ BN_free(bn_prime);
+ return ret;
+}
+
+static ERL_NIF_TERM srp_server_secret(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Verifier, b, u, A, Prime) */
+/*
+ <premaster secret> = (A * v^u) ^ b % N
+*/
+ BIGNUM *bn_b = NULL, *bn_verifier = NULL;
+ BIGNUM *bn_prime, *bn_A, *bn_u, *bn_base, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ if (!get_bn_from_bin(env, argv[0], &bn_verifier)
+ || !get_bn_from_bin(env, argv[1], &bn_b)
+ || !get_bn_from_bin(env, argv[2], &bn_u)
+ || !get_bn_from_bin(env, argv[3], &bn_A)
+ || !get_bn_from_bin(env, argv[4], &bn_prime))
+ {
+ if (bn_verifier) BN_free(bn_verifier);
+ if (bn_b) BN_free(bn_b);
+ if (bn_u) BN_free(bn_u);
+ if (bn_A) BN_free(bn_A);
+ if (bn_prime) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_ctx = BN_CTX_new();
+ bn_result = BN_new();
+
+ /* check that A % N != 0 */
+ BN_nnmod(bn_result, bn_A, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_result)) {
+ BN_free(bn_b);
+ BN_free(bn_verifier);
+ BN_free(bn_prime);
+ BN_free(bn_A);
+ BN_CTX_free(bn_ctx);
+
+ return atom_error;
+ }
+
+ /* (A * v^u) */
+ bn_base = BN_new();
+ BN_mod_exp(bn_base, bn_verifier, bn_u, bn_prime, bn_ctx);
+ BN_mod_mul(bn_base, bn_A, bn_base, bn_prime, bn_ctx);
+
+ /* (A * v^u) ^ b % N */
+ BN_mod_exp(bn_result, bn_base, bn_b, bn_prime, bn_ctx);
+
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+
+ BN_free(bn_u);
+ BN_free(bn_base);
+ BN_free(bn_verifier);
+ BN_free(bn_prime);
+ BN_free(bn_A);
+ BN_free(bn_b);
+ return ret;
+}
+
static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, Ivec, Data, IsEncrypt) */
ErlNifBinary key_bin, ivec_bin, data_bin;
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 6b9b2ef207..ea837df255 100755
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -1256,6 +1256,95 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</desc>
</func>
+ <func>
+ <name>srp_mod_exp(Generator, Exponent, Prime) -> Result</name>
+ <fsummary>Computes the SRP-SHA function: g^x % N</fsummary>
+ <type>
+ <v>Generator, Exponent, Prime = binary()</v>
+ <v>Result = binary() | error</v>
+ </type>
+ <desc>
+ <p>Computes the SRP-SHA function g^x % N used for the verifier and client public key (RFC-2945, Sect. 3)
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>srp_value_B(Multiplier, Verifier, Generator, Exponent, Prime) -> ValueB</name>
+ <fsummary>Computes the SRP function: B = k*v + g^b % N</fsummary>
+ <type>
+ <v>Verifier (v), Generator (g), Exponent (b), Prime (N), ValueB (B) = binary()</v>
+ <v>Multiplier (k) = integer() | binary()</v>
+ </type>
+ <desc>
+ <p>Computes the SRP value B according to RFC-2945, Sect. 3 and RFC-5054, Sect. 2.5.3</p>
+ <p>B = k*v + g^b % N</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>srp_client_secret(A, U, B, Multiplier, Generator, Exponent, Prime) -> Secret</name>
+ <fsummary>Computes the SRP client secret</fsummary>
+ <type>
+ <v>A (a), U (u), B, Multiplier (k), Generator (g), Exponent (x), Prime (N), Secret = binary()</v>
+ <v>Multiplier (k) = integer() | binary()</v>
+ </type>
+ <desc>
+ <p>Computes the SRP client secret according to RFC-2945, Sect. 3 and RFC-5054, Sect. 2.6</p>
+ <p>Secret = (B - (k * g^x)) ^ (a + (u * x)) % N</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>srp_server_secret(Verifier, B, U, A, Prime) -> Secret</name>
+ <fsummary>Computes the SRP host secret</fsummary>
+ <type>
+ <v>Verifier (v), B (b), U (u), A, Prime (N), Secret = binary()</v>
+ </type>
+ <desc>
+ <p>Computes the SRP host secret according to RFC-2945, Sect. 3 and RFC-5054, Sect. 2.6</p>
+ <p>Secret = (A * v^u) ^ b % N</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>srp3_value_u(B) -> Result</name>
+ <fsummary>Computes the SRP3-SHA value u</fsummary>
+ <type>
+ <v>B = binary()</v>
+ <v>Result = integer()</v>
+ </type>
+ <desc>
+ <p>Computes the SRP-3 value u according to RFC-2945, Sect. 3
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>srp6_value_u(A, B, Prime) -> Result</name>
+ <fsummary>Computes the SRP6a value u as u = SHA1(PAD(A) | PAD(B))</fsummary>
+ <type>
+ <v>A, B, Prime = binary()</v>
+ <v>Result = integer()</v>
+ </type>
+ <desc>
+ <p>Computes the SRP-6 value u according to RFC-5054, Sect. 2.6
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>srp6a_multiplier(Generator, Prime) -> Result</name>
+ <fsummary>Computes the SRP-SHA function: k = SHA1(N | PAD(g))</fsummary>
+ <type>
+ <v>Generator, Prime = binary()</v>
+ <v>Result = integer()</v>
+ </type>
+ <desc>
+ <p>Computes the SRP-6a function SHA1(N | PAD(g)) as the multiplier
+ </p>
+ </desc>
+ </func>
<func>
<name>exor(Data1, Data2) -> Result</name>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 1328a95e87..a9b350842f 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -58,6 +58,10 @@
-export([rand_bytes/1, rand_bytes/3, rand_uniform/2]).
-export([strong_rand_bytes/1, strong_rand_mpint/3]).
-export([mod_exp/3, mpint/1, erlint/1]).
+-export([srp_mod_exp/3, srp_value_B/5]).
+-export([srp3_value_u/1, srp6_value_u/3, srp6a_multiplier/2]).
+-export([srp_client_secret/7, srp_server_secret/5]).
+
%% -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]).
@@ -109,6 +113,9 @@
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_mod_exp, srp_value_B,
+ srp3_value_u, srp6_value_u, srp6a_multiplier,
+ srp_client_secret, srp_server_secret,
info_lib]).
-type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
@@ -1065,9 +1072,72 @@ dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) ->
dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub.
%%
+%% SRP functions
+%%
+-spec srp_mod_exp(binary(), binary(), binary()) -> binary().
+srp_mod_exp(Generator, Exponent, Prime) ->
+ Verifier = mod_exp_nif(bin2bn(Generator), bin2bn(Exponent), bin2bn(Prime)),
+ case erlint(Verifier) of
+ 0 -> error;
+ _ -> bn2bin(Verifier)
+ end.
+
+-spec srp_value_B(binary(), integer(), binary(), binary(), binary()) -> binary().
+srp_value_B(Multiplier, Verifier, Generator, Exponent, Prime) ->
+ srp_value_B_nif(srp_multiplier(Multiplier), Verifier, Generator, Exponent, Prime).
+
+srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub.
+
+-spec srp_client_secret(binary(), binary(), binary(), integer()|binary(), binary(), binary(), binary()) -> binary().
+srp_client_secret(A, U, B, Multiplier, Generator, Exponent, Prime) ->
+ srp_client_secret_nif(A, U, B, srp_multiplier(Multiplier), Generator, Exponent, Prime).
+
+srp_client_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub.
+
+-spec srp_server_secret(binary(), binary(), binary(), binary(), binary()) -> binary().
+srp_server_secret(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub.
+
+-spec srp6a_multiplier(binary(), binary()) -> binary().
+srp6a_multiplier(Generator, Prime) ->
+ %% k = SHA1(N | PAD(g))
+ C0 = sha_init(),
+ C1 = sha_update(C0, Prime),
+ C2 = sha_update(C1, srp_pad_to(erlang:byte_size(Prime), Generator)),
+ sha_final(C2).
+
+-spec srp3_value_u(binary()) -> binary().
+srp3_value_u(B) ->
+ %% 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(B),
+ U.
+
+-spec srp6_value_u(binary(), binary(), binary()) -> binary().
+srp6_value_u(A, B, Prime) ->
+ %% SHA1(PAD(A) | PAD(B))
+ PadLength = erlang:byte_size(Prime),
+ C0 = sha_init(),
+ C1 = sha_update(C0, srp_pad_to(PadLength, A)),
+ C2 = sha_update(C1, srp_pad_to(PadLength, B)),
+ sha_final(C2).
+
+%%
%% LOCAL FUNCTIONS
%%
+srp_pad_length(Width, Length) ->
+ (Width - Length rem Width) rem Width.
+
+srp_pad_to(Width, Binary) ->
+ case srp_pad_length(Width, size(Binary)) of
+ 0 -> Binary;
+ N -> << 0:(N*8), Binary/binary>>
+ end.
+
+srp_multiplier(Multiplier) when is_binary(Multiplier) ->
+ bin2bn(Multiplier);
+srp_multiplier(Multiplier) when is_integer(Multiplier) ->
+ mpint(Multiplier).
%% large integer in a binary with 32bit length
%% MP representaion (SSH2)
@@ -1111,3 +1181,10 @@ erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) ->
Bits= MPIntSize * 8,
<<Integer:Bits/integer>> = MPIntValue,
Integer.
+
+bin2bn(Bin) ->
+ Len = erlang:byte_size(Bin),
+ <<?UINT32(Len), Bin/binary>>.
+
+bn2bin(<<_:32, Bin/binary>>) ->
+ Bin.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 6f2df0f07b..01c6b0cae4 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -72,6 +72,7 @@
dsa_sign_hash_test/1,
rsa_encrypt_decrypt/1,
dh/1,
+ srp3/1, srp6/1, srp6a/1,
exor_test/1,
rc4_test/1,
rc4_stream_test/1,
@@ -100,7 +101,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, exor_test,
+ rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, exor_test,
rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64,
smp]}].
@@ -2017,6 +2018,157 @@ dh(Config) when is_list(Config) ->
exit(Pid, kill)
end.
+srp3(doc) ->
+ ["SRP-3 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
+srp3(suite) -> [];
+srp3(Config) when is_list(Config) ->
+ Username = <<"alice">>,
+ Password = <<"password123">>,
+ Salt = hexstr2bin("2857827A19266A1F2BC6"),
+ Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+ "FD5138FE8376435B9FC61D2FC0EB06E3"),
+ Generator = <<2>>,
+ Multiplier = 1,
+ %% X = hexstr2bin("96E54AB0CD4C5123EDCFA4A1502918AAD3C9E2A8"),
+ Verifier = hexstr2bin("96EB5F13621D911AA1CA405DE9C64217D4108EEEECAFFE500034FE0E"
+ "C031E42C8714667C161BCE0E7996F7DDE1B63824C130D2D7286C08C0"
+ "49758420735961347112AE102A3F23B3F687F8FEE0DF2BFAF933C608"
+ "D6FE5B5EEE3116FE54016E065BF8E8C9FDBBC08719231AC215149140"
+ "519E8FDD9AA4F410C28A58AF42974D2D"),
+ ClntPriv = hexstr2bin("6411DE75538BED8170677D577D0608F39112BC95B503C447EB6AC945"
+ "49C75C7B"),
+ SrvrPriv = hexstr2bin("85E44A6F694DBE676145DB245A045CD37C99F05C562C7840A31F270D"
+ "9AADCF8B"),
+ ClntPub = hexstr2bin("B22B1FFA2244B8CB94F3A9080F419CAEAB0DBA93EA1965B5E84587EE"
+ "55C79E7A118865DC59B9D0353362C2A8261E7C1B0D221A0E233C2AD1"
+ "640DACBB8664CBC9733EAC392DA7800142860380C3FC573C3C064329"
+ "CF54063FD114C7210E9CB3A611EA8002B1844B698F930D95D143899B"
+ "948A090E0C25938E5F84067D1883DC63"),
+ SrvrPub = hexstr2bin("93A8C4D8B7F7395ADCFD4ABA37B015124513D3F37B3E85EB23064BE5"
+ "F53C0AE32FFB9D8C0AA0DCFFA74D632DD67DEBB5C35AAE9812286CC8"
+ "C43CC176ECBC6D3F447594D9554E995B2509127BF88FADDDA4982D03"
+ "8EC3001320712D3B1269308CE70F319B2295FA57674F03A2D993CFB1"
+ "F84C35B7D0C012FA73CD4C8F7D5A71C7"),
+ U = hexstr2bin("02E2476A"),
+
+ PremasterSecret = hexstr2bin("C29A986C4D521BBC66428ED11D994CD7431574A6184B83CDCC345092"
+ "791E75748A1D38CAC4BD14760F0D2694B711236419240FF2F172454C"
+ "46ABF4FF39498DAFDD2C82924F7D7BD76CDFCE688C77D93F18A65409"
+ "9176A9192615DC0277AE7C12F1F6A7F6563FCA11675D809AF578BDE5"
+ "2B51E05D440B63099A017A0B45044801"),
+ UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
+ m(crypto:srp_mod_exp(Generator, UserPassHash, Prime), Verifier),
+ m(crypto:srp_mod_exp(Generator, ClntPriv, Prime), ClntPub),
+ m(crypto:srp3_value_u(SrvrPub), U),
+ m(crypto:srp_value_B(Multiplier, Verifier, Generator, SrvrPriv, Prime), SrvrPub),
+ m(crypto:srp_client_secret(ClntPriv, U, SrvrPub, Multiplier, Generator, UserPassHash, Prime), PremasterSecret),
+ m(crypto:srp_server_secret(Verifier, SrvrPriv, U, ClntPub, Prime), PremasterSecret),
+ ok.
+
+srp6(doc) ->
+ ["SRP-6 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
+srp6(suite) -> [];
+srp6(Config) when is_list(Config) ->
+ Username = <<"alice">>,
+ Password = <<"password123">>,
+ Salt = hexstr2bin("2857827A19266A1F2BC6"),
+ Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+ "FD5138FE8376435B9FC61D2FC0EB06E3"),
+ Generator = <<2>>,
+ Multiplier = 3,
+ %% X = hexstr2bin("96E54AB0CD4C5123EDCFA4A1502918AAD3C9E2A8"),
+ Verifier = hexstr2bin("96EB5F13621D911AA1CA405DE9C64217D4108EEEECAFFE500034FE0E"
+ "C031E42C8714667C161BCE0E7996F7DDE1B63824C130D2D7286C08C0"
+ "49758420735961347112AE102A3F23B3F687F8FEE0DF2BFAF933C608"
+ "D6FE5B5EEE3116FE54016E065BF8E8C9FDBBC08719231AC215149140"
+ "519E8FDD9AA4F410C28A58AF42974D2D"),
+ ClntPriv = hexstr2bin("6411DE75538BED8170677D577D0608F39112BC95B503C447EB6AC945"
+ "49C75C7B"),
+ SrvrPriv = hexstr2bin("85E44A6F694DBE676145DB245A045CD37C99F05C562C7840A31F270D"
+ "9AADCF8B"),
+ ClntPub = hexstr2bin("B22B1FFA2244B8CB94F3A9080F419CAEAB0DBA93EA1965B5E84587EE"
+ "55C79E7A118865DC59B9D0353362C2A8261E7C1B0D221A0E233C2AD1"
+ "640DACBB8664CBC9733EAC392DA7800142860380C3FC573C3C064329"
+ "CF54063FD114C7210E9CB3A611EA8002B1844B698F930D95D143899B"
+ "948A090E0C25938E5F84067D1883DC63"),
+ SrvrPub = hexstr2bin("D2D07845CE7ECDB9845DD36B10ACD3598CC29049DE9F467F84CE16B6"
+ "D97A6DC567AF8B0F9FEDF74962400AD5C357951E64E67B641246F264"
+ "C8DE6D9A72E554D6C8D3194548780A0C438A0FCC509CA88A14AA1DEB"
+ "C0F09E4B37A965D1545DB4AD361346F3189B0EA569C06D326C4E4797"
+ "9E381C748293B7C0591BE0BE419E053E"),
+ U = hexstr2bin("0A2534C0BF52A0DA9001EEC62CF2A546AB0908A7"),
+
+ PremasterSecret = hexstr2bin("19D22C19612874EBF1F2581F8EFCFDC44C6FDA3B87B0A73823D7E962"
+ "554295D4E48D3A336523ADBDDD0EC8FB0F02687109E97E01C17C93CC"
+ "7216F9CD8A4AC39F0429857D8D1023066614BDFCBCB89F59A0FEB81C"
+ "72E992AAD89095A84B6A5FADA152369AB1E350A03693BEF044DF3EDF"
+ "0C34741F4696C30E9F675D09F58ACBEB"),
+ UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
+ m(crypto:srp_mod_exp(Generator, UserPassHash, Prime), Verifier),
+ m(crypto:srp_mod_exp(Generator, ClntPriv, Prime), ClntPub),
+ m(crypto:srp6_value_u(ClntPub, SrvrPub, Prime), U),
+ m(crypto:srp_value_B(Multiplier, Verifier, Generator, SrvrPriv, Prime), SrvrPub),
+ m(crypto:srp_client_secret(ClntPriv, U, SrvrPub, Multiplier, Generator, UserPassHash, Prime), PremasterSecret),
+ m(crypto:srp_server_secret(Verifier, SrvrPriv, U, ClntPub, Prime), PremasterSecret),
+ ok.
+
+srp6a(doc) ->
+ ["SRP-6a test vectors from RFC5054."];
+srp6a(suite) -> [];
+srp6a(Config) when is_list(Config) ->
+ Username = <<"alice">>,
+ Password = <<"password123">>,
+ Salt = hexstr2bin("BEB25379D1A8581EB5A727673A2441EE"),
+ Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+ "FD5138FE8376435B9FC61D2FC0EB06E3"),
+ Generator = <<2>>,
+ Multiplier = hexstr2bin("7556AA045AEF2CDD07ABAF0F665C3E818913186F"),
+ %% X = hexstr2bin("94B7555AABE9127CC58CCF4993DB6CF84D16C124"),
+ Verifier = hexstr2bin("7E273DE8696FFC4F4E337D05B4B375BEB0DDE1569E8FA00A9886D812"
+ "9BADA1F1822223CA1A605B530E379BA4729FDC59F105B4787E5186F5"
+ "C671085A1447B52A48CF1970B4FB6F8400BBF4CEBFBB168152E08AB5"
+ "EA53D15C1AFF87B2B9DA6E04E058AD51CC72BFC9033B564E26480D78"
+ "E955A5E29E7AB245DB2BE315E2099AFB"),
+ ClntPriv = hexstr2bin("60975527035CF2AD1989806F0407210BC81EDC04E2762A56AFD529DD"
+ "DA2D4393"),
+ SrvrPriv = hexstr2bin("E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D1"
+ "05284D20"),
+ ClntPub = hexstr2bin("61D5E490F6F1B79547B0704C436F523DD0E560F0C64115BB72557EC4"
+ "4352E8903211C04692272D8B2D1A5358A2CF1B6E0BFCF99F921530EC"
+ "8E39356179EAE45E42BA92AEACED825171E1E8B9AF6D9C03E1327F44"
+ "BE087EF06530E69F66615261EEF54073CA11CF5858F0EDFDFE15EFEA"
+ "B349EF5D76988A3672FAC47B0769447B"),
+ SrvrPub = hexstr2bin("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011"
+ "BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC99"
+ "6C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA"
+ "37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAE"
+ "EB4012B7D7665238A8E3FB004B117B58"),
+ U = hexstr2bin("CE38B9593487DA98554ED47D70A7AE5F462EF019"),
+
+ PremasterSecret = hexstr2bin("B0DC82BABCF30674AE450C0287745E7990A3381F63B387AAF271A10D"
+ "233861E359B48220F7C4693C9AE12B0A6F67809F0876E2D013800D6C"
+ "41BB59B6D5979B5C00A172B4A2A5903A0BDCAF8A709585EB2AFAFA8F"
+ "3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D"
+ "C346D7E474B29EDE8A469FFECA686E5A"),
+ UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
+ m(crypto:srp_mod_exp(Generator, UserPassHash, Prime), Verifier),
+ m(crypto:srp_mod_exp(Generator, ClntPriv, Prime), ClntPub),
+ m(crypto:srp6a_multiplier(Generator, Prime), Multiplier),
+ m(crypto:srp6_value_u(ClntPub, SrvrPub, Prime), U),
+ m(crypto:srp_value_B(Multiplier, Verifier, Generator, SrvrPriv, Prime), SrvrPub),
+ m(crypto:srp_client_secret(ClntPriv, U, SrvrPub, Multiplier, Generator, UserPassHash, Prime), PremasterSecret),
+ m(crypto:srp_server_secret(Verifier, SrvrPriv, U, ClntPub, Prime), PremasterSecret),
+ ok.
+
%%
%%
exor_test(doc) ->