| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CRYPTO_P224_SPAKE_H_ |
| #define CRYPTO_P224_SPAKE_H_ |
| |
| #include <stdint.h> |
| |
| #include <string> |
| |
| #include "base/gtest_prod_util.h" |
| #include "base/strings/string_piece.h" |
| #include "crypto/sha2.h" |
| |
| namespace crypto { |
| |
| // 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 an insecure 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 |
| // the password is leaked. (However, you must be sure to limit the number of |
| // permitted authentication attempts otherwise they get many one-shot oracles.) |
| // |
| // The protocol requires several RTTs (actually two, but you shouldn't assume |
| // that.) To use the object, call GetNextMessage() and pass that message to the |
| // peer. Get a message from the peer and feed it into ProcessMessage. Then |
| // examine the return value of ProcessMessage: |
| // kResultPending: Another round is required. Call GetNextMessage and repeat. |
| // kResultFailed: The authentication has failed. You can get a human readable |
| // error message by calling error(). |
| // kResultSuccess: The authentication was successful. |
| // |
| // In each exchange, each peer always sends a message. |
| class CRYPTO_EXPORT P224EncryptedKeyExchange { |
| public: |
| enum Result { |
| kResultPending, |
| kResultFailed, |
| kResultSuccess, |
| }; |
| |
| // PeerType's values are named client and server due to convention. But |
| // they could be called "A" and "B" as far as the protocol is concerned so |
| // long as the two parties don't both get the same label. |
| enum PeerType { |
| kPeerTypeClient, |
| kPeerTypeServer, |
| }; |
| |
| // peer_type: the type of the local authentication party. |
| // 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, base::StringPiece password); |
| |
| // GetNextMessage returns a byte string which must be passed to the other |
| // party in the authentication. |
| const std::string& GetNextMessage(); |
| |
| // ProcessMessage processes a message which must have been generated by a |
| // call to GetNextMessage() by the other party. |
| Result ProcessMessage(base::StringPiece message); |
| |
| // In the event that ProcessMessage() returns kResultFailed, error will |
| // 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() const; |
| |
| // The key established as result of the key exchange. Can be called after |
| // the first ProcessMessage() |
| const std::string& GetUnverifiedKey() const; |
| |
| private: |
| // The authentication state machine is very simple and each party proceeds |
| // through each of these states, in order. |
| enum State { |
| kStateInitial, |
| kStateRecvDH, |
| kStateSendHash, |
| kStateRecvHash, |
| kStateDone, |
| }; |
| |
| FRIEND_TEST_ALL_PREFIXES(MutualAuth, ExpectedValues); |
| |
| void Init(); |
| |
| // Sets internal random scalar. Should be used by tests only. |
| void SetXForTesting(const std::string& x); |
| |
| State state_; |
| const bool is_server_; |
| // next_message_ contains a value for GetNextMessage() to return. |
| std::string next_message_; |
| std::string error_; |
| |
| // CalculateHash computes the verification hash for the given peer and writes |
| // |kSHA256Length| bytes at |out_digest|. |
| void CalculateHash(PeerType peer_type, |
| const std::string& client_masked_dh, |
| const std::string& server_masked_dh, |
| const std::string& k, |
| uint8_t* out_digest); |
| |
| // kScalarBytes is the number of bytes in a P-224 scalar. |
| static constexpr size_t kScalarBytes = 28; |
| // x_ is the secret Diffie-Hellman exponent (see paper referenced in .cc |
| // file). |
| uint8_t x_[kScalarBytes]; |
| // pw_ is SHA256(P(password), P(session))[:28] where P() prepends a uint32_t, |
| // big-endian length prefix (see paper referenced in .cc file). |
| uint8_t pw_[kScalarBytes]; |
| // expected_authenticator_ is used to store the hash value expected from the |
| // other party. |
| uint8_t expected_authenticator_[kSHA256Length]; |
| |
| std::string key_; |
| }; |
| |
| } // namespace crypto |
| |
| #endif // CRYPTO_P224_SPAKE_H_ |