diff options
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.cpp | 193 |
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); + } + +} |