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