• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "crypto/p224_spake.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <string>
11 
12 #include "base/strings/string_number_conversions.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 
15 namespace crypto {
16 
17 namespace {
18 
HexEncodeString(const std::string & binary_data)19 std::string HexEncodeString(const std::string& binary_data) {
20   return base::HexEncode(binary_data.c_str(), binary_data.size());
21 }
22 
RunExchange(P224EncryptedKeyExchange * client,P224EncryptedKeyExchange * server,bool is_password_same)23 bool RunExchange(P224EncryptedKeyExchange* client,
24                  P224EncryptedKeyExchange* server,
25                  bool is_password_same) {
26   for (;;) {
27     std::string client_message, server_message;
28     client_message = client->GetNextMessage();
29     server_message = server->GetNextMessage();
30 
31     P224EncryptedKeyExchange::Result client_result, server_result;
32     client_result = client->ProcessMessage(server_message);
33     server_result = server->ProcessMessage(client_message);
34 
35     // Check that we never hit the case where only one succeeds.
36     EXPECT_EQ(client_result == P224EncryptedKeyExchange::kResultSuccess,
37               server_result == P224EncryptedKeyExchange::kResultSuccess);
38 
39     if (client_result == P224EncryptedKeyExchange::kResultFailed ||
40         server_result == P224EncryptedKeyExchange::kResultFailed) {
41       return false;
42     }
43 
44     EXPECT_EQ(is_password_same,
45               client->GetUnverifiedKey() == server->GetUnverifiedKey());
46 
47     if (client_result == P224EncryptedKeyExchange::kResultSuccess &&
48         server_result == P224EncryptedKeyExchange::kResultSuccess) {
49       return true;
50     }
51 
52     EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, client_result);
53     EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, server_result);
54   }
55 }
56 
57 const char kPassword[] = "foo";
58 
59 }  // namespace
60 
TEST(MutualAuth,CorrectAuth)61 TEST(MutualAuth, CorrectAuth) {
62   P224EncryptedKeyExchange client(
63       P224EncryptedKeyExchange::kPeerTypeClient, kPassword);
64   P224EncryptedKeyExchange server(
65       P224EncryptedKeyExchange::kPeerTypeServer, kPassword);
66 
67   EXPECT_TRUE(RunExchange(&client, &server, true));
68   EXPECT_EQ(client.GetKey(), server.GetKey());
69 }
70 
TEST(MutualAuth,IncorrectPassword)71 TEST(MutualAuth, IncorrectPassword) {
72   P224EncryptedKeyExchange client(
73       P224EncryptedKeyExchange::kPeerTypeClient,
74       kPassword);
75   P224EncryptedKeyExchange server(
76       P224EncryptedKeyExchange::kPeerTypeServer,
77       "wrongpassword");
78 
79   EXPECT_FALSE(RunExchange(&client, &server, false));
80 }
81 
TEST(MutualAuth,ExpectedValues)82 TEST(MutualAuth, ExpectedValues) {
83   P224EncryptedKeyExchange client(P224EncryptedKeyExchange::kPeerTypeClient,
84                                   kPassword);
85   client.SetXForTesting("Client x");
86   P224EncryptedKeyExchange server(P224EncryptedKeyExchange::kPeerTypeServer,
87                                   kPassword);
88   server.SetXForTesting("Server x");
89 
90   std::string client_message = client.GetNextMessage();
91   EXPECT_EQ(
92       "3508EF7DECC8AB9F9C439FBB0154288BBECC0A82E8448F4CF29554EB"
93       "BE9D486686226255EAD1D077C635B1A41F46AC91D7F7F32CED9EC3E0",
94       HexEncodeString(client_message));
95 
96   std::string server_message = server.GetNextMessage();
97   EXPECT_EQ(
98       "A3088C18B75D2C2B107105661AEC85424777475EB29F1DDFB8C14AFB"
99       "F1603D0DF38413A00F420ACF2059E7997C935F5A957A193D09A2B584",
100       HexEncodeString(server_message));
101 
102   EXPECT_EQ(P224EncryptedKeyExchange::kResultPending,
103             client.ProcessMessage(server_message));
104   EXPECT_EQ(P224EncryptedKeyExchange::kResultPending,
105             server.ProcessMessage(client_message));
106 
107   EXPECT_EQ(client.GetUnverifiedKey(), server.GetUnverifiedKey());
108   // Must stay the same. External implementations should be able to pair with.
109   EXPECT_EQ(
110       "CE7CCFC435CDA4F01EC8826788B1F8B82EF7D550A34696B371096E64"
111       "C487D4FE193F7D1A6FF6820BC7F807796BA3889E8F999BBDEFC32FFA",
112       HexEncodeString(server.GetUnverifiedKey()));
113 
114   EXPECT_TRUE(RunExchange(&client, &server, true));
115   EXPECT_EQ(client.GetKey(), server.GetKey());
116 }
117 
TEST(MutualAuth,Fuzz)118 TEST(MutualAuth, Fuzz) {
119   static const unsigned kIterations = 40;
120 
121   for (unsigned i = 0; i < kIterations; i++) {
122     P224EncryptedKeyExchange client(
123         P224EncryptedKeyExchange::kPeerTypeClient, kPassword);
124     P224EncryptedKeyExchange server(
125         P224EncryptedKeyExchange::kPeerTypeServer, kPassword);
126 
127     // We'll only be testing small values of i, but we don't want that to bias
128     // the test coverage. So we disperse the value of i by multiplying by the
129     // FNV, 32-bit prime, producing a simplistic PRNG.
130     const uint32_t rand = i * 16777619;
131 
132     for (unsigned round = 0;; round++) {
133       std::string client_message, server_message;
134       client_message = client.GetNextMessage();
135       server_message = server.GetNextMessage();
136 
137       if ((rand & 1) == round) {
138         const bool server_or_client = rand & 2;
139         std::string* m = server_or_client ? &server_message : &client_message;
140         if (rand & 4) {
141           // Truncate
142           *m = m->substr(0, (i >> 3) % m->size());
143         } else {
144           // Corrupt
145           const size_t bits = m->size() * 8;
146           const size_t bit_to_corrupt = (rand >> 3) % bits;
147           const_cast<char*>(m->data())[bit_to_corrupt / 8] ^=
148               1 << (bit_to_corrupt % 8);
149         }
150       }
151 
152       P224EncryptedKeyExchange::Result client_result, server_result;
153       client_result = client.ProcessMessage(server_message);
154       server_result = server.ProcessMessage(client_message);
155 
156       // If we have corrupted anything, we expect the authentication to fail,
157       // although one side can succeed if we happen to corrupt the second round
158       // message to the other.
159       ASSERT_FALSE(
160           client_result == P224EncryptedKeyExchange::kResultSuccess &&
161           server_result == P224EncryptedKeyExchange::kResultSuccess);
162 
163       if (client_result == P224EncryptedKeyExchange::kResultFailed ||
164           server_result == P224EncryptedKeyExchange::kResultFailed) {
165         break;
166       }
167 
168       ASSERT_EQ(P224EncryptedKeyExchange::kResultPending,
169                 client_result);
170       ASSERT_EQ(P224EncryptedKeyExchange::kResultPending,
171                 server_result);
172     }
173   }
174 }
175 
176 }  // namespace crypto
177