Skip to content

Commit

Permalink
Simplify SPAKE2 implementation.
Browse files Browse the repository at this point in the history
Currently P224EncryptedKeyExchange uses two pieces of secret: password 
and session-specific key. They are combined and used together as one 
password. It is not really needed and the calling code can do
it when neccessary.

BUG=105214


Review URL: http://codereview.chromium.org/8903001

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@114189 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
sergeyu@chromium.org committed Dec 13, 2011
1 parent 291d774 commit 78df46a
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 61 deletions.
40 changes: 13 additions & 27 deletions crypto/p224_spake.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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_) {
Expand All @@ -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;
Expand Down Expand Up @@ -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
26 changes: 14 additions & 12 deletions crypto/p224_spake.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand Down
29 changes: 7 additions & 22 deletions crypto/p224_spake_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand All @@ -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
Expand Down

0 comments on commit 78df46a

Please sign in to comment.