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