• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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