1 /* $OpenBSD: ecdhtest.c,v 1.20 2023/07/16 07:34:07 tb Exp $ */ 2 /* ==================================================================== 3 * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. 4 * 5 * The Elliptic Curve Public-Key Crypto Library (ECC Code) included 6 * herein is developed by SUN MICROSYSTEMS, INC., and is contributed 7 * to the OpenSSL project. 8 * 9 * The ECC Code is licensed pursuant to the OpenSSL open source 10 * license provided below. 11 * 12 * The ECDH software is originally written by Douglas Stebila of 13 * Sun Microsystems Laboratories. 14 * 15 */ 16 /* ==================================================================== 17 * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved. 18 * 19 * Redistribution and use in source and binary forms, with or without 20 * modification, are permitted provided that the following conditions 21 * are met: 22 * 23 * 1. Redistributions of source code must retain the above copyright 24 * notice, this list of conditions and the following disclaimer. 25 * 26 * 2. Redistributions in binary form must reproduce the above copyright 27 * notice, this list of conditions and the following disclaimer in 28 * the documentation and/or other materials provided with the 29 * distribution. 30 * 31 * 3. All advertising materials mentioning features or use of this 32 * software must display the following acknowledgment: 33 * "This product includes software developed by the OpenSSL Project 34 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 35 * 36 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 37 * endorse or promote products derived from this software without 38 * prior written permission. For written permission, please contact 39 * openssl-core@openssl.org. 40 * 41 * 5. Products derived from this software may not be called "OpenSSL" 42 * nor may "OpenSSL" appear in their names without prior written 43 * permission of the OpenSSL Project. 44 * 45 * 6. Redistributions of any form whatsoever must retain the following 46 * acknowledgment: 47 * "This product includes software developed by the OpenSSL Project 48 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 51 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 53 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 54 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 56 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 57 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 59 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 60 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 61 * OF THE POSSIBILITY OF SUCH DAMAGE. 62 * ==================================================================== 63 * 64 * This product includes cryptographic software written by Eric Young 65 * (eay@cryptsoft.com). This product includes software written by Tim 66 * Hudson (tjh@cryptsoft.com). 67 * 68 */ 69 70 #include <err.h> 71 #include <stdio.h> 72 #include <stdlib.h> 73 #include <string.h> 74 75 #include <openssl/bn.h> 76 #include <openssl/objects.h> 77 #include <openssl/sha.h> 78 #include <openssl/err.h> 79 80 #include <openssl/ec.h> 81 #include <openssl/ecdh.h> 82 83 static void 84 hexdump(const unsigned char *buf, size_t len) 85 { 86 size_t i; 87 88 for (i = 1; i <= len; i++) 89 fprintf(stdout, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n"); 90 91 if (len % 8) 92 fprintf(stdout, "\n"); 93 } 94 95 static void * 96 KDF1_SHA1(const void *in, size_t inlen, void *out, size_t *outlen) 97 { 98 #ifdef OPENSSL_NO_SHA 99 return NULL; 100 #else 101 if (*outlen < SHA_DIGEST_LENGTH) 102 return NULL; 103 *outlen = SHA_DIGEST_LENGTH; 104 return SHA1(in, inlen, out); 105 #endif 106 } 107 108 static int 109 ecdh_keygen_test(int nid) 110 { 111 EC_KEY *keya = NULL, *keyb = NULL; 112 const EC_POINT *puba, *pubb; 113 unsigned char *abuf = NULL, *bbuf = NULL; 114 int len = SHA_DIGEST_LENGTH; 115 int failed = 1; 116 117 if ((keya = EC_KEY_new_by_curve_name(nid)) == NULL) 118 goto err; 119 if (!EC_KEY_generate_key(keya)) 120 goto err; 121 if ((puba = EC_KEY_get0_public_key(keya)) == NULL) 122 goto err; 123 124 if ((keyb = EC_KEY_new_by_curve_name(nid)) == NULL) 125 goto err; 126 if (!EC_KEY_generate_key(keyb)) 127 goto err; 128 if ((pubb = EC_KEY_get0_public_key(keyb)) == NULL) 129 goto err; 130 131 if ((abuf = calloc(1, len)) == NULL) 132 goto err; 133 if ((bbuf = calloc(1, len)) == NULL) 134 goto err; 135 136 if (ECDH_compute_key(abuf, len, pubb, keya, KDF1_SHA1) != len) 137 goto err; 138 if (ECDH_compute_key(bbuf, len, puba, keyb, KDF1_SHA1) != len) 139 goto err; 140 141 if (memcmp(abuf, bbuf, len) != 0) { 142 printf("key generation with %s failed\n", OBJ_nid2sn(nid)); 143 144 EC_KEY_print_fp(stdout, keya, 1); 145 printf(" shared secret:\n"); 146 hexdump(abuf, len); 147 148 EC_KEY_print_fp(stdout, keyb, 1); 149 printf(" shared secret:\n"); 150 hexdump(bbuf, len); 151 152 fprintf(stderr, "Error in ECDH routines\n"); 153 154 goto err; 155 } 156 157 failed = 0; 158 159 err: 160 ERR_print_errors_fp(stderr); 161 162 EC_KEY_free(keya); 163 EC_KEY_free(keyb); 164 freezero(abuf, len); 165 freezero(bbuf, len); 166 167 return failed; 168 } 169 170 static const struct ecdh_kat_test { 171 const int nid; 172 const char *keya; 173 const char *keyb; 174 const char *want; 175 } ecdh_kat_tests[] = { 176 /* Keys and shared secrets from RFC 5114 */ 177 { 178 .nid = NID_X9_62_prime192v1, 179 .keya = "323fa3169d8e9c6593f59476bc142000ab5be0e249c43426", 180 .keyb = "631f95bb4a67632c9c476eee9ab695ab240a0499307fcf62", 181 .want = "ad420182633f8526bfe954acda376f05e5ff4f837f54febe", 182 }, 183 { 184 .nid = NID_secp224r1, 185 .keya = "b558eb6c288da707bbb4f8fbae2ab9e9cb62e3bc5c7573e2" 186 "2e26d37f", 187 .keyb = "ac3b1add3d9770e6f6a708ee9f3b8e0ab3b480e9f27f85c8" 188 "8b5e6d18", 189 .want = "52272f50f46f4edc9151569092f46df2d96ecc3b6dc1714a" 190 "4ea949fa", 191 }, 192 { 193 .nid = NID_X9_62_prime256v1, 194 .keya = "814264145f2f56f2e96a8e337a1284993faf432a5abce59e" 195 "867b7291d507a3af", 196 .keyb = "2ce1788ec197e096db95a200cc0ab26a19ce6bccad562b8e" 197 "ee1b593761cf7f41", 198 .want = "dd0f5396219d1ea393310412d19a08f1f5811e9dc8ec8eea" 199 "7f80d21c820c2788", 200 }, 201 { 202 .nid = NID_secp384r1, 203 .keya = "d27335ea71664af244dd14e9fd1260715dfd8a7965571c48" 204 "d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1", 205 .keyb = "52d1791fdb4b70f89c0f00d456c2f7023b6125262c36a7df" 206 "1f80231121cce3d39be52e00c194a4132c4a6c768bcd94d2", 207 .want = "5ea1fc4af7256d2055981b110575e0a8cae53160137d904c" 208 "59d926eb1b8456e427aa8a4540884c37de159a58028abc0e", 209 }, 210 { 211 .nid = NID_secp521r1, 212 .keya = "0113f82da825735e3d97276683b2b74277bad27335ea7166" 213 "4af2430cc4f33459b9669ee78b3ffb9b8683015d344dcbfe" 214 "f6fb9af4c6c470be254516cd3c1a1fb47362", 215 .keyb = "00cee3480d8645a17d249f2776d28bae616952d1791fdb4b" 216 "70f7c3378732aa1b22928448bcd1dc2496d435b01048066e" 217 "be4f72903c361b1a9dc1193dc2c9d0891b96", 218 .want = "00cdea89621cfa46b132f9e4cfe2261cde2d4368eb565663" 219 "4c7cc98c7a00cde54ed1866a0dd3e6126c9d2f845daff82c" 220 "eb1da08f5d87521bb0ebeca77911169c20cc", 221 }, 222 /* Keys and shared secrets from RFC 5903 */ 223 { 224 .nid = NID_X9_62_prime256v1, 225 .keya = "c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049" 226 "c62a9c57862d1433", 227 .keyb = "c6ef9c5d78ae012a011164acb397ce2088685d8f06bf9be0" 228 "b283ab46476bee53", 229 .want = "d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03" 230 "812464d04b9442de", 231 }, 232 { 233 .nid = NID_secp384r1, 234 .keya = "099f3c7034d4a2c699884d73a375a67f7624ef7c6b3c0f16" 235 "0647b67414dce655e35b538041e649ee3faef896783ab194", 236 .keyb = "41cb0779b4bdb85d47846725fbec3c9430fab46cc8dc5060" 237 "855cc9bda0aa2942e0308312916b8ed2960e4bd55a7448fc", 238 .want = "11187331c279962d93d604243fd592cb9d0a926f422e4718" 239 "7521287e7156c5c4d603135569b9e9d09cf5d4a270f59746", 240 }, 241 { 242 .nid = NID_secp521r1, 243 .keya = "0037ade9319a89f4dabdb3ef411aaccca5123c61acab57b5" 244 "393dce47608172a095aa85a30fe1c2952c6771d937ba9777" 245 "f5957b2639bab072462f68c27a57382d" 246 "4a52", 247 .keyb = "0145ba99a847af43793fdd0e872e7cdfa16be30fdc780f97" 248 "bccc3f078380201e9c677d600b343757a3bdbf2a3163e4c2" 249 "f869cca7458aa4a4effc311f5cb151685eb9", 250 .want = "01144c7d79ae6956bc8edb8e7c787c4521cb086fa64407f9" 251 "7894e5e6b2d79b04d1427e73ca4baa240a34786859810c06" 252 "b3c715a3a8cc3151f2bee417996d19f3ddea", 253 }, 254 /* Keys and shared secrets from RFC 7027 */ 255 { 256 .nid = NID_brainpoolP256r1, 257 .keya = "81db1ee100150ff2ea338d708271be38300cb54241d79950" 258 "f77b063039804f1d", 259 .keyb = "55e40bc41e37e3e2ad25c3c6654511ffa8474a91a0032087" 260 "593852d3e7d76bd3", 261 .want = "89afc39d41d3b327814b80940b042590f96556ec91e6ae79" 262 "39bce31f3a18bf2b", 263 }, 264 { 265 .nid = NID_brainpoolP384r1, 266 .keya = "1e20f5e048a5886f1f157c74e91bde2b98c8b52d58e5003d" 267 "57053fc4b0bd65d6f15eb5d1ee1610df870795143627d042", 268 .keyb = "032640bc6003c59260f7250c3db58ce647f98e1260acce4a" 269 "cda3dd869f74e01f8ba5e0324309db6a9831497abac96670", 270 .want = "0bd9d3a7ea0b3d519d09d8e48d0785fb744a6b355e6304bc" 271 "51c229fbbce239bbadf6403715c35d4fb2a5444f575d4f42", 272 }, 273 { 274 .nid = NID_brainpoolP512r1, 275 .keya = "16302ff0dbbb5a8d733dab7141c1b45acbc8715939677f6a" 276 "56850a38bd87bd59b09e80279609ff333eb9d4c061231fb2" 277 "6f92eeb04982a5f1d1764cad57665422", 278 .keyb = "230e18e1bcc88a362fa54e4ea3902009292f7f8033624fd4" 279 "71b5d8ace49d12cfabbc19963dab8e2f1eba00bffb29e4d7" 280 "2d13f2224562f405cb80503666b25429", 281 .want = "a7927098655f1f9976fa50a9d566865dc530331846381c87" 282 "256baf3226244b76d36403c024d7bbf0aa0803eaff405d3d" 283 "24f11a9b5c0bef679fe1454b21c4cd1f", 284 }, 285 }; 286 287 #define N_KATS (sizeof(ecdh_kat_tests) / sizeof(ecdh_kat_tests[0])) 288 289 /* Given private value and NID, create EC_KEY structure */ 290 291 static EC_KEY * 292 mk_eckey(int nid, const char *priv_str) 293 { 294 EC_KEY *key = NULL; 295 BIGNUM *priv = NULL; 296 EC_POINT *pub = NULL; 297 const EC_GROUP *group; 298 EC_KEY *ret = NULL; 299 300 if ((key = EC_KEY_new_by_curve_name(nid)) == NULL) 301 goto err; 302 if (!BN_hex2bn(&priv, priv_str)) 303 goto err; 304 if (!EC_KEY_set_private_key(key, priv)) 305 goto err; 306 if ((group = EC_KEY_get0_group(key)) == NULL) 307 goto err; 308 if ((pub = EC_POINT_new(group)) == NULL) 309 goto err; 310 if (!EC_POINT_mul(group, pub, priv, NULL, NULL, NULL)) 311 goto err; 312 if (!EC_KEY_set_public_key(key, pub)) 313 goto err; 314 315 ret = key; 316 key = NULL; 317 318 err: 319 EC_KEY_free(key); 320 BN_free(priv); 321 EC_POINT_free(pub); 322 323 return ret; 324 } 325 326 /* 327 * Known answer test: compute shared secret and check it matches expected value. 328 */ 329 static int 330 ecdh_kat(const struct ecdh_kat_test *kat) 331 { 332 EC_KEY *keya = NULL, *keyb = NULL; 333 const EC_POINT *puba, *pubb; 334 BIGNUM *z = NULL; 335 unsigned char *want = NULL, *got = NULL; 336 int len = 0; 337 int failed = 1; 338 339 if ((keya = mk_eckey(kat->nid, kat->keya)) == NULL) 340 goto err; 341 if ((puba = EC_KEY_get0_public_key(keya)) == NULL) 342 goto err; 343 if ((keyb = mk_eckey(kat->nid, kat->keyb)) == NULL) 344 goto err; 345 if ((pubb = EC_KEY_get0_public_key(keyb)) == NULL) 346 goto err; 347 348 if ((len = ECDH_size(keya)) != ECDH_size(keyb)) 349 goto err; 350 351 if ((want = calloc(1, len)) == NULL) 352 goto err; 353 if ((got = calloc(1, len)) == NULL) 354 goto err; 355 356 if (!BN_hex2bn(&z, kat->want)) 357 goto err; 358 if (BN_num_bytes(z) > len) 359 goto err; 360 if (BN_bn2binpad(z, want, len) != len) 361 goto err; 362 363 if (ECDH_compute_key(got, len, pubb, keya, NULL) != len) 364 goto err; 365 if (memcmp(got, want, len) != 0) 366 goto err; 367 368 memset(got, 0, len); 369 370 if (ECDH_compute_key(got, len, puba, keyb, NULL) != len) 371 goto err; 372 if (memcmp(got, want, len) != 0) 373 goto err; 374 375 failed = 0; 376 377 err: 378 if (failed) { 379 printf("shared secret with %s failed", OBJ_nid2sn(kat->nid)); 380 381 fprintf(stderr, "Error in ECDH routines\n"); 382 ERR_print_errors_fp(stderr); 383 } 384 385 EC_KEY_free(keya); 386 EC_KEY_free(keyb); 387 BN_free(z); 388 freezero(want, len); 389 freezero(got, len); 390 391 return failed; 392 } 393 394 int 395 main(void) 396 { 397 EC_builtin_curve *curves = NULL; 398 size_t i, n_curves; 399 int failed = 0; 400 401 if ((n_curves = EC_get_builtin_curves(NULL, 0)) == 0) 402 errx(1, "EC_get_builtin_curves failed"); 403 if ((curves = calloc(n_curves, sizeof(*curves))) == NULL) 404 errx(1, NULL); 405 if (EC_get_builtin_curves(curves, n_curves) != n_curves) 406 errx(1, "EC_get_builtin_curves failed"); 407 408 for (i = 0; i < n_curves; i++) 409 failed |= ecdh_keygen_test(curves[i].nid); 410 411 for (i = 0; i < N_KATS; i++) 412 failed |= ecdh_kat(&ecdh_kat_tests[i]); 413 414 free(curves); 415 ERR_print_errors_fp(stderr); 416 417 return failed; 418 } 419