1 /* Copyright (c) 2015, 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 <stdint.h>
16 #include <stdio.h>
17 #include <string.h>
18
19 #include <gtest/gtest.h>
20
21 #include <openssl/curve25519.h>
22
23 #include "internal.h"
24 #include "../internal.h"
25 #include "../test/abi_test.h"
26 #include "../test/file_test.h"
27 #include "../test/test_util.h"
28 #include "../test/wycheproof_util.h"
29 #include "internal.h"
30
ctwrapX25519(uint8_t out_shared_key[32],const uint8_t private_key[32],const uint8_t peer_public_value[32])31 static inline int ctwrapX25519(uint8_t out_shared_key[32],
32 const uint8_t private_key[32],
33 const uint8_t peer_public_value[32]) {
34 uint8_t scalar[32], point[32];
35 // Copy all the secrets into a temporary buffer, so we can run constant-time
36 // validation on them.
37 OPENSSL_memcpy(scalar, private_key, sizeof(scalar));
38 OPENSSL_memcpy(point, peer_public_value, sizeof(point));
39
40 // X25519 should not leak the private key.
41 CONSTTIME_SECRET(scalar, sizeof(scalar));
42 // All other inputs are also marked as secret. This is not to support any
43 // particular use case for calling X25519 with a secret *point*, but
44 // rather to ensure that the choice of the point cannot influence whether
45 // the scalar is leaked or not. Same for the initial contents of the
46 // output buffer. This conservative choice may be revised in the future.
47 CONSTTIME_SECRET(point, sizeof(point));
48 CONSTTIME_SECRET(out_shared_key, 32);
49 int r = X25519(out_shared_key, scalar, point);
50 CONSTTIME_DECLASSIFY(out_shared_key, 32);
51 return r;
52 }
53
TEST(X25519Test,TestVector)54 TEST(X25519Test, TestVector) {
55 // Taken from https://www.rfc-editor.org/rfc/rfc7748#section-5.2
56 static const uint8_t kScalar1[32] = {
57 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15,
58 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc,
59 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4,
60 };
61 static const uint8_t kPoint1[32] = {
62 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1,
63 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3,
64 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c,
65 };
66
67 uint8_t out[32], secret[32];
68 EXPECT_TRUE(ctwrapX25519(out, kScalar1, kPoint1));
69 static const uint8_t kExpected1[32] = {
70 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea,
71 0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c,
72 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52,
73 };
74 EXPECT_EQ(Bytes(kExpected1), Bytes(out));
75
76 static const uint8_t kScalar2[32] = {
77 0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, 0x5a, 0xd2, 0x26,
78 0x91, 0x95, 0x7d, 0x6a, 0xf5, 0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea,
79 0x01, 0xd4, 0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, 0xba, 0x0d,
80 };
81 static const uint8_t kPoint2[32] = {
82 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, 0xf4, 0xb7, 0x95,
83 0x9d, 0x05, 0x38, 0xae, 0x2c, 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0,
84 0x3c, 0x3e, 0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, 0xa4, 0x93,
85 };
86 EXPECT_TRUE(ctwrapX25519(out, kScalar2, kPoint2));
87 static const uint8_t kExpected2[32] = {
88 0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, 0x7a, 0xad, 0xe4,
89 0x5c, 0xb4, 0xb8, 0x73, 0xf8, 0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f,
90 0xa1, 0x52, 0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac, 0x79, 0x57,
91 };
92 EXPECT_EQ(Bytes(kExpected2), Bytes(out));
93
94 // Taken from https://www.rfc-editor.org/rfc/rfc7748.html#section-6.1
95 static const uint8_t kPrivateA[32] = {
96 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1,
97 0x72, 0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0,
98 0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a,
99 };
100 static const uint8_t kPublicA[32] = {
101 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d,
102 0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38,
103 0x1a, 0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a,
104 };
105 static const uint8_t kPrivateB[32] = {
106 0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b, 0x79, 0xe1, 0x7f,
107 0x8b, 0x83, 0x80, 0x0e, 0xe6, 0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18,
108 0xb6, 0xfd, 0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb,
109 };
110 static const uint8_t kPublicB[32] = {
111 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b, 0x61,
112 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78,
113 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f,
114 };
115 static const uint8_t kSecret[32] = {
116 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, 0x72, 0x8e, 0x3b,
117 0xf4, 0x80, 0x35, 0x0f, 0x25, 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1,
118 0x9e, 0x33, 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42,
119 };
120
121 OPENSSL_memcpy(secret, kPrivateA, sizeof(secret));
122 CONSTTIME_SECRET(secret, sizeof(secret));
123 X25519_public_from_private(out, secret);
124 CONSTTIME_DECLASSIFY(out, sizeof(out));
125 EXPECT_EQ(Bytes(out), Bytes(kPublicA));
126
127 OPENSSL_memcpy(secret, kPrivateB, sizeof(secret));
128 CONSTTIME_SECRET(secret, sizeof(secret));
129 X25519_public_from_private(out, secret);
130 CONSTTIME_DECLASSIFY(out, sizeof(out));
131 EXPECT_EQ(Bytes(out), Bytes(kPublicB));
132
133 ctwrapX25519(out, kPrivateA, kPublicB);
134 EXPECT_EQ(Bytes(out), Bytes(kSecret));
135
136 ctwrapX25519(out, kPrivateB, kPublicA);
137 EXPECT_EQ(Bytes(out), Bytes(kSecret));
138 }
139
TEST(X25519Test,SmallOrder)140 TEST(X25519Test, SmallOrder) {
141 static const uint8_t kSmallOrderPoint[32] = {
142 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3,
143 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32,
144 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8,
145 };
146
147 uint8_t out[32], private_key[32];
148 OPENSSL_memset(private_key, 0x11, sizeof(private_key));
149
150 OPENSSL_memset(out, 0xff, sizeof(out));
151 EXPECT_FALSE(ctwrapX25519(out, private_key, kSmallOrderPoint))
152 << "X25519 returned success with a small-order input.";
153
154 // For callers which don't check, |out| should still be filled with zeros.
155 static const uint8_t kZeros[32] = {0};
156 EXPECT_EQ(Bytes(kZeros), Bytes(out));
157 }
158
TEST(X25519Test,Iterated)159 TEST(X25519Test, Iterated) {
160 // Taken from https://tools.ietf.org/html/rfc7748#section-5.2.
161 uint8_t scalar[32] = {9}, point[32] = {9}, out[32];
162
163 for (unsigned i = 0; i < 1000; i++) {
164 EXPECT_TRUE(ctwrapX25519(out, scalar, point));
165 OPENSSL_memcpy(point, scalar, sizeof(point));
166 OPENSSL_memcpy(scalar, out, sizeof(scalar));
167 }
168
169 static const uint8_t kExpected[32] = {
170 0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, 0x28, 0x00, 0xef,
171 0x56, 0x6f, 0x2f, 0x4d, 0x3c, 0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60,
172 0xe3, 0x87, 0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51,
173 };
174
175 EXPECT_EQ(Bytes(kExpected), Bytes(scalar));
176 }
177
TEST(X25519Test,DISABLED_IteratedLarge)178 TEST(X25519Test, DISABLED_IteratedLarge) {
179 // Taken from https://tools.ietf.org/html/rfc7748#section-5.2.
180 uint8_t scalar[32] = {9}, point[32] = {9}, out[32];
181
182 for (unsigned i = 0; i < 1000000; i++) {
183 EXPECT_TRUE(ctwrapX25519(out, scalar, point));
184 OPENSSL_memcpy(point, scalar, sizeof(point));
185 OPENSSL_memcpy(scalar, out, sizeof(scalar));
186 }
187
188 static const uint8_t kExpected[32] = {
189 0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, 0x86, 0x44, 0x97,
190 0x29, 0x7e, 0x57, 0x5e, 0x6f, 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c,
191 0x30, 0xdf, 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24,
192 };
193
194 EXPECT_EQ(Bytes(kExpected), Bytes(scalar));
195 }
196
TEST(X25519Test,Wycheproof)197 TEST(X25519Test, Wycheproof) {
198 FileTestGTest("third_party/wycheproof_testvectors/x25519_test.txt",
199 [](FileTest *t) {
200 t->IgnoreInstruction("curve");
201 t->IgnoreAttribute("curve");
202
203 WycheproofResult result;
204 ASSERT_TRUE(GetWycheproofResult(t, &result));
205 std::vector<uint8_t> priv, pub, shared;
206 ASSERT_TRUE(t->GetBytes(&priv, "private"));
207 ASSERT_TRUE(t->GetBytes(&pub, "public"));
208 ASSERT_TRUE(t->GetBytes(&shared, "shared"));
209 ASSERT_EQ(32u, priv.size());
210 ASSERT_EQ(32u, pub.size());
211
212 uint8_t secret[32];
213 int ret = ctwrapX25519(secret, priv.data(), pub.data());
214 EXPECT_EQ(ret, result.IsValid({"NonCanonicalPublic", "Twist"}) ? 1 : 0);
215 EXPECT_EQ(Bytes(secret), Bytes(shared));
216 });
217 }
218
219 #if defined(BORINGSSL_X25519_NEON) && defined(SUPPORTS_ABI_TEST)
TEST(X25519Test,NeonABI)220 TEST(X25519Test, NeonABI) {
221 if (!CRYPTO_is_NEON_capable()) {
222 GTEST_SKIP() << "Can't test ABI of NEON code without NEON";
223 }
224
225 static const uint8_t kScalar[32] = {
226 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15,
227 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc,
228 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4,
229 };
230 static const uint8_t kPoint[32] = {
231 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1,
232 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3,
233 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c,
234 };
235 uint8_t secret[32];
236 CHECK_ABI(x25519_NEON, secret, kScalar, kPoint);
237 }
238 #endif // BORINGSSL_X25519_NEON && SUPPORTS_ABI_TEST
239
240 #if defined(BORINGSSL_FE25519_ADX) && defined(SUPPORTS_ABI_TEST)
TEST(X25519Test,AdxMulABI)241 TEST(X25519Test, AdxMulABI) {
242 static const uint64_t in1[4] = {0}, in2[4] = {0};
243 uint64_t out[4];
244 if (CRYPTO_is_BMI1_capable() && CRYPTO_is_BMI2_capable() &&
245 CRYPTO_is_ADX_capable()) {
246 CHECK_ABI(fiat_curve25519_adx_mul, out, in1, in2);
247 } else {
248 GTEST_SKIP() << "Can't test ABI of ADX code without ADX";
249 }
250 }
251
TEST(X25519Test,AdxSquareABI)252 TEST(X25519Test, AdxSquareABI) {
253 static const uint64_t in[4] = {0};
254 uint64_t out[4];
255 if (CRYPTO_is_BMI1_capable() && CRYPTO_is_BMI2_capable() &&
256 CRYPTO_is_ADX_capable()) {
257 CHECK_ABI(fiat_curve25519_adx_square, out, in);
258 } else {
259 GTEST_SKIP() << "Can't test ABI of ADX code without ADX";
260 }
261 }
262 #endif // BORINGSSL_FE25519_ADX && SUPPORTS_ABI_TEST
263