Home | History | Annotate | Download | only in crypto
      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 
     16 namespace crypto {
     17 
     18 namespace {
     19 
     20 std::string HexEncodeString(const std::string& binary_data) {
     21   return base::HexEncode(binary_data.c_str(), binary_data.size());
     22 }
     23 
     24 bool 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 
     58 const char kPassword[] = "foo";
     59 
     60 }  // namespace
     61 
     62 TEST(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 
     72 TEST(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 
     83 TEST(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 
    119 TEST(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