Botan  1.11.15
src/lib/misc/srp6/srp6.cpp
Go to the documentation of this file.
00001 /*
00002 * SRP-6a (RFC 5054 compatatible)
00003 * (C) 2011,2012 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/srp6.h>
00009 #include <botan/dl_group.h>
00010 #include <botan/numthry.h>
00011 #include <botan/lookup.h>
00012 
00013 namespace Botan {
00014 
00015 namespace {
00016 
00017 BigInt hash_seq(const std::string& hash_id,
00018                 size_t pad_to,
00019                 const BigInt& in1,
00020                 const BigInt& in2)
00021    {
00022    std::unique_ptr<HashFunction> hash_fn(get_hash(hash_id));
00023 
00024    hash_fn->update(BigInt::encode_1363(in1, pad_to));
00025    hash_fn->update(BigInt::encode_1363(in2, pad_to));
00026 
00027    return BigInt::decode(hash_fn->final());
00028    }
00029 
00030 BigInt compute_x(const std::string& hash_id,
00031                  const std::string& identifier,
00032                  const std::string& password,
00033                  const std::vector<byte>& salt)
00034    {
00035    std::unique_ptr<HashFunction> hash_fn(get_hash(hash_id));
00036 
00037    hash_fn->update(identifier);
00038    hash_fn->update(":");
00039    hash_fn->update(password);
00040 
00041    secure_vector<byte> inner_h = hash_fn->final();
00042 
00043    hash_fn->update(salt);
00044    hash_fn->update(inner_h);
00045 
00046    secure_vector<byte> outer_h = hash_fn->final();
00047 
00048    return BigInt::decode(outer_h);
00049    }
00050 
00051 }
00052 
00053 std::string srp6_group_identifier(const BigInt& N, const BigInt& g)
00054    {
00055    /*
00056    This function assumes that only one 'standard' SRP parameter set has
00057    been defined for a particular bitsize. As of this writing that is the case.
00058    */
00059    try
00060       {
00061       const std::string group_name = "modp/srp/" + std::to_string(N.bits());
00062 
00063       DL_Group group(group_name);
00064 
00065       if(group.get_p() == N && group.get_g() == g)
00066          return group_name;
00067 
00068       throw std::runtime_error("Unknown SRP params");
00069       }
00070    catch(...)
00071       {
00072       throw Invalid_Argument("Bad SRP group parameters");
00073       }
00074    }
00075 
00076 std::pair<BigInt, SymmetricKey>
00077 srp6_client_agree(const std::string& identifier,
00078                   const std::string& password,
00079                   const std::string& group_id,
00080                   const std::string& hash_id,
00081                   const std::vector<byte>& salt,
00082                   const BigInt& B,
00083                   RandomNumberGenerator& rng)
00084    {
00085    DL_Group group(group_id);
00086    const BigInt& g = group.get_g();
00087    const BigInt& p = group.get_p();
00088 
00089    const size_t p_bytes = group.get_p().bytes();
00090 
00091    if(B <= 0 || B >= p)
00092       throw std::runtime_error("Invalid SRP parameter from server");
00093 
00094    BigInt k = hash_seq(hash_id, p_bytes, p, g);
00095 
00096    BigInt a(rng, 256);
00097 
00098    BigInt A = power_mod(g, a, p);
00099 
00100    BigInt u = hash_seq(hash_id, p_bytes, A, B);
00101 
00102    const BigInt x = compute_x(hash_id, identifier, password, salt);
00103 
00104    BigInt S = power_mod((B - (k * power_mod(g, x, p))) % p, (a + (u * x)), p);
00105 
00106    SymmetricKey Sk(BigInt::encode_1363(S, p_bytes));
00107 
00108    return std::make_pair(A, Sk);
00109    }
00110 
00111 BigInt generate_srp6_verifier(const std::string& identifier,
00112                               const std::string& password,
00113                               const std::vector<byte>& salt,
00114                               const std::string& group_id,
00115                               const std::string& hash_id)
00116    {
00117    const BigInt x = compute_x(hash_id, identifier, password, salt);
00118 
00119    DL_Group group(group_id);
00120    return power_mod(group.get_g(), x, group.get_p());
00121    }
00122 
00123 BigInt SRP6_Server_Session::step1(const BigInt& v,
00124                                   const std::string& group_id,
00125                                   const std::string& hash_id,
00126                                   RandomNumberGenerator& rng)
00127    {
00128    DL_Group group(group_id);
00129    const BigInt& g = group.get_g();
00130    const BigInt& p = group.get_p();
00131 
00132    m_p_bytes = p.bytes();
00133    m_v = v;
00134    m_b = BigInt(rng, 256);
00135    m_p = p;
00136    m_hash_id = hash_id;
00137 
00138    const BigInt k = hash_seq(hash_id, m_p_bytes, p, g);
00139 
00140    m_B = (v*k + power_mod(g, m_b, p)) % p;
00141 
00142    return m_B;
00143    }
00144 
00145 SymmetricKey SRP6_Server_Session::step2(const BigInt& A)
00146    {
00147    if(A <= 0 || A >= m_p)
00148       throw std::runtime_error("Invalid SRP parameter from client");
00149 
00150    const BigInt u = hash_seq(m_hash_id, m_p_bytes, A, m_B);
00151 
00152    const BigInt S = power_mod(A * power_mod(m_v, u, m_p), m_b, m_p);
00153 
00154    return BigInt::encode_1363(S, m_p_bytes);
00155    }
00156 
00157 }