diff options
-rw-r--r-- | crypto/p224_spake.cc | 40 | ||||
-rw-r--r-- | crypto/p224_spake.h | 26 | ||||
-rw-r--r-- | crypto/p224_spake_unittest.cc | 29 |
3 files changed, 34 insertions, 61 deletions
diff --git a/crypto/p224_spake.cc b/crypto/p224_spake.cc index 3d83e25..ec0c416 100644 --- a/crypto/p224_spake.cc +++ b/crypto/p224_spake.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// This code implements SPAKE2, a varient of EKE: +// This code implements SPAKE2, a variant of EKE: // http://www.di.ens.fr/~pointche/pub.php?reference=AbPo04 #include <crypto/p224_spake.h> @@ -96,9 +96,7 @@ const crypto::p224::Point kN = { namespace crypto { P224EncryptedKeyExchange::P224EncryptedKeyExchange( - PeerType peer_type, - const base::StringPiece& password, - const base::StringPiece& session) + PeerType peer_type, const base::StringPiece& password) : state_(kStateInitial), is_server_(peer_type == kPeerTypeServer) { // x_ is a random scalar. @@ -108,26 +106,9 @@ P224EncryptedKeyExchange::P224EncryptedKeyExchange( p224::Point X; p224::ScalarBaseMult(x_, &X); - // The "password" in the SPAKE2 protocol is - // SHA256(P(password) + P(session)) where P is function that prepends a - // uint32, big-endian length prefix. - uint8 password_length[4], session_length[4]; - password_length[0] = password.size() >> 24; - password_length[1] = password.size() >> 16; - password_length[2] = password.size() >> 8; - password_length[3] = password.size(); - session_length[0] = session.size() >> 24; - session_length[1] = session.size() >> 16; - session_length[2] = session.size() >> 8; - session_length[3] = session.size(); - SHA256HashString(std::string(reinterpret_cast<const char *>(password_length), - sizeof(password_length)) + - password.as_string() + - std::string(reinterpret_cast<const char *>(session_length), - sizeof(session_length)) + - session.as_string(), - pw_, - sizeof(pw_)); + // Calculate |password| hash to get SPAKE password value. + SHA256HashString(std::string(password.data(), password.length()), + pw_, sizeof(pw_)); // The client masks the Diffie-Hellman value, X, by adding M**pw and the // server uses N**pw. @@ -200,7 +181,7 @@ P224EncryptedKeyExchange::Result P224EncryptedKeyExchange::ProcessMessage( p224::ScalarMult(Y, x_, &k); // If everything worked out, then K is the same for both parties. - std::string k_str = k.ToString(); + key_ = k.ToString(); std::string client_masked_dh, server_masked_dh; if (is_server_) { @@ -214,9 +195,9 @@ P224EncryptedKeyExchange::Result P224EncryptedKeyExchange::ProcessMessage( // Now we calculate the hashes that each side will use to prove to the other // that they derived the correct value for K. uint8 client_hash[kSHA256Length], server_hash[kSHA256Length]; - CalculateHash(kPeerTypeClient, client_masked_dh, server_masked_dh, k_str, + CalculateHash(kPeerTypeClient, client_masked_dh, server_masked_dh, key_, client_hash); - CalculateHash(kPeerTypeServer, client_masked_dh, server_masked_dh, k_str, + CalculateHash(kPeerTypeServer, client_masked_dh, server_masked_dh, key_, server_hash); const uint8* my_hash = is_server_ ? server_hash : client_hash; @@ -256,4 +237,9 @@ const std::string& P224EncryptedKeyExchange::error() const { return error_; } +const std::string& P224EncryptedKeyExchange::GetKey() { + DCHECK_EQ(state_, kStateDone); + return key_; +} + } // namespace crypto diff --git a/crypto/p224_spake.h b/crypto/p224_spake.h index 0441efb..01507c9 100644 --- a/crypto/p224_spake.h +++ b/crypto/p224_spake.h @@ -12,12 +12,10 @@ namespace crypto { -// P224EncryptedKeyExchange provides a means to authenticate an -// encrypted transport using a low-entropy, shared secret. -// -// You need a value derived from the master secret of the connection in order -// to bind the authentication to the encrypted channel. It's the |session| -// argument to the constructor and can be of any length. +// P224EncryptedKeyExchange implements SPAKE2, a variant of Encrypted +// Key Exchange. It allows two parties that have a secret common +// password to establish a common secure key by exchanging messages +// over unsecure channel without disclosing the password. // // The password can be low entropy as authenticating with an attacker only // gives the attacker a one-shot password oracle. No other information about @@ -51,13 +49,11 @@ class CRYPTO_EXPORT P224EncryptedKeyExchange { }; // peer_type: the type of the local authentication party. - // password: a, possibly low-entropy, mutually known password. - // session: a value securely derived from the connection's master secret. - // Both parties to the authentication must pass the same value. For the - // case of a TLS connection, see RFC 5705. + // password: secret session password. Both parties to the + // authentication must pass the same value. For the case of a + // TLS connection, see RFC 5705. P224EncryptedKeyExchange(PeerType peer_type, - const base::StringPiece& password, - const base::StringPiece& session); + const base::StringPiece& password); // GetMessage returns a byte string which must be passed to the other party // in the authentication. @@ -71,6 +67,10 @@ class CRYPTO_EXPORT P224EncryptedKeyExchange { // return a human readable error message. const std::string& error() const; + // The key established as result of the key exchange. Must be called + // at then end after ProcessMessage() returns kResultSuccess. + const std::string& GetKey(); + private: // The authentication state machine is very simple and each party proceeds // through each of these states, in order. @@ -106,6 +106,8 @@ class CRYPTO_EXPORT P224EncryptedKeyExchange { // expected_authenticator_ is used to store the hash value expected from the // other party. uint8 expected_authenticator_[kSHA256Length]; + + std::string key_; }; } // namespace crypto diff --git a/crypto/p224_spake_unittest.cc b/crypto/p224_spake_unittest.cc index e45ec82..bcd448c 100644 --- a/crypto/p224_spake_unittest.cc +++ b/crypto/p224_spake_unittest.cc @@ -43,37 +43,24 @@ bool RunExchange(P224EncryptedKeyExchange* client, } static const char kPassword[] = "foo"; -static const char kSession[] = "bar"; TEST(MutualAuth, CorrectAuth) { P224EncryptedKeyExchange client( - P224EncryptedKeyExchange::kPeerTypeClient, - kPassword, kSession); + P224EncryptedKeyExchange::kPeerTypeClient, kPassword); P224EncryptedKeyExchange server( - P224EncryptedKeyExchange::kPeerTypeServer, - kPassword, kSession); + P224EncryptedKeyExchange::kPeerTypeServer, kPassword); EXPECT_TRUE(RunExchange(&client, &server)); + EXPECT_EQ(client.GetKey(), server.GetKey()); } TEST(MutualAuth, IncorrectPassword) { P224EncryptedKeyExchange client( P224EncryptedKeyExchange::kPeerTypeClient, - kPassword, kSession); - P224EncryptedKeyExchange server( - P224EncryptedKeyExchange::kPeerTypeServer, - "wrongpassword", kSession); - - EXPECT_FALSE(RunExchange(&client, &server)); -} - -TEST(MutualAuth, IncorrectSession) { - P224EncryptedKeyExchange client( - P224EncryptedKeyExchange::kPeerTypeClient, - kPassword, kSession); + kPassword); P224EncryptedKeyExchange server( P224EncryptedKeyExchange::kPeerTypeServer, - kPassword, "wrongsession"); + "wrongpassword"); EXPECT_FALSE(RunExchange(&client, &server)); } @@ -83,11 +70,9 @@ TEST(MutualAuth, Fuzz) { for (unsigned i = 0; i < kIterations; i++) { P224EncryptedKeyExchange client( - P224EncryptedKeyExchange::kPeerTypeClient, - kPassword, kSession); + P224EncryptedKeyExchange::kPeerTypeClient, kPassword); P224EncryptedKeyExchange server( - P224EncryptedKeyExchange::kPeerTypeServer, - kPassword, kSession); + P224EncryptedKeyExchange::kPeerTypeServer, kPassword); // We'll only be testing small values of i, but we don't want that to bias // the test coverage. So we disperse the value of i by multiplying by the |