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 <string>
      6 #include <crypto/p224_spake.h>
      7 
      8 #include "base/logging.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 
     11 namespace crypto {
     12 
     13 namespace {
     14 
     15 bool RunExchange(P224EncryptedKeyExchange* client,
     16                  P224EncryptedKeyExchange* server) {
     17   for (;;) {
     18     std::string client_message, server_message;
     19     client_message = client->GetMessage();
     20     server_message = server->GetMessage();
     21 
     22     P224EncryptedKeyExchange::Result client_result, server_result;
     23     client_result = client->ProcessMessage(server_message);
     24     server_result = server->ProcessMessage(client_message);
     25 
     26     // Check that we never hit the case where only one succeeds.
     27     if ((client_result == P224EncryptedKeyExchange::kResultSuccess) ^
     28         (server_result == P224EncryptedKeyExchange::kResultSuccess)) {
     29       CHECK(false) << "Parties differ on whether authentication was successful";
     30     }
     31 
     32     if (client_result == P224EncryptedKeyExchange::kResultFailed ||
     33         server_result == P224EncryptedKeyExchange::kResultFailed) {
     34       return false;
     35     }
     36 
     37     if (client_result == P224EncryptedKeyExchange::kResultSuccess &&
     38         server_result == P224EncryptedKeyExchange::kResultSuccess) {
     39       return true;
     40     }
     41 
     42     CHECK_EQ(P224EncryptedKeyExchange::kResultPending, client_result);
     43     CHECK_EQ(P224EncryptedKeyExchange::kResultPending, server_result);
     44   }
     45 }
     46 
     47 const char kPassword[] = "foo";
     48 
     49 }  // namespace
     50 
     51 TEST(MutualAuth, CorrectAuth) {
     52   P224EncryptedKeyExchange client(
     53       P224EncryptedKeyExchange::kPeerTypeClient, kPassword);
     54   P224EncryptedKeyExchange server(
     55       P224EncryptedKeyExchange::kPeerTypeServer, kPassword);
     56 
     57   EXPECT_TRUE(RunExchange(&client, &server));
     58   EXPECT_EQ(client.GetKey(), server.GetKey());
     59 }
     60 
     61 TEST(MutualAuth, IncorrectPassword) {
     62   P224EncryptedKeyExchange client(
     63       P224EncryptedKeyExchange::kPeerTypeClient,
     64       kPassword);
     65   P224EncryptedKeyExchange server(
     66       P224EncryptedKeyExchange::kPeerTypeServer,
     67       "wrongpassword");
     68 
     69   EXPECT_FALSE(RunExchange(&client, &server));
     70 }
     71 
     72 TEST(MutualAuth, Fuzz) {
     73   static const unsigned kIterations = 40;
     74 
     75   for (unsigned i = 0; i < kIterations; i++) {
     76     P224EncryptedKeyExchange client(
     77         P224EncryptedKeyExchange::kPeerTypeClient, kPassword);
     78     P224EncryptedKeyExchange server(
     79         P224EncryptedKeyExchange::kPeerTypeServer, kPassword);
     80 
     81     // We'll only be testing small values of i, but we don't want that to bias
     82     // the test coverage. So we disperse the value of i by multiplying by the
     83     // FNV, 32-bit prime, producing a poor-man's PRNG.
     84     const uint32 rand = i * 16777619;
     85 
     86     for (unsigned round = 0;; round++) {
     87       std::string client_message, server_message;
     88       client_message = client.GetMessage();
     89       server_message = server.GetMessage();
     90 
     91       if ((rand & 1) == round) {
     92         const bool server_or_client = rand & 2;
     93         std::string* m = server_or_client ? &server_message : &client_message;
     94         if (rand & 4) {
     95           // Truncate
     96           *m = m->substr(0, (i >> 3) % m->size());
     97         } else {
     98           // Corrupt
     99           const size_t bits = m->size() * 8;
    100           const size_t bit_to_corrupt = (rand >> 3) % bits;
    101           const_cast<char*>(m->data())[bit_to_corrupt / 8] ^=
    102               1 << (bit_to_corrupt % 8);
    103         }
    104       }
    105 
    106       P224EncryptedKeyExchange::Result client_result, server_result;
    107       client_result = client.ProcessMessage(server_message);
    108       server_result = server.ProcessMessage(client_message);
    109 
    110       // If we have corrupted anything, we expect the authentication to fail,
    111       // although one side can succeed if we happen to corrupt the second round
    112       // message to the other.
    113       ASSERT_FALSE(
    114           client_result == P224EncryptedKeyExchange::kResultSuccess &&
    115           server_result == P224EncryptedKeyExchange::kResultSuccess);
    116 
    117       if (client_result == P224EncryptedKeyExchange::kResultFailed ||
    118           server_result == P224EncryptedKeyExchange::kResultFailed) {
    119         break;
    120       }
    121 
    122       ASSERT_EQ(P224EncryptedKeyExchange::kResultPending,
    123                 client_result);
    124       ASSERT_EQ(P224EncryptedKeyExchange::kResultPending,
    125                 server_result);
    126     }
    127   }
    128 }
    129 
    130 }  // namespace crypto
    131