summaryrefslogtreecommitdiffstats
path: root/comm/third_party/botan/src/lib/misc/srp6/srp6.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/third_party/botan/src/lib/misc/srp6/srp6.cpp')
-rw-r--r--comm/third_party/botan/src/lib/misc/srp6/srp6.cpp193
1 files changed, 193 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/misc/srp6/srp6.cpp b/comm/third_party/botan/src/lib/misc/srp6/srp6.cpp
new file mode 100644
index 0000000000..0bd9b192ae
--- /dev/null
+++ b/comm/third_party/botan/src/lib/misc/srp6/srp6.cpp
@@ -0,0 +1,193 @@
+/*
+* SRP-6a (RFC 5054 compatatible)
+* (C) 2011,2012,2019 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/srp6.h>
+#include <botan/hash.h>
+#include <botan/dl_group.h>
+#include <botan/numthry.h>
+
+namespace Botan {
+
+namespace {
+
+BigInt hash_seq(const std::string& hash_id,
+ size_t pad_to,
+ const BigInt& in1,
+ const BigInt& in2)
+ {
+ std::unique_ptr<HashFunction> hash_fn(HashFunction::create_or_throw(hash_id));
+
+ hash_fn->update(BigInt::encode_1363(in1, pad_to));
+ hash_fn->update(BigInt::encode_1363(in2, pad_to));
+
+ return BigInt::decode(hash_fn->final());
+ }
+
+BigInt compute_x(const std::string& hash_id,
+ const std::string& identifier,
+ const std::string& password,
+ const std::vector<uint8_t>& salt)
+ {
+ std::unique_ptr<HashFunction> hash_fn(HashFunction::create_or_throw(hash_id));
+
+ hash_fn->update(identifier);
+ hash_fn->update(":");
+ hash_fn->update(password);
+
+ secure_vector<uint8_t> inner_h = hash_fn->final();
+
+ hash_fn->update(salt);
+ hash_fn->update(inner_h);
+
+ secure_vector<uint8_t> outer_h = hash_fn->final();
+
+ return BigInt::decode(outer_h);
+ }
+
+}
+
+std::string srp6_group_identifier(const BigInt& N, const BigInt& g)
+ {
+ /*
+ This function assumes that only one 'standard' SRP parameter set has
+ been defined for a particular bitsize. As of this writing that is the case.
+ */
+ try
+ {
+ const std::string group_name = "modp/srp/" + std::to_string(N.bits());
+
+ DL_Group group(group_name);
+
+ if(group.get_p() == N && group.get_g() == g)
+ return group_name;
+ }
+ catch(...)
+ {
+ }
+
+ // If we didn't return, the group was unknown or did not match
+ throw Invalid_Argument("Invalid or unknown SRP group parameters");
+ }
+
+std::pair<BigInt, SymmetricKey>
+srp6_client_agree(const std::string& identifier,
+ const std::string& password,
+ const std::string& group_id,
+ const std::string& hash_id,
+ const std::vector<uint8_t>& salt,
+ const BigInt& B,
+ RandomNumberGenerator& rng)
+ {
+ DL_Group group(group_id);
+ const size_t a_bits = group.exponent_bits();
+
+ return srp6_client_agree(identifier, password, group, hash_id, salt, B, a_bits, rng);
+ }
+
+std::pair<BigInt, SymmetricKey>
+srp6_client_agree(const std::string& identifier,
+ const std::string& password,
+ const DL_Group& group,
+ const std::string& hash_id,
+ const std::vector<uint8_t>& salt,
+ const BigInt& B,
+ const size_t a_bits,
+ RandomNumberGenerator& rng)
+ {
+ const BigInt& g = group.get_g();
+ const BigInt& p = group.get_p();
+
+ const size_t p_bytes = group.p_bytes();
+
+ if(B <= 0 || B >= p)
+ throw Decoding_Error("Invalid SRP parameter from server");
+
+ const BigInt k = hash_seq(hash_id, p_bytes, p, g);
+
+ const BigInt a(rng, a_bits);
+
+ const BigInt A = group.power_g_p(a, a_bits);
+
+ const BigInt u = hash_seq(hash_id, p_bytes, A, B);
+
+ const BigInt x = compute_x(hash_id, identifier, password, salt);
+
+ const BigInt S = power_mod(group.mod_p(B - (k * power_mod(g, x, p))),
+ group.mod_p(a + (u * x)), p);
+
+ const SymmetricKey Sk(BigInt::encode_1363(S, p_bytes));
+
+ return std::make_pair(A, Sk);
+ }
+
+BigInt generate_srp6_verifier(const std::string& identifier,
+ const std::string& password,
+ const std::vector<uint8_t>& salt,
+ const std::string& group_id,
+ const std::string& hash_id)
+ {
+ DL_Group group(group_id);
+ return generate_srp6_verifier(identifier, password, salt, group, hash_id);
+ }
+
+BigInt generate_srp6_verifier(const std::string& identifier,
+ const std::string& password,
+ const std::vector<uint8_t>& salt,
+ const DL_Group& group,
+ const std::string& hash_id)
+ {
+ const BigInt x = compute_x(hash_id, identifier, password, salt);
+ // FIXME: x should be size of hash fn so avoid computing x.bits() here
+ return group.power_g_p(x, x.bits());
+ }
+
+BigInt SRP6_Server_Session::step1(const BigInt& v,
+ const std::string& group_id,
+ const std::string& hash_id,
+ RandomNumberGenerator& rng)
+ {
+ DL_Group group(group_id);
+ const size_t b_bits = group.exponent_bits();
+
+ return this->step1(v, group, hash_id, b_bits, rng);
+ }
+
+BigInt SRP6_Server_Session::step1(const BigInt& v,
+ const DL_Group& group,
+ const std::string& hash_id,
+ size_t b_bits,
+ RandomNumberGenerator& rng)
+ {
+ const BigInt& g = group.get_g();
+ const BigInt& p = group.get_p();
+
+ m_p_bytes = p.bytes();
+ m_v = v;
+ m_b = BigInt(rng, b_bits);
+ m_p = p;
+ m_hash_id = hash_id;
+
+ const BigInt k = hash_seq(hash_id, m_p_bytes, p, g);
+
+ m_B = group.mod_p(v*k + group.power_g_p(m_b, b_bits));
+
+ return m_B;
+ }
+
+SymmetricKey SRP6_Server_Session::step2(const BigInt& A)
+ {
+ if(A <= 0 || A >= m_p)
+ throw Decoding_Error("Invalid SRP parameter from client");
+
+ const BigInt u = hash_seq(m_hash_id, m_p_bytes, A, m_B);
+
+ const BigInt S = power_mod(A * power_mod(m_v, u, m_p), m_b, m_p);
+
+ return BigInt::encode_1363(S, m_p_bytes);
+ }
+
+}