1 // Copyright 2015 The BoringSSL Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
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], point[32], out[32];
162 // This could simply be `uint8_t scalar[32] = {9}`, but GCC's -Warray-bounds
163 // warning is broken. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114826.
164 OPENSSL_memset(scalar, 0, sizeof(scalar));
165 scalar[0] = 9;
166 OPENSSL_memset(point, 0, sizeof(point));
167 point[0] = 9;
168
169 for (unsigned i = 0; i < 1000; i++) {
170 EXPECT_TRUE(ctwrapX25519(out, scalar, point));
171 OPENSSL_memcpy(point, scalar, sizeof(point));
172 OPENSSL_memcpy(scalar, out, sizeof(scalar));
173 }
174
175 static const uint8_t kExpected[32] = {
176 0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, 0x28, 0x00, 0xef,
177 0x56, 0x6f, 0x2f, 0x4d, 0x3c, 0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60,
178 0xe3, 0x87, 0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51,
179 };
180
181 EXPECT_EQ(Bytes(kExpected), Bytes(scalar));
182 }
183
TEST(X25519Test,DISABLED_IteratedLarge)184 TEST(X25519Test, DISABLED_IteratedLarge) {
185 // Taken from https://tools.ietf.org/html/rfc7748#section-5.2.
186 uint8_t scalar[32], point[32], out[32];
187 // This could simply be `uint8_t scalar[32] = {9}`, but GCC's -Warray-bounds
188 // warning is broken. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114826.
189 OPENSSL_memset(scalar, 0, sizeof(scalar));
190 scalar[0] = 9;
191 OPENSSL_memset(point, 0, sizeof(point));
192 point[0] = 9;
193
194 for (unsigned i = 0; i < 1000000; i++) {
195 EXPECT_TRUE(ctwrapX25519(out, scalar, point));
196 OPENSSL_memcpy(point, scalar, sizeof(point));
197 OPENSSL_memcpy(scalar, out, sizeof(scalar));
198 }
199
200 static const uint8_t kExpected[32] = {
201 0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, 0x86, 0x44, 0x97,
202 0x29, 0x7e, 0x57, 0x5e, 0x6f, 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c,
203 0x30, 0xdf, 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24,
204 };
205
206 EXPECT_EQ(Bytes(kExpected), Bytes(scalar));
207 }
208
TEST(X25519Test,Wycheproof)209 TEST(X25519Test, Wycheproof) {
210 FileTestGTest("third_party/wycheproof_testvectors/x25519_test.txt",
211 [](FileTest *t) {
212 t->IgnoreInstruction("curve");
213 t->IgnoreAttribute("curve");
214
215 WycheproofResult result;
216 ASSERT_TRUE(GetWycheproofResult(t, &result));
217 std::vector<uint8_t> priv, pub, shared;
218 ASSERT_TRUE(t->GetBytes(&priv, "private"));
219 ASSERT_TRUE(t->GetBytes(&pub, "public"));
220 ASSERT_TRUE(t->GetBytes(&shared, "shared"));
221 ASSERT_EQ(32u, priv.size());
222 ASSERT_EQ(32u, pub.size());
223
224 uint8_t secret[32];
225 int ret = ctwrapX25519(secret, priv.data(), pub.data());
226 EXPECT_EQ(ret, result.IsValid({"NonCanonicalPublic", "Twist"}) ? 1 : 0);
227 EXPECT_EQ(Bytes(secret), Bytes(shared));
228 });
229 }
230
231 #if defined(BORINGSSL_X25519_NEON) && defined(SUPPORTS_ABI_TEST)
TEST(X25519Test,NeonABI)232 TEST(X25519Test, NeonABI) {
233 if (!CRYPTO_is_NEON_capable()) {
234 GTEST_SKIP() << "Can't test ABI of NEON code without NEON";
235 }
236
237 static const uint8_t kScalar[32] = {
238 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15,
239 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc,
240 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4,
241 };
242 static const uint8_t kPoint[32] = {
243 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1,
244 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3,
245 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c,
246 };
247 uint8_t secret[32];
248 CHECK_ABI(x25519_NEON, secret, kScalar, kPoint);
249 }
250 #endif // BORINGSSL_X25519_NEON && SUPPORTS_ABI_TEST
251
252 #if defined(BORINGSSL_FE25519_ADX) && defined(SUPPORTS_ABI_TEST)
TEST(X25519Test,AdxMulABI)253 TEST(X25519Test, AdxMulABI) {
254 static const uint64_t in1[4] = {0}, in2[4] = {0};
255 uint64_t out[4];
256 if (CRYPTO_is_BMI1_capable() && CRYPTO_is_BMI2_capable() &&
257 CRYPTO_is_ADX_capable()) {
258 CHECK_ABI(fiat_curve25519_adx_mul, out, in1, in2);
259 } else {
260 GTEST_SKIP() << "Can't test ABI of ADX code without ADX";
261 }
262 }
263
TEST(X25519Test,AdxSquareABI)264 TEST(X25519Test, AdxSquareABI) {
265 static const uint64_t in[4] = {0};
266 uint64_t out[4];
267 if (CRYPTO_is_BMI1_capable() && CRYPTO_is_BMI2_capable() &&
268 CRYPTO_is_ADX_capable()) {
269 CHECK_ABI(fiat_curve25519_adx_square, out, in);
270 } else {
271 GTEST_SKIP() << "Can't test ABI of ADX code without ADX";
272 }
273 }
274 #endif // BORINGSSL_FE25519_ADX && SUPPORTS_ABI_TEST
275