1 /* Copyright 2024 The BoringSSL Authors 2 * 3 * Permission to use, copy, modify, and/or distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14 15 #ifndef OPENSSL_HEADER_SPAKE2PLUS_INTERNAL_H 16 #define OPENSSL_HEADER_SPAKE2PLUS_INTERNAL_H 17 18 #include <openssl/base.h> 19 20 #include <sys/types.h> 21 22 #include <openssl/sha.h> 23 #include <openssl/span.h> 24 25 #include "../fipsmodule/ec/internal.h" 26 27 28 BSSL_NAMESPACE_BEGIN 29 30 // SPAKE2+. 31 // 32 // SPAKE2+ is an augmented password-authenticated key-exchange. It allows 33 // two parties, a prover and verifier, to derive a strong shared key with no 34 // risk of disclosing the password, known only to the prover, to the verifier. 35 // (But note that the verifier can still attempt an offline, brute-force attack 36 // to recover the password.) 37 // 38 // This is an implementation of SPAKE2+ using P-256 as the group, SHA-256 as 39 // the hash function, HKDF-SHA256 as the key derivation function, and 40 // HMAC-SHA256 as the message authentication code. 41 // 42 // See https://www.rfc-editor.org/rfc/rfc9383.html 43 44 namespace spake2plus { 45 46 // kShareSize is the size of a SPAKE2+ key share. 47 constexpr size_t kShareSize = 65; 48 49 // kConfirmSize is the size of a SPAKE2+ key confirmation message. 50 constexpr size_t kConfirmSize = 32; 51 52 // kVerifierSize is the size of the w0 and w1 values in the SPAKE2+ protocol. 53 constexpr size_t kVerifierSize = 32; 54 55 // kRegistrationRecordSize is the number of bytes in a registration record, 56 // which is provided to the verifier. 57 constexpr size_t kRegistrationRecordSize = 65; 58 59 // kSecretSize is the number of bytes of shared secret that the SPAKE2+ protocol 60 // generates. 61 constexpr size_t kSecretSize = 32; 62 63 // Register computes the values needed in the offline registration 64 // step of the SPAKE2+ protocol. See the following for more details: 65 // https://www.rfc-editor.org/rfc/rfc9383.html#section-3.2 66 // 67 // The |password| argument is the mandatory prover password. The |out_w0|, 68 // |out_w1|, and |out_registration_record| arguments are where the password 69 // verifiers (w0 and w1) and registration record (L) are stored, respectively. 70 // The prover is given |out_w0| and |out_w1| while the verifier is given 71 // |out_w0| and |out_registration_record|. 72 // 73 // To ensure success, |out_w0| and |out_w1| must be of length |kVerifierSize|, 74 // and |out_registration_record| of size |kRegistrationRecordSize|. 75 [[nodiscard]] OPENSSL_EXPORT bool Register( 76 Span<uint8_t> out_w0, Span<uint8_t> out_w1, 77 Span<uint8_t> out_registration_record, Span<const uint8_t> password, 78 Span<const uint8_t> id_prover, Span<const uint8_t> id_verifier); 79 80 class OPENSSL_EXPORT Prover { 81 public: 82 static constexpr bool kAllowUniquePtr = true; 83 84 Prover(); 85 ~Prover(); 86 87 // Init creates a new prover, which can only be used for a single execution of 88 // the protocol. 89 // 90 // The |context| argument is an application-specific value meant to constrain 91 // the protocol execution. The |w0| and |w1| arguments are password verifier 92 // values computed during the offline registration phase of the protocol. The 93 // |id_prover| and |id_verifier| arguments allow optional, opaque names to be 94 // bound into the protocol. See the following for more information about how 95 // these identities may be chosen: 96 // https://www.rfc-editor.org/rfc/rfc9383.html#name-definition-of-spake2 97 [[nodiscard]] bool Init(Span<const uint8_t> context, 98 Span<const uint8_t> id_prover, 99 Span<const uint8_t> id_verifier, 100 Span<const uint8_t> w0, Span<const uint8_t> w1, 101 Span<const uint8_t> x = Span<const uint8_t>()); 102 103 // GenerateShare computes a SPAKE2+ share and writes it to |out_share|. 104 // 105 // This function can only be called once for a given |Prover|. To ensure 106 // success, |out_share| must be |kShareSize| bytes. 107 [[nodiscard]] bool GenerateShare(Span<uint8_t> out_share); 108 109 // ComputeConfirmation computes a SPAKE2+ key confirmation 110 // message and writes it to |out_confirm|. It also computes the shared secret 111 // and writes it to |out_secret|. 112 // 113 // This function can only be called once for a given |Prover|. 114 // 115 // To ensure success, |out_confirm| must be |kConfirmSize| bytes 116 // and |out_secret| must be |kSecretSize| bytes. 117 [[nodiscard]] bool ComputeConfirmation(Span<uint8_t> out_confirm, 118 Span<uint8_t> out_secret, 119 Span<const uint8_t> peer_share, 120 Span<const uint8_t> peer_confirm); 121 122 private: 123 enum class State { 124 kInit, 125 kShareGenerated, 126 kConfirmGenerated, 127 kDone, 128 }; 129 130 State state_ = State::kInit; 131 SHA256_CTX transcript_hash_; 132 EC_SCALAR w0_; 133 EC_SCALAR w1_; 134 EC_SCALAR x_; 135 EC_AFFINE X_; 136 uint8_t share_[kShareSize]; 137 }; 138 139 class OPENSSL_EXPORT Verifier { 140 public: 141 static constexpr bool kAllowUniquePtr = true; 142 143 Verifier(); 144 ~Verifier(); 145 146 // Init creates a new verifier, which can only be used for a single execution 147 // of the protocol. 148 // 149 // The |context| argument is an application-specific value meant to constrain 150 // the protocol execution. The |w0| and |registration_record| arguments are 151 // required, and are computed by the prover via |Register|. Only the prover 152 // can produce |w0| and |registration_record|, as they require 153 // knowledge of the password. The prover must securely transmit this to the 154 // verifier out-of-band. The |id_prover| and |id_verifier| arguments allow 155 // optional, opaque names to be bound into the protocol. See the following for 156 // more information about how these identities may be chosen: 157 // https://www.rfc-editor.org/rfc/rfc9383.html#name-definition-of-spake2 158 [[nodiscard]] bool Init(Span<const uint8_t> context, 159 Span<const uint8_t> id_prover, 160 Span<const uint8_t> id_verifier, 161 Span<const uint8_t> w0, 162 Span<const uint8_t> registration_record, 163 Span<const uint8_t> y = Span<const uint8_t>()); 164 165 // ProcessProverShare computes a SPAKE2+ share from an input share, 166 // |prover_share|, and writes it to |out_share|. It also computes the key 167 // confirmation message and writes it to |out_confirm|. Finally, it computes 168 // the shared secret and writes it to |out_secret|. 169 // 170 // This function can only be called once for a given |Verifier|. 171 // 172 // To ensure success, |out_share| must be |kShareSize| bytes, |out_confirm| 173 // must be |kConfirmSize| bytes, and |out_secret| must be |kSecretSize| bytes. 174 [[nodiscard]] bool ProcessProverShare(Span<uint8_t> out_share, 175 Span<uint8_t> out_confirm, 176 Span<uint8_t> out_secret, 177 Span<const uint8_t> prover_share); 178 179 // VerifyProverConfirmation verifies a SPAKE2+ key confirmation message, 180 // |prover_confirm|. 181 // 182 // This function can only be called once for a given |Verifier|. 183 [[nodiscard]] bool VerifyProverConfirmation(Span<const uint8_t> peer_confirm); 184 185 private: 186 enum class State { 187 kInit, 188 kProverShareSeen, 189 kDone, 190 }; 191 192 State state_ = State::kInit; 193 SHA256_CTX transcript_hash_; 194 EC_SCALAR w0_; 195 EC_AFFINE L_; 196 EC_SCALAR y_; 197 uint8_t confirm_[kConfirmSize]; 198 }; 199 200 } // namespace spake2plus 201 202 BSSL_NAMESPACE_END 203 204 #endif // OPENSSL_HEADER_SPAKE2PLUS_INTERNAL_H 205