xref: /aosp_15_r20/external/libchrome/crypto/p224_spake.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker // This code implements SPAKE2, a variant of EKE:
6*635a8641SAndroid Build Coastguard Worker //  http://www.di.ens.fr/~pointche/pub.php?reference=AbPo04
7*635a8641SAndroid Build Coastguard Worker 
8*635a8641SAndroid Build Coastguard Worker #include "crypto/p224_spake.h"
9*635a8641SAndroid Build Coastguard Worker 
10*635a8641SAndroid Build Coastguard Worker #include <algorithm>
11*635a8641SAndroid Build Coastguard Worker 
12*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
13*635a8641SAndroid Build Coastguard Worker #include "crypto/p224.h"
14*635a8641SAndroid Build Coastguard Worker #include "crypto/random.h"
15*635a8641SAndroid Build Coastguard Worker #include "crypto/secure_util.h"
16*635a8641SAndroid Build Coastguard Worker 
17*635a8641SAndroid Build Coastguard Worker namespace {
18*635a8641SAndroid Build Coastguard Worker 
19*635a8641SAndroid Build Coastguard Worker // The following two points (M and N in the protocol) are verifiable random
20*635a8641SAndroid Build Coastguard Worker // points on the curve and can be generated with the following code:
21*635a8641SAndroid Build Coastguard Worker 
22*635a8641SAndroid Build Coastguard Worker // #include <stdint.h>
23*635a8641SAndroid Build Coastguard Worker // #include <stdio.h>
24*635a8641SAndroid Build Coastguard Worker // #include <string.h>
25*635a8641SAndroid Build Coastguard Worker //
26*635a8641SAndroid Build Coastguard Worker // #include <openssl/ec.h>
27*635a8641SAndroid Build Coastguard Worker // #include <openssl/obj_mac.h>
28*635a8641SAndroid Build Coastguard Worker // #include <openssl/sha.h>
29*635a8641SAndroid Build Coastguard Worker //
30*635a8641SAndroid Build Coastguard Worker // // Silence a presubmit.
31*635a8641SAndroid Build Coastguard Worker // #define PRINTF printf
32*635a8641SAndroid Build Coastguard Worker //
33*635a8641SAndroid Build Coastguard Worker // static const char kSeed1[] = "P224 point generation seed (M)";
34*635a8641SAndroid Build Coastguard Worker // static const char kSeed2[] = "P224 point generation seed (N)";
35*635a8641SAndroid Build Coastguard Worker //
36*635a8641SAndroid Build Coastguard Worker // void find_seed(const char* seed) {
37*635a8641SAndroid Build Coastguard Worker //   SHA256_CTX sha256;
38*635a8641SAndroid Build Coastguard Worker //   uint8_t digest[SHA256_DIGEST_LENGTH];
39*635a8641SAndroid Build Coastguard Worker //
40*635a8641SAndroid Build Coastguard Worker //   SHA256_Init(&sha256);
41*635a8641SAndroid Build Coastguard Worker //   SHA256_Update(&sha256, seed, strlen(seed));
42*635a8641SAndroid Build Coastguard Worker //   SHA256_Final(digest, &sha256);
43*635a8641SAndroid Build Coastguard Worker //
44*635a8641SAndroid Build Coastguard Worker //   BIGNUM x, y;
45*635a8641SAndroid Build Coastguard Worker //   EC_GROUP* p224 = EC_GROUP_new_by_curve_name(NID_secp224r1);
46*635a8641SAndroid Build Coastguard Worker //   EC_POINT* p = EC_POINT_new(p224);
47*635a8641SAndroid Build Coastguard Worker //
48*635a8641SAndroid Build Coastguard Worker //   for (unsigned i = 0;; i++) {
49*635a8641SAndroid Build Coastguard Worker //     BN_init(&x);
50*635a8641SAndroid Build Coastguard Worker //     BN_bin2bn(digest, 28, &x);
51*635a8641SAndroid Build Coastguard Worker //
52*635a8641SAndroid Build Coastguard Worker //     if (EC_POINT_set_compressed_coordinates_GFp(
53*635a8641SAndroid Build Coastguard Worker //             p224, p, &x, digest[28] & 1, NULL)) {
54*635a8641SAndroid Build Coastguard Worker //       BN_init(&y);
55*635a8641SAndroid Build Coastguard Worker //       EC_POINT_get_affine_coordinates_GFp(p224, p, &x, &y, NULL);
56*635a8641SAndroid Build Coastguard Worker //       char* x_str = BN_bn2hex(&x);
57*635a8641SAndroid Build Coastguard Worker //       char* y_str = BN_bn2hex(&y);
58*635a8641SAndroid Build Coastguard Worker //       PRINTF("Found after %u iterations:\n%s\n%s\n", i, x_str, y_str);
59*635a8641SAndroid Build Coastguard Worker //       OPENSSL_free(x_str);
60*635a8641SAndroid Build Coastguard Worker //       OPENSSL_free(y_str);
61*635a8641SAndroid Build Coastguard Worker //       BN_free(&x);
62*635a8641SAndroid Build Coastguard Worker //       BN_free(&y);
63*635a8641SAndroid Build Coastguard Worker //       break;
64*635a8641SAndroid Build Coastguard Worker //     }
65*635a8641SAndroid Build Coastguard Worker //
66*635a8641SAndroid Build Coastguard Worker //     SHA256_Init(&sha256);
67*635a8641SAndroid Build Coastguard Worker //     SHA256_Update(&sha256, digest, sizeof(digest));
68*635a8641SAndroid Build Coastguard Worker //     SHA256_Final(digest, &sha256);
69*635a8641SAndroid Build Coastguard Worker //
70*635a8641SAndroid Build Coastguard Worker //     BN_free(&x);
71*635a8641SAndroid Build Coastguard Worker //   }
72*635a8641SAndroid Build Coastguard Worker //
73*635a8641SAndroid Build Coastguard Worker //   EC_POINT_free(p);
74*635a8641SAndroid Build Coastguard Worker //   EC_GROUP_free(p224);
75*635a8641SAndroid Build Coastguard Worker // }
76*635a8641SAndroid Build Coastguard Worker //
77*635a8641SAndroid Build Coastguard Worker // int main() {
78*635a8641SAndroid Build Coastguard Worker //   find_seed(kSeed1);
79*635a8641SAndroid Build Coastguard Worker //   find_seed(kSeed2);
80*635a8641SAndroid Build Coastguard Worker //   return 0;
81*635a8641SAndroid Build Coastguard Worker // }
82*635a8641SAndroid Build Coastguard Worker 
83*635a8641SAndroid Build Coastguard Worker const crypto::p224::Point kM = {
84*635a8641SAndroid Build Coastguard Worker   {174237515, 77186811, 235213682, 33849492,
85*635a8641SAndroid Build Coastguard Worker    33188520, 48266885, 177021753, 81038478},
86*635a8641SAndroid Build Coastguard Worker   {104523827, 245682244, 266509668, 236196369,
87*635a8641SAndroid Build Coastguard Worker    28372046, 145351378, 198520366, 113345994},
88*635a8641SAndroid Build Coastguard Worker   {1, 0, 0, 0, 0, 0, 0, 0},
89*635a8641SAndroid Build Coastguard Worker };
90*635a8641SAndroid Build Coastguard Worker 
91*635a8641SAndroid Build Coastguard Worker const crypto::p224::Point kN = {
92*635a8641SAndroid Build Coastguard Worker   {136176322, 263523628, 251628795, 229292285,
93*635a8641SAndroid Build Coastguard Worker    5034302, 185981975, 171998428, 11653062},
94*635a8641SAndroid Build Coastguard Worker   {197567436, 51226044, 60372156, 175772188,
95*635a8641SAndroid Build Coastguard Worker    42075930, 8083165, 160827401, 65097570},
96*635a8641SAndroid Build Coastguard Worker   {1, 0, 0, 0, 0, 0, 0, 0},
97*635a8641SAndroid Build Coastguard Worker };
98*635a8641SAndroid Build Coastguard Worker 
99*635a8641SAndroid Build Coastguard Worker }  // anonymous namespace
100*635a8641SAndroid Build Coastguard Worker 
101*635a8641SAndroid Build Coastguard Worker namespace crypto {
102*635a8641SAndroid Build Coastguard Worker 
P224EncryptedKeyExchange(PeerType peer_type,base::StringPiece password)103*635a8641SAndroid Build Coastguard Worker P224EncryptedKeyExchange::P224EncryptedKeyExchange(PeerType peer_type,
104*635a8641SAndroid Build Coastguard Worker                                                    base::StringPiece password)
105*635a8641SAndroid Build Coastguard Worker     : state_(kStateInitial), is_server_(peer_type == kPeerTypeServer) {
106*635a8641SAndroid Build Coastguard Worker   memset(&x_, 0, sizeof(x_));
107*635a8641SAndroid Build Coastguard Worker   memset(&expected_authenticator_, 0, sizeof(expected_authenticator_));
108*635a8641SAndroid Build Coastguard Worker 
109*635a8641SAndroid Build Coastguard Worker   // x_ is a random scalar.
110*635a8641SAndroid Build Coastguard Worker   RandBytes(x_, sizeof(x_));
111*635a8641SAndroid Build Coastguard Worker 
112*635a8641SAndroid Build Coastguard Worker   // Calculate |password| hash to get SPAKE password value.
113*635a8641SAndroid Build Coastguard Worker   SHA256HashString(std::string(password.data(), password.length()),
114*635a8641SAndroid Build Coastguard Worker                    pw_, sizeof(pw_));
115*635a8641SAndroid Build Coastguard Worker 
116*635a8641SAndroid Build Coastguard Worker   Init();
117*635a8641SAndroid Build Coastguard Worker }
118*635a8641SAndroid Build Coastguard Worker 
Init()119*635a8641SAndroid Build Coastguard Worker void P224EncryptedKeyExchange::Init() {
120*635a8641SAndroid Build Coastguard Worker   // X = g**x_
121*635a8641SAndroid Build Coastguard Worker   p224::Point X;
122*635a8641SAndroid Build Coastguard Worker   p224::ScalarBaseMult(x_, &X);
123*635a8641SAndroid Build Coastguard Worker 
124*635a8641SAndroid Build Coastguard Worker   // The client masks the Diffie-Hellman value, X, by adding M**pw and the
125*635a8641SAndroid Build Coastguard Worker   // server uses N**pw.
126*635a8641SAndroid Build Coastguard Worker   p224::Point MNpw;
127*635a8641SAndroid Build Coastguard Worker   p224::ScalarMult(is_server_ ? kN : kM, pw_, &MNpw);
128*635a8641SAndroid Build Coastguard Worker 
129*635a8641SAndroid Build Coastguard Worker   // X* = X + (N|M)**pw
130*635a8641SAndroid Build Coastguard Worker   p224::Point Xstar;
131*635a8641SAndroid Build Coastguard Worker   p224::Add(X, MNpw, &Xstar);
132*635a8641SAndroid Build Coastguard Worker 
133*635a8641SAndroid Build Coastguard Worker   next_message_ = Xstar.ToString();
134*635a8641SAndroid Build Coastguard Worker }
135*635a8641SAndroid Build Coastguard Worker 
GetNextMessage()136*635a8641SAndroid Build Coastguard Worker const std::string& P224EncryptedKeyExchange::GetNextMessage() {
137*635a8641SAndroid Build Coastguard Worker   if (state_ == kStateInitial) {
138*635a8641SAndroid Build Coastguard Worker     state_ = kStateRecvDH;
139*635a8641SAndroid Build Coastguard Worker     return next_message_;
140*635a8641SAndroid Build Coastguard Worker   } else if (state_ == kStateSendHash) {
141*635a8641SAndroid Build Coastguard Worker     state_ = kStateRecvHash;
142*635a8641SAndroid Build Coastguard Worker     return next_message_;
143*635a8641SAndroid Build Coastguard Worker   }
144*635a8641SAndroid Build Coastguard Worker 
145*635a8641SAndroid Build Coastguard Worker   LOG(FATAL) << "P224EncryptedKeyExchange::GetNextMessage called in"
146*635a8641SAndroid Build Coastguard Worker                 " bad state " << state_;
147*635a8641SAndroid Build Coastguard Worker   next_message_ = "";
148*635a8641SAndroid Build Coastguard Worker   return next_message_;
149*635a8641SAndroid Build Coastguard Worker }
150*635a8641SAndroid Build Coastguard Worker 
ProcessMessage(base::StringPiece message)151*635a8641SAndroid Build Coastguard Worker P224EncryptedKeyExchange::Result P224EncryptedKeyExchange::ProcessMessage(
152*635a8641SAndroid Build Coastguard Worker     base::StringPiece message) {
153*635a8641SAndroid Build Coastguard Worker   if (state_ == kStateRecvHash) {
154*635a8641SAndroid Build Coastguard Worker     // This is the final state of the protocol: we are reading the peer's
155*635a8641SAndroid Build Coastguard Worker     // authentication hash and checking that it matches the one that we expect.
156*635a8641SAndroid Build Coastguard Worker     if (message.size() != sizeof(expected_authenticator_)) {
157*635a8641SAndroid Build Coastguard Worker       error_ = "peer's hash had an incorrect size";
158*635a8641SAndroid Build Coastguard Worker       return kResultFailed;
159*635a8641SAndroid Build Coastguard Worker     }
160*635a8641SAndroid Build Coastguard Worker     if (!SecureMemEqual(message.data(), expected_authenticator_,
161*635a8641SAndroid Build Coastguard Worker                         message.size())) {
162*635a8641SAndroid Build Coastguard Worker       error_ = "peer's hash had incorrect value";
163*635a8641SAndroid Build Coastguard Worker       return kResultFailed;
164*635a8641SAndroid Build Coastguard Worker     }
165*635a8641SAndroid Build Coastguard Worker     state_ = kStateDone;
166*635a8641SAndroid Build Coastguard Worker     return kResultSuccess;
167*635a8641SAndroid Build Coastguard Worker   }
168*635a8641SAndroid Build Coastguard Worker 
169*635a8641SAndroid Build Coastguard Worker   if (state_ != kStateRecvDH) {
170*635a8641SAndroid Build Coastguard Worker     LOG(FATAL) << "P224EncryptedKeyExchange::ProcessMessage called in"
171*635a8641SAndroid Build Coastguard Worker                   " bad state " << state_;
172*635a8641SAndroid Build Coastguard Worker     error_ = "internal error";
173*635a8641SAndroid Build Coastguard Worker     return kResultFailed;
174*635a8641SAndroid Build Coastguard Worker   }
175*635a8641SAndroid Build Coastguard Worker 
176*635a8641SAndroid Build Coastguard Worker   // Y* is the other party's masked, Diffie-Hellman value.
177*635a8641SAndroid Build Coastguard Worker   p224::Point Ystar;
178*635a8641SAndroid Build Coastguard Worker   if (!Ystar.SetFromString(message)) {
179*635a8641SAndroid Build Coastguard Worker     error_ = "failed to parse peer's masked Diffie-Hellman value";
180*635a8641SAndroid Build Coastguard Worker     return kResultFailed;
181*635a8641SAndroid Build Coastguard Worker   }
182*635a8641SAndroid Build Coastguard Worker 
183*635a8641SAndroid Build Coastguard Worker   // We calculate the mask value: (N|M)**pw
184*635a8641SAndroid Build Coastguard Worker   p224::Point MNpw, minus_MNpw, Y, k;
185*635a8641SAndroid Build Coastguard Worker   p224::ScalarMult(is_server_ ? kM : kN, pw_, &MNpw);
186*635a8641SAndroid Build Coastguard Worker   p224::Negate(MNpw, &minus_MNpw);
187*635a8641SAndroid Build Coastguard Worker 
188*635a8641SAndroid Build Coastguard Worker   // Y = Y* - (N|M)**pw
189*635a8641SAndroid Build Coastguard Worker   p224::Add(Ystar, minus_MNpw, &Y);
190*635a8641SAndroid Build Coastguard Worker 
191*635a8641SAndroid Build Coastguard Worker   // K = Y**x_
192*635a8641SAndroid Build Coastguard Worker   p224::ScalarMult(Y, x_, &k);
193*635a8641SAndroid Build Coastguard Worker 
194*635a8641SAndroid Build Coastguard Worker   // If everything worked out, then K is the same for both parties.
195*635a8641SAndroid Build Coastguard Worker   key_ = k.ToString();
196*635a8641SAndroid Build Coastguard Worker 
197*635a8641SAndroid Build Coastguard Worker   std::string client_masked_dh, server_masked_dh;
198*635a8641SAndroid Build Coastguard Worker   if (is_server_) {
199*635a8641SAndroid Build Coastguard Worker     client_masked_dh = message.as_string();
200*635a8641SAndroid Build Coastguard Worker     server_masked_dh = next_message_;
201*635a8641SAndroid Build Coastguard Worker   } else {
202*635a8641SAndroid Build Coastguard Worker     client_masked_dh = next_message_;
203*635a8641SAndroid Build Coastguard Worker     server_masked_dh = message.as_string();
204*635a8641SAndroid Build Coastguard Worker   }
205*635a8641SAndroid Build Coastguard Worker 
206*635a8641SAndroid Build Coastguard Worker   // Now we calculate the hashes that each side will use to prove to the other
207*635a8641SAndroid Build Coastguard Worker   // that they derived the correct value for K.
208*635a8641SAndroid Build Coastguard Worker   uint8_t client_hash[kSHA256Length], server_hash[kSHA256Length];
209*635a8641SAndroid Build Coastguard Worker   CalculateHash(kPeerTypeClient, client_masked_dh, server_masked_dh, key_,
210*635a8641SAndroid Build Coastguard Worker                 client_hash);
211*635a8641SAndroid Build Coastguard Worker   CalculateHash(kPeerTypeServer, client_masked_dh, server_masked_dh, key_,
212*635a8641SAndroid Build Coastguard Worker                 server_hash);
213*635a8641SAndroid Build Coastguard Worker 
214*635a8641SAndroid Build Coastguard Worker   const uint8_t* my_hash = is_server_ ? server_hash : client_hash;
215*635a8641SAndroid Build Coastguard Worker   const uint8_t* their_hash = is_server_ ? client_hash : server_hash;
216*635a8641SAndroid Build Coastguard Worker 
217*635a8641SAndroid Build Coastguard Worker   next_message_ =
218*635a8641SAndroid Build Coastguard Worker       std::string(reinterpret_cast<const char*>(my_hash), kSHA256Length);
219*635a8641SAndroid Build Coastguard Worker   memcpy(expected_authenticator_, their_hash, kSHA256Length);
220*635a8641SAndroid Build Coastguard Worker   state_ = kStateSendHash;
221*635a8641SAndroid Build Coastguard Worker   return kResultPending;
222*635a8641SAndroid Build Coastguard Worker }
223*635a8641SAndroid Build Coastguard Worker 
CalculateHash(PeerType peer_type,const std::string & client_masked_dh,const std::string & server_masked_dh,const std::string & k,uint8_t * out_digest)224*635a8641SAndroid Build Coastguard Worker void P224EncryptedKeyExchange::CalculateHash(
225*635a8641SAndroid Build Coastguard Worker     PeerType peer_type,
226*635a8641SAndroid Build Coastguard Worker     const std::string& client_masked_dh,
227*635a8641SAndroid Build Coastguard Worker     const std::string& server_masked_dh,
228*635a8641SAndroid Build Coastguard Worker     const std::string& k,
229*635a8641SAndroid Build Coastguard Worker     uint8_t* out_digest) {
230*635a8641SAndroid Build Coastguard Worker   std::string hash_contents;
231*635a8641SAndroid Build Coastguard Worker 
232*635a8641SAndroid Build Coastguard Worker   if (peer_type == kPeerTypeServer) {
233*635a8641SAndroid Build Coastguard Worker     hash_contents = "server";
234*635a8641SAndroid Build Coastguard Worker   } else {
235*635a8641SAndroid Build Coastguard Worker     hash_contents = "client";
236*635a8641SAndroid Build Coastguard Worker   }
237*635a8641SAndroid Build Coastguard Worker 
238*635a8641SAndroid Build Coastguard Worker   hash_contents += client_masked_dh;
239*635a8641SAndroid Build Coastguard Worker   hash_contents += server_masked_dh;
240*635a8641SAndroid Build Coastguard Worker   hash_contents +=
241*635a8641SAndroid Build Coastguard Worker       std::string(reinterpret_cast<const char *>(pw_), sizeof(pw_));
242*635a8641SAndroid Build Coastguard Worker   hash_contents += k;
243*635a8641SAndroid Build Coastguard Worker 
244*635a8641SAndroid Build Coastguard Worker   SHA256HashString(hash_contents, out_digest, kSHA256Length);
245*635a8641SAndroid Build Coastguard Worker }
246*635a8641SAndroid Build Coastguard Worker 
error() const247*635a8641SAndroid Build Coastguard Worker const std::string& P224EncryptedKeyExchange::error() const {
248*635a8641SAndroid Build Coastguard Worker   return error_;
249*635a8641SAndroid Build Coastguard Worker }
250*635a8641SAndroid Build Coastguard Worker 
GetKey() const251*635a8641SAndroid Build Coastguard Worker const std::string& P224EncryptedKeyExchange::GetKey() const {
252*635a8641SAndroid Build Coastguard Worker   DCHECK_EQ(state_, kStateDone);
253*635a8641SAndroid Build Coastguard Worker   return GetUnverifiedKey();
254*635a8641SAndroid Build Coastguard Worker }
255*635a8641SAndroid Build Coastguard Worker 
GetUnverifiedKey() const256*635a8641SAndroid Build Coastguard Worker const std::string& P224EncryptedKeyExchange::GetUnverifiedKey() const {
257*635a8641SAndroid Build Coastguard Worker   // Key is already final when state is kStateSendHash. Subsequent states are
258*635a8641SAndroid Build Coastguard Worker   // used only for verification of the key. Some users may combine verification
259*635a8641SAndroid Build Coastguard Worker   // with sending verifiable data instead of |expected_authenticator_|.
260*635a8641SAndroid Build Coastguard Worker   DCHECK_GE(state_, kStateSendHash);
261*635a8641SAndroid Build Coastguard Worker   return key_;
262*635a8641SAndroid Build Coastguard Worker }
263*635a8641SAndroid Build Coastguard Worker 
SetXForTesting(const std::string & x)264*635a8641SAndroid Build Coastguard Worker void P224EncryptedKeyExchange::SetXForTesting(const std::string& x) {
265*635a8641SAndroid Build Coastguard Worker   memset(&x_, 0, sizeof(x_));
266*635a8641SAndroid Build Coastguard Worker   memcpy(&x_, x.data(), std::min(x.size(), sizeof(x_)));
267*635a8641SAndroid Build Coastguard Worker   Init();
268*635a8641SAndroid Build Coastguard Worker }
269*635a8641SAndroid Build Coastguard Worker 
270*635a8641SAndroid Build Coastguard Worker }  // namespace crypto
271