• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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