1 /* Copyright (c) 2016, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15 #include <openssl/curve25519.h>
16
17 #include <string>
18
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <string.h>
22
23 #include <gtest/gtest.h>
24
25 #include "../internal.h"
26
27
28 /* TODO(agl): add tests with fixed vectors once SPAKE2 is nailed down. */
29
30 struct SPAKE2Run {
RunSPAKE2Run31 bool Run() {
32 bssl::UniquePtr<SPAKE2_CTX> alice(SPAKE2_CTX_new(
33 spake2_role_alice,
34 reinterpret_cast<const uint8_t *>(alice_names.first.data()),
35 alice_names.first.size(),
36 reinterpret_cast<const uint8_t *>(alice_names.second.data()),
37 alice_names.second.size()));
38 bssl::UniquePtr<SPAKE2_CTX> bob(SPAKE2_CTX_new(
39 spake2_role_bob,
40 reinterpret_cast<const uint8_t *>(bob_names.first.data()),
41 bob_names.first.size(),
42 reinterpret_cast<const uint8_t *>(bob_names.second.data()),
43 bob_names.second.size()));
44
45 if (!alice || !bob) {
46 return false;
47 }
48
49 uint8_t alice_msg[SPAKE2_MAX_MSG_SIZE];
50 uint8_t bob_msg[SPAKE2_MAX_MSG_SIZE];
51 size_t alice_msg_len, bob_msg_len;
52
53 if (!SPAKE2_generate_msg(
54 alice.get(), alice_msg, &alice_msg_len, sizeof(alice_msg),
55 reinterpret_cast<const uint8_t *>(alice_password.data()),
56 alice_password.size()) ||
57 !SPAKE2_generate_msg(
58 bob.get(), bob_msg, &bob_msg_len, sizeof(bob_msg),
59 reinterpret_cast<const uint8_t *>(bob_password.data()),
60 bob_password.size())) {
61 return false;
62 }
63
64 if (alice_corrupt_msg_bit >= 0 &&
65 static_cast<size_t>(alice_corrupt_msg_bit) < 8 * alice_msg_len) {
66 alice_msg[alice_corrupt_msg_bit/8] ^= 1 << (alice_corrupt_msg_bit & 7);
67 }
68
69 uint8_t alice_key[64], bob_key[64];
70 size_t alice_key_len, bob_key_len;
71
72 if (!SPAKE2_process_msg(alice.get(), alice_key, &alice_key_len,
73 sizeof(alice_key), bob_msg, bob_msg_len) ||
74 !SPAKE2_process_msg(bob.get(), bob_key, &bob_key_len, sizeof(bob_key),
75 alice_msg, alice_msg_len)) {
76 return false;
77 }
78
79 key_matches_ = (alice_key_len == bob_key_len &&
80 OPENSSL_memcmp(alice_key, bob_key, alice_key_len) == 0);
81
82 return true;
83 }
84
key_matchesSPAKE2Run85 bool key_matches() const {
86 return key_matches_;
87 }
88
89 std::string alice_password = "password";
90 std::string bob_password = "password";
91 std::pair<std::string, std::string> alice_names = {"alice", "bob"};
92 std::pair<std::string, std::string> bob_names = {"bob", "alice"};
93 int alice_corrupt_msg_bit = -1;
94
95 private:
96 bool key_matches_ = false;
97 };
98
TEST(SPAKE25519Test,SPAKE2)99 TEST(SPAKE25519Test, SPAKE2) {
100 for (unsigned i = 0; i < 20; i++) {
101 SPAKE2Run spake2;
102 ASSERT_TRUE(spake2.Run());
103 EXPECT_TRUE(spake2.key_matches());
104 }
105 }
106
TEST(SPAKE25519Test,WrongPassword)107 TEST(SPAKE25519Test, WrongPassword) {
108 SPAKE2Run spake2;
109 spake2.bob_password = "wrong password";
110 ASSERT_TRUE(spake2.Run());
111 EXPECT_FALSE(spake2.key_matches()) << "Key matched for unequal passwords.";
112 }
113
TEST(SPAKE25519Test,WrongNames)114 TEST(SPAKE25519Test, WrongNames) {
115 SPAKE2Run spake2;
116 spake2.alice_names.second = "charlie";
117 spake2.bob_names.second = "charlie";
118 ASSERT_TRUE(spake2.Run());
119 EXPECT_FALSE(spake2.key_matches()) << "Key matched for unequal names.";
120 }
121
TEST(SPAKE25519Test,CorruptMessages)122 TEST(SPAKE25519Test, CorruptMessages) {
123 for (int i = 0; i < 8 * SPAKE2_MAX_MSG_SIZE; i++) {
124 SPAKE2Run spake2;
125 spake2.alice_corrupt_msg_bit = i;
126 EXPECT_FALSE(spake2.Run() && spake2.key_matches())
127 << "Passed after corrupting Alice's message, bit " << i;
128 }
129 }
130