1 // Copyright 2017 Google Inc. 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 // http://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 //////////////////////////////////////////////////////////////////////////////// 16 17 package com.google.crypto.tink.subtle; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static org.junit.Assert.assertArrayEquals; 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertFalse; 23 import static org.junit.Assert.assertThrows; 24 25 import com.google.crypto.tink.testing.TestUtil; 26 import com.google.crypto.tink.testing.WycheproofTestUtil; 27 import com.google.gson.JsonArray; 28 import com.google.gson.JsonObject; 29 import java.math.BigInteger; 30 import java.security.GeneralSecurityException; 31 import java.security.KeyFactory; 32 import java.security.interfaces.ECPrivateKey; 33 import java.security.interfaces.ECPublicKey; 34 import java.security.spec.ECPoint; 35 import java.security.spec.EllipticCurve; 36 import java.security.spec.X509EncodedKeySpec; 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 import org.junit.runners.JUnit4; 40 41 /** Unit tests for {@link com.google.crypto.tink.subtle.EllipticCurves}. */ 42 @RunWith(JUnit4.class) 43 public class EllipticCurvesTest { 44 // The tests are from 45 // http://google.github.io/end-to-end/api/source/src/javascript/crypto/e2e/ecc/ecdh_testdata.js.src.html. 46 47 /** 48 * A class for storing test vectors. This class contains the directory for the public and private 49 * key, the message and the corresponding signature. 50 */ 51 protected static class TestVector2 { 52 protected EllipticCurves.CurveType curve; 53 protected EllipticCurves.PointFormatType format; 54 protected byte[] encoded; 55 BigInteger x; 56 BigInteger y; 57 TestVector2( EllipticCurves.CurveType curve, EllipticCurves.PointFormatType format, String encodedHex, String x, String y)58 protected TestVector2( 59 EllipticCurves.CurveType curve, 60 EllipticCurves.PointFormatType format, 61 String encodedHex, 62 String x, 63 String y) { 64 this.curve = curve; 65 this.format = format; 66 this.encoded = Hex.decode(encodedHex); 67 this.x = new BigInteger(x); 68 this.y = new BigInteger(y); 69 } 70 } 71 72 protected static final TestVector2[] testVectors2 = { 73 // NIST_P256 74 new TestVector2( 75 EllipticCurves.CurveType.NIST_P256, 76 EllipticCurves.PointFormatType.UNCOMPRESSED, 77 "04" 78 + "b0cfc7bc02fc980d858077552947ffb449b10df8949dee4e56fe21e016dcb25a" 79 + "1886ccdca5487a6772f9401888203f90587cc00a730e2b83d5c6f89b3b568df7", 80 "79974177209371530366349631093481213364328002500948308276357601809416549347930", 81 "11093679777528052772423074391650378811758820120351664471899251711300542565879"), 82 new TestVector2( 83 EllipticCurves.CurveType.NIST_P256, 84 EllipticCurves.PointFormatType.DO_NOT_USE_CRUNCHY_UNCOMPRESSED, 85 "b0cfc7bc02fc980d858077552947ffb449b10df8949dee4e56fe21e016dcb25a" 86 + "1886ccdca5487a6772f9401888203f90587cc00a730e2b83d5c6f89b3b568df7", 87 "79974177209371530366349631093481213364328002500948308276357601809416549347930", 88 "11093679777528052772423074391650378811758820120351664471899251711300542565879"), 89 new TestVector2( 90 EllipticCurves.CurveType.NIST_P256, 91 EllipticCurves.PointFormatType.COMPRESSED, 92 "03b0cfc7bc02fc980d858077552947ffb449b10df8949dee4e56fe21e016dcb25a", 93 "79974177209371530366349631093481213364328002500948308276357601809416549347930", 94 "11093679777528052772423074391650378811758820120351664471899251711300542565879"), 95 // Exceptional point: x==0 96 new TestVector2( 97 EllipticCurves.CurveType.NIST_P256, 98 EllipticCurves.PointFormatType.UNCOMPRESSED, 99 "04" 100 + "0000000000000000000000000000000000000000000000000000000000000000" 101 + "66485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4", 102 "0", 103 "46263761741508638697010950048709651021688891777877937875096931459006746039284"), 104 new TestVector2( 105 EllipticCurves.CurveType.NIST_P256, 106 EllipticCurves.PointFormatType.DO_NOT_USE_CRUNCHY_UNCOMPRESSED, 107 "0000000000000000000000000000000000000000000000000000000000000000" 108 + "66485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4", 109 "0", 110 "46263761741508638697010950048709651021688891777877937875096931459006746039284"), 111 new TestVector2( 112 EllipticCurves.CurveType.NIST_P256, 113 EllipticCurves.PointFormatType.COMPRESSED, 114 "020000000000000000000000000000000000000000000000000000000000000000", 115 "0", 116 "46263761741508638697010950048709651021688891777877937875096931459006746039284"), 117 // Exceptional point: x==-3 118 new TestVector2( 119 EllipticCurves.CurveType.NIST_P256, 120 EllipticCurves.PointFormatType.UNCOMPRESSED, 121 "04" 122 + "ffffffff00000001000000000000000000000000fffffffffffffffffffffffc" 123 + "19719bebf6aea13f25c96dfd7c71f5225d4c8fc09eb5a0ab9f39e9178e55c121", 124 "115792089210356248762697446949407573530086143415290314195533631308867097853948", 125 "11508551065151498768481026661199445482476508121209842448718573150489103679777"), 126 new TestVector2( 127 EllipticCurves.CurveType.NIST_P256, 128 EllipticCurves.PointFormatType.DO_NOT_USE_CRUNCHY_UNCOMPRESSED, 129 "ffffffff00000001000000000000000000000000fffffffffffffffffffffffc" 130 + "19719bebf6aea13f25c96dfd7c71f5225d4c8fc09eb5a0ab9f39e9178e55c121", 131 "115792089210356248762697446949407573530086143415290314195533631308867097853948", 132 "11508551065151498768481026661199445482476508121209842448718573150489103679777"), 133 new TestVector2( 134 EllipticCurves.CurveType.NIST_P256, 135 EllipticCurves.PointFormatType.COMPRESSED, 136 "03ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 137 "115792089210356248762697446949407573530086143415290314195533631308867097853948", 138 "11508551065151498768481026661199445482476508121209842448718573150489103679777"), 139 // NIST_P384 140 new TestVector2( 141 EllipticCurves.CurveType.NIST_P384, 142 EllipticCurves.PointFormatType.UNCOMPRESSED, 143 "04aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a" 144 + "385502f25dbf55296c3a545e3872760ab73617de4a96262c6f5d9e98bf9292dc" 145 + "29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e" 146 + "5f", 147 "2624703509579968926862315674456698189185292349110921338781561590" 148 + "0925518854738050089022388053975719786650872476732087", 149 "8325710961489029985546751289520108179287853048861315594709205902" 150 + "480503199884419224438643760392947333078086511627871"), 151 new TestVector2( 152 EllipticCurves.CurveType.NIST_P384, 153 EllipticCurves.PointFormatType.COMPRESSED, 154 "03aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a" 155 + "385502f25dbf55296c3a545e3872760ab7", 156 "2624703509579968926862315674456698189185292349110921338781561590" 157 + "0925518854738050089022388053975719786650872476732087", 158 "8325710961489029985546751289520108179287853048861315594709205902" 159 + "480503199884419224438643760392947333078086511627871"), 160 // x = 0 161 new TestVector2( 162 EllipticCurves.CurveType.NIST_P384, 163 EllipticCurves.PointFormatType.UNCOMPRESSED, 164 "0400000000000000000000000000000000000000000000000000000000000000" 165 + "00000000000000000000000000000000003cf99ef04f51a5ea630ba3f9f960dd" 166 + "593a14c9be39fd2bd215d3b4b08aaaf86bbf927f2c46e52ab06fb742b8850e52" 167 + "1e", 168 "0", 169 "9384923975005507693384933751151973636103286582194273515051780595" 170 + "652610803541482195894618304099771370981414591681054"), 171 new TestVector2( 172 EllipticCurves.CurveType.NIST_P384, 173 EllipticCurves.PointFormatType.COMPRESSED, 174 "0200000000000000000000000000000000000000000000000000000000000000" 175 + "0000000000000000000000000000000000", 176 "0", 177 "9384923975005507693384933751151973636103286582194273515051780595" 178 + "652610803541482195894618304099771370981414591681054"), 179 // x = 2 180 new TestVector2( 181 EllipticCurves.CurveType.NIST_P384, 182 EllipticCurves.PointFormatType.UNCOMPRESSED, 183 "0400000000000000000000000000000000000000000000000000000000000000" 184 + "0000000000000000000000000000000002732152442fb6ee5c3e6ce1d920c059" 185 + "bc623563814d79042b903ce60f1d4487fccd450a86da03f3e6ed525d02017bfd" 186 + "b3", 187 "2", 188 "1772015366480916228638409476801818679957736647795608728422858375" 189 + "4887974043472116432532980617621641492831213601947059"), 190 new TestVector2( 191 EllipticCurves.CurveType.NIST_P384, 192 EllipticCurves.PointFormatType.COMPRESSED, 193 "0300000000000000000000000000000000000000000000000000000000000000" 194 + "0000000000000000000000000000000002", 195 "2", 196 "1772015366480916228638409476801818679957736647795608728422858375" 197 + "4887974043472116432532980617621641492831213601947059"), 198 // x = -3 199 new TestVector2( 200 EllipticCurves.CurveType.NIST_P384, 201 EllipticCurves.PointFormatType.UNCOMPRESSED, 202 "04ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 203 + "feffffffff0000000000000000fffffffc2de9de09a95b74e6b2c430363e1afb" 204 + "8dff7164987a8cfe0a0d5139250ac02f797f81092a9bdc0e09b574a8f43bf80c" 205 + "17", 206 "3940200619639447921227904010014361380507973927046544666794829340" 207 + "4245721771496870329047266088258938001861606973112316", 208 "7066741234775658874139271223692271325950306561732202191471600407" 209 + "582071247913794644254895122656050391930754095909911"), 210 new TestVector2( 211 EllipticCurves.CurveType.NIST_P384, 212 EllipticCurves.PointFormatType.COMPRESSED, 213 "03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 214 + "feffffffff0000000000000000fffffffc", 215 "3940200619639447921227904010014361380507973927046544666794829340" 216 + "4245721771496870329047266088258938001861606973112316", 217 "7066741234775658874139271223692271325950306561732202191471600407" 218 + "582071247913794644254895122656050391930754095909911"), 219 // NIST_P521 220 new TestVector2( 221 EllipticCurves.CurveType.NIST_P521, 222 EllipticCurves.PointFormatType.UNCOMPRESSED, 223 "0400c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b" 224 + "4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2" 225 + "e5bd66011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd" 226 + "17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94" 227 + "769fd16650", 228 "2661740802050217063228768716723360960729859168756973147706671368" 229 + "4188029449964278084915450806277719023520942412250655586621571135" 230 + "45570916814161637315895999846", 231 "3757180025770020463545507224491183603594455134769762486694567779" 232 + "6155444774405563166912344050129455395621444445372894285225856667" 233 + "29196580810124344277578376784"), 234 new TestVector2( 235 EllipticCurves.CurveType.NIST_P521, 236 EllipticCurves.PointFormatType.COMPRESSED, 237 "0200c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b" 238 + "4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2" 239 + "e5bd66", 240 "2661740802050217063228768716723360960729859168756973147706671368" 241 + "4188029449964278084915450806277719023520942412250655586621571135" 242 + "45570916814161637315895999846", 243 "3757180025770020463545507224491183603594455134769762486694567779" 244 + "6155444774405563166912344050129455395621444445372894285225856667" 245 + "29196580810124344277578376784"), 246 // x = 0 247 new TestVector2( 248 EllipticCurves.CurveType.NIST_P521, 249 EllipticCurves.PointFormatType.UNCOMPRESSED, 250 "0400000000000000000000000000000000000000000000000000000000000000" 251 + "0000000000000000000000000000000000000000000000000000000000000000" 252 + "00000000d20ec9fea6b577c10d26ca1bb446f40b299e648b1ad508aad068896f" 253 + "ee3f8e614bc63054d5772bf01a65d412e0bcaa8e965d2f5d332d7f39f846d440" 254 + "ae001f4f87", 255 "0", 256 "2816414230262626695230339754503506208598534788872316917808418392" 257 + "0894686826982898181454171638541149642517061885689521392260532032" 258 + "30035588176689756661142736775"), 259 new TestVector2( 260 EllipticCurves.CurveType.NIST_P521, 261 EllipticCurves.PointFormatType.COMPRESSED, 262 "0300000000000000000000000000000000000000000000000000000000000000" 263 + "0000000000000000000000000000000000000000000000000000000000000000" 264 + "000000", 265 "0", 266 "2816414230262626695230339754503506208598534788872316917808418392" 267 + "0894686826982898181454171638541149642517061885689521392260532032" 268 + "30035588176689756661142736775"), 269 // x = 1 270 new TestVector2( 271 EllipticCurves.CurveType.NIST_P521, 272 EllipticCurves.PointFormatType.UNCOMPRESSED, 273 "0400000000000000000000000000000000000000000000000000000000000000" 274 + "0000000000000000000000000000000000000000000000000000000000000000" 275 + "0000010010e59be93c4f269c0269c79e2afd65d6aeaa9b701eacc194fb3ee03d" 276 + "f47849bf550ec636ebee0ddd4a16f1cd9406605af38f584567770e3f272d688c" 277 + "832e843564", 278 "1", 279 "2265505274322546447629271557184988697103589068170534253193208655" 280 + "0778100463909972583865730916407864371153050622267306901033104806" 281 + "9570407113457901669103973732"), 282 new TestVector2( 283 EllipticCurves.CurveType.NIST_P521, 284 EllipticCurves.PointFormatType.COMPRESSED, 285 "0200000000000000000000000000000000000000000000000000000000000000" 286 + "0000000000000000000000000000000000000000000000000000000000000000" 287 + "000001", 288 "1", 289 "2265505274322546447629271557184988697103589068170534253193208655" 290 + "0778100463909972583865730916407864371153050622267306901033104806" 291 + "9570407113457901669103973732"), 292 // x = 2 293 new TestVector2( 294 EllipticCurves.CurveType.NIST_P521, 295 EllipticCurves.PointFormatType.UNCOMPRESSED, 296 "0400000000000000000000000000000000000000000000000000000000000000" 297 + "0000000000000000000000000000000000000000000000000000000000000000" 298 + "00000200d9254fdf800496acb33790b103c5ee9fac12832fe546c632225b0f7f" 299 + "ce3da4574b1a879b623d722fa8fc34d5fc2a8731aad691a9a8bb8b554c95a051" 300 + "d6aa505acf", 301 "2", 302 "2911448509017565583245824537994174021964465504209366849707937264" 303 + "0417919148200722009442607963590225526059407040161685364728526719" 304 + "10134103604091376779754756815"), 305 new TestVector2( 306 EllipticCurves.CurveType.NIST_P521, 307 EllipticCurves.PointFormatType.COMPRESSED, 308 "0300000000000000000000000000000000000000000000000000000000000000" 309 + "0000000000000000000000000000000000000000000000000000000000000000" 310 + "000002", 311 "2", 312 "2911448509017565583245824537994174021964465504209366849707937264" 313 + "0417919148200722009442607963590225526059407040161685364728526719" 314 + "10134103604091376779754756815"), 315 // x = -2 316 new TestVector2( 317 EllipticCurves.CurveType.NIST_P521, 318 EllipticCurves.PointFormatType.UNCOMPRESSED, 319 "0401ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 320 + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 321 + "fffffd0010e59be93c4f269c0269c79e2afd65d6aeaa9b701eacc194fb3ee03d" 322 + "f47849bf550ec636ebee0ddd4a16f1cd9406605af38f584567770e3f272d688c" 323 + "832e843564", 324 "6864797660130609714981900799081393217269435300143305409394463459" 325 + "1855431833976560521225596406614545549772963113914808580371219879" 326 + "99716643812574028291115057149", 327 "2265505274322546447629271557184988697103589068170534253193208655" 328 + "0778100463909972583865730916407864371153050622267306901033104806" 329 + "9570407113457901669103973732"), 330 new TestVector2( 331 EllipticCurves.CurveType.NIST_P521, 332 EllipticCurves.PointFormatType.COMPRESSED, 333 "0201ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 334 + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 335 + "fffffd", 336 "6864797660130609714981900799081393217269435300143305409394463459" 337 + "1855431833976560521225596406614545549772963113914808580371219879" 338 + "99716643812574028291115057149", 339 "2265505274322546447629271557184988697103589068170534253193208655" 340 + "0778100463909972583865730916407864371153050622267306901033104806" 341 + "9570407113457901669103973732"), 342 }; 343 344 @Test testFieldSizeInBytes()345 public void testFieldSizeInBytes() throws Exception { 346 assertThat( 347 EllipticCurves.fieldSizeInBytes( 348 EllipticCurves.getCurveSpec(EllipticCurves.CurveType.NIST_P256).getCurve())) 349 .isEqualTo(32); 350 assertThat( 351 EllipticCurves.fieldSizeInBytes( 352 EllipticCurves.getCurveSpec(EllipticCurves.CurveType.NIST_P384).getCurve())) 353 .isEqualTo(48); 354 assertThat( 355 EllipticCurves.fieldSizeInBytes( 356 EllipticCurves.getCurveSpec(EllipticCurves.CurveType.NIST_P521).getCurve())) 357 .isEqualTo(66); 358 } 359 360 @Test testPointDecode()361 public void testPointDecode() throws Exception { 362 for (TestVector2 test : testVectors2) { 363 EllipticCurve curve = EllipticCurves.getCurveSpec(test.curve).getCurve(); 364 ECPoint p = EllipticCurves.pointDecode(curve, test.format, test.encoded); 365 assertEquals(p.getAffineX(), test.x); 366 assertEquals(p.getAffineY(), test.y); 367 } 368 } 369 370 @Test testPointEncode()371 public void testPointEncode() throws Exception { 372 for (TestVector2 test : testVectors2) { 373 EllipticCurve curve = EllipticCurves.getCurveSpec(test.curve).getCurve(); 374 ECPoint p = new ECPoint(test.x, test.y); 375 byte[] encoded = EllipticCurves.pointEncode(curve, test.format, p); 376 assertEquals(Hex.encode(encoded), Hex.encode(test.encoded)); 377 } 378 } 379 380 @Test pointEncode_failsIfPointIsNotOnCurve()381 public void pointEncode_failsIfPointIsNotOnCurve() throws Exception { 382 // Same an entry of testVectors2, but the value of y has been incremented by 1. 383 BigInteger x = new BigInteger( 384 "79974177209371530366349631093481213364328002500948308276357601809416549347930"); 385 BigInteger y = new BigInteger( 386 "11093679777528052772423074391650378811758820120351664471899251711300542565880"); 387 // Adding one to y make the point not be on the curve. 388 assertThrows( 389 GeneralSecurityException.class, 390 () -> 391 EllipticCurves.pointEncode( 392 EllipticCurves.CurveType.NIST_P256, 393 EllipticCurves.PointFormatType.UNCOMPRESSED, 394 new ECPoint(x, y))); 395 } 396 397 @Test pointDecode_uncompressed_failsIfPointIsNotOnCurve()398 public void pointDecode_uncompressed_failsIfPointIsNotOnCurve() throws Exception { 399 // Same an entry of testVectors2, but the last byte is changed from f7 to f6 400 byte[] encoded = 401 Hex.decode( 402 "04" 403 + "b0cfc7bc02fc980d858077552947ffb449b10df8949dee4e56fe21e016dcb25a" 404 + "1886ccdca5487a6772f9401888203f90587cc00a730e2b83d5c6f89b3b568df6"); 405 // Adding one to y make the point not be on the curve. 406 assertThrows(GeneralSecurityException.class, 407 () -> EllipticCurves.pointDecode(EllipticCurves.CurveType.NIST_P256, 408 EllipticCurves.PointFormatType.UNCOMPRESSED, encoded)); 409 } 410 411 @Test pointDecode_crunchy_failsIfPointIsNotOnCurve()412 public void pointDecode_crunchy_failsIfPointIsNotOnCurve() throws Exception { 413 // Same as an entry of testVectors2, but the last byte is changed from f4 to f5 414 byte[] encoded = 415 Hex.decode( 416 "0000000000000000000000000000000000000000000000000000000000000000" 417 + "66485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f5"); 418 // Adding one to y make the point not be on the curve. 419 assertThrows(GeneralSecurityException.class, 420 () -> EllipticCurves.pointDecode(EllipticCurves.CurveType.NIST_P256, 421 EllipticCurves.PointFormatType.DO_NOT_USE_CRUNCHY_UNCOMPRESSED, encoded)); 422 } 423 424 @Test pointDecode_compressed_failsIfEncodingIsInvalid()425 public void pointDecode_compressed_failsIfEncodingIsInvalid() throws Exception { 426 // Same as an entry of testVectors2, but the last byte is changed from 00 to 01 427 byte[] encoded = 428 Hex.decode("020000000000000000000000000000000000000000000000000000000000000001"); 429 assertThrows(GeneralSecurityException.class, 430 () -> EllipticCurves.pointDecode(EllipticCurves.CurveType.NIST_P256, 431 EllipticCurves.PointFormatType.COMPRESSED, encoded)); 432 } 433 434 /** A class to store a pair of valid Ecdsa signature in IEEE_P1363 and DER format. */ 435 protected static class EcdsaIeeeDer { 436 public String hexIeee; 437 public String hexDer; 438 EcdsaIeeeDer(String hexIeee, String hexDer)439 protected EcdsaIeeeDer(String hexIeee, String hexDer) { 440 this.hexIeee = hexIeee; 441 this.hexDer = hexDer; 442 } 443 }; 444 445 protected static final EcdsaIeeeDer[] ieeeDerTestVector = 446 new EcdsaIeeeDer[] { 447 new EcdsaIeeeDer( // normal case, short-form length 448 "0102030405060708090a0b0c0d0e0f100102030405060708090a0b0c0d0e0f10", 449 "302402100102030405060708090a0b0c0d0e0f1002100102030405060708090a0b0c0d0e0f10"), 450 new EcdsaIeeeDer( // normal case, long-form length 451 "010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000203010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000203", 452 "30818802420100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000002030242010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000203"), 453 new EcdsaIeeeDer( // zero prefix. 454 "0002030405060708090a0b0c0d0e0f100002030405060708090a0b0c0d0e0f10", 455 "3022020f02030405060708090a0b0c0d0e0f10020f02030405060708090a0b0c0d0e0f10"), 456 new EcdsaIeeeDer( // highest bit is set. 457 "00ff030405060708090a0b0c0d0e0f1000ff030405060708090a0b0c0d0e0f10", 458 "3024021000ff030405060708090a0b0c0d0e0f10021000ff030405060708090a0b0c0d0e0f10"), 459 new EcdsaIeeeDer( // highest bit is set, full length. 460 "ff02030405060708090a0b0c0d0e0f10ff02030405060708090a0b0c0d0e0f10", 461 "3026021100ff02030405060708090a0b0c0d0e0f10021100ff02030405060708090a0b0c0d0e0f10"), 462 new EcdsaIeeeDer( // all zeros. 463 "0000000000000000000000000000000000000000000000000000000000000000", "3006020100020100"), 464 }; 465 466 @Test testEcdsaIeee2Der()467 public void testEcdsaIeee2Der() throws Exception { 468 for (EcdsaIeeeDer test : ieeeDerTestVector) { 469 assertArrayEquals( 470 Hex.decode(test.hexDer), EllipticCurves.ecdsaIeee2Der(Hex.decode(test.hexIeee))); 471 } 472 } 473 474 @Test testEcdsaDer2Ieee()475 public void testEcdsaDer2Ieee() throws Exception { 476 for (EcdsaIeeeDer test : ieeeDerTestVector) { 477 assertArrayEquals( 478 Hex.decode(test.hexIeee), 479 EllipticCurves.ecdsaDer2Ieee(Hex.decode(test.hexDer), test.hexIeee.length() / 2)); 480 } 481 } 482 483 protected static final String[] invalidEcdsaDers = 484 new String[] { 485 "2006020101020101", // 1st byte is not 0x30 (SEQUENCE tag) 486 "3006050101020101", // 3rd byte is not 0x02 (INTEGER tag) 487 "3006020101050101", // 6th byte is not 0x02 (INTEGER tag) 488 "308206020101020101", // long form length is not 0x81 489 "30ff020101020101", // invalid total length 490 "3006020201020101", // invalid rLength 491 "3006020101020201", // invalid sLength 492 "30060201ff020101", // no extra zero when highest bit of r is set 493 "30060201010201ff", // no extra zero when highest bit of s is set 494 }; 495 496 @Test testIsValidDerEncoding()497 public void testIsValidDerEncoding() throws Exception { 498 for (String der : invalidEcdsaDers) { 499 assertFalse(EllipticCurves.isValidDerEncoding(Hex.decode(der))); 500 } 501 } 502 503 @Test testComputeSharedSecretWithWycheproofTestVectors()504 public void testComputeSharedSecretWithWycheproofTestVectors() throws Exception { 505 if (TestUtil.isTsan()) { 506 return; 507 } 508 509 // NOTE(bleichen): Instead of ecdh_test.json it might be easier to use the 510 // files ecdh_<curve>_ecpoint.json, which encode the public key point just as DER 511 // encoded bitsequence. 512 JsonObject json = 513 WycheproofTestUtil.readJson("../wycheproof/testvectors/ecdh_test.json"); 514 int errors = 0; 515 JsonArray testGroups = json.get("testGroups").getAsJsonArray(); 516 for (int i = 0; i < testGroups.size(); i++) { 517 JsonObject group = testGroups.get(i).getAsJsonObject(); 518 JsonArray tests = group.get("tests").getAsJsonArray(); 519 String curve = group.get("curve").getAsString(); 520 if (!curve.equals("secp256r1") && !curve.equals("secp384r1") && !curve.equals("secp521r1")) { 521 // Only NIST curves P-256, P-384 and P-521 are supported. 522 continue; 523 } 524 EllipticCurves.CurveType curveType = WycheproofTestUtil.getCurveType(curve); 525 for (int j = 0; j < tests.size(); j++) { 526 JsonObject testcase = tests.get(j).getAsJsonObject(); 527 String tcId = 528 String.format( 529 "testcase %d (%s)", 530 testcase.get("tcId").getAsInt(), testcase.get("comment").getAsString()); 531 String result = testcase.get("result").getAsString(); 532 String hexPubKey = testcase.get("public").getAsString(); 533 String expectedSharedSecret = testcase.get("shared").getAsString(); 534 String hexPrivKey = testcase.get("private").getAsString(); 535 if (hexPrivKey.length() % 2 == 1) { 536 hexPrivKey = "0" + hexPrivKey; 537 } 538 KeyFactory kf = EngineFactory.KEY_FACTORY.getInstance("EC"); 539 try { 540 ECPrivateKey privKey = EllipticCurves.getEcPrivateKey(curveType, Hex.decode(hexPrivKey)); 541 542 X509EncodedKeySpec x509keySpec = new X509EncodedKeySpec(Hex.decode(hexPubKey)); 543 ECPublicKey pubKey = (ECPublicKey) kf.generatePublic(x509keySpec); 544 String sharedSecret = Hex.encode(EllipticCurves.computeSharedSecret(privKey, pubKey)); 545 if (result.equals("invalid")) { 546 if (expectedSharedSecret.equals(sharedSecret) 547 && WycheproofTestUtil.checkFlags( 548 testcase, "WrongOrder", "WeakPublicKey", "UnnamedCurve")) { 549 System.out.println( 550 tcId + " accepted invalid parameters but shared secret is correct."); 551 } else { 552 System.out.println( 553 "FAIL " + tcId + " accepted invalid parameters, shared secret: " + sharedSecret); 554 errors++; 555 } 556 } else if (!expectedSharedSecret.equals(sharedSecret)) { 557 System.out.println( 558 "FAIL " 559 + tcId 560 + " incorrect shared secret, computed: " 561 + sharedSecret 562 + " expected: " 563 + expectedSharedSecret); 564 errors++; 565 } 566 } catch (GeneralSecurityException ex) { 567 System.out.println(tcId + " threw exception: " + ex.toString()); 568 if (result.equals("valid")) { 569 System.out.println("FAIL " + tcId + " exception: " + ex.toString()); 570 ex.printStackTrace(); 571 errors++; 572 } 573 } catch (Exception ex) { 574 // Other exceptions typically indicate that something is wrong with the implementation. 575 System.out.println("FAIL " + tcId + " exception: " + ex.toString()); 576 ex.printStackTrace(); 577 errors++; 578 } 579 } 580 } 581 assertEquals(0, errors); 582 } 583 584 @Test computeSharedSecretWithPublicPoint()585 public void computeSharedSecretWithPublicPoint() throws Exception { 586 // test vector from wycheproof's ecdh_secp256r1_ecpoint_test.json, normal case. 587 ECPrivateKey ecPrivateKey = 588 EllipticCurves.getEcPrivateKey( 589 EllipticCurves.CurveType.NIST_P256, 590 Hex.decode("0612465c89a023ab17855b0a6bcebfd3febb53aef84138647b5352e02c10c346")); 591 ECPoint ecPublicPoint = 592 EllipticCurves.pointDecode( 593 EllipticCurves.CurveType.NIST_P256, 594 EllipticCurves.PointFormatType.UNCOMPRESSED, 595 Hex.decode( 596 "0462d5bd3372af75fe85a040715d0f502428e07046868b0bfdfa61d731afe44f26ac333a93" 597 + "a9e70a81cd5a95b5bf8d13990eb741c8c38872b4a07d275a014e30cf")); 598 byte[] expected = 599 Hex.decode("53020d908b0219328b658b525f26780e3ae12bcd952bb25a93bc0895e1714285"); 600 601 byte[] sharedSecret = EllipticCurves.computeSharedSecret(ecPrivateKey, ecPublicPoint); 602 assertThat(sharedSecret).isEqualTo(expected); 603 604 ECPoint publicPointNotOnCurve = 605 new ECPoint(ecPublicPoint.getAffineX(), ecPublicPoint.getAffineY().add(BigInteger.ONE)); 606 assertThrows( 607 GeneralSecurityException.class, 608 () -> EllipticCurves.computeSharedSecret(ecPrivateKey, publicPointNotOnCurve)); 609 } 610 611 @Test computeSharedSecretWithPublicPointP256()612 public void computeSharedSecretWithPublicPointP256() throws Exception { 613 // test vector from golang's crypto/ecdh/ecdh_test.go. 614 ECPrivateKey ecPrivateKey = 615 EllipticCurves.getEcPrivateKey( 616 EllipticCurves.CurveType.NIST_P256, 617 Hex.decode("7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534")); 618 ECPoint ecPublicPoint = 619 EllipticCurves.pointDecode( 620 EllipticCurves.CurveType.NIST_P256, 621 EllipticCurves.PointFormatType.UNCOMPRESSED, 622 Hex.decode( 623 "04700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287" 624 + "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac")); 625 byte[] expected = 626 Hex.decode("46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b"); 627 628 byte[] sharedSecret = EllipticCurves.computeSharedSecret(ecPrivateKey, ecPublicPoint); 629 assertThat(sharedSecret).isEqualTo(expected); 630 } 631 632 @Test computeSharedSecretWithPublicPointP384()633 public void computeSharedSecretWithPublicPointP384() throws Exception { 634 // test vector from golang's crypto/ecdh/ecdh_test.go. 635 ECPrivateKey ecPrivateKey = 636 EllipticCurves.getEcPrivateKey( 637 EllipticCurves.CurveType.NIST_P384, 638 Hex.decode( 639 "3cc3122a68f0d95027ad38c067916ba0eb8c38894d22e1b15618b6818a661774ad463b205da88cf699ab4d43c9cf98a1")); 640 ECPoint ecPublicPoint = 641 EllipticCurves.pointDecode( 642 EllipticCurves.CurveType.NIST_P384, 643 EllipticCurves.PointFormatType.UNCOMPRESSED, 644 Hex.decode( 645 "04a7c76b970c3b5fe8b05d2838ae04ab47697b9eaf52e764592efda27fe7513272734466b400091adbf2d68c58e0c50066" 646 + "ac68f19f2e1cb879aed43a9969b91a0839c4c38a49749b661efedf243451915ed0905a32b060992b468c64766fc8437a")); 647 byte[] expected = 648 Hex.decode( 649 "5f9d29dc5e31a163060356213669c8ce132e22f57c9a04f40ba7fcead493b457e5621e766c40a2e3d4d6a04b25e533f1"); 650 651 byte[] sharedSecret = EllipticCurves.computeSharedSecret(ecPrivateKey, ecPublicPoint); 652 assertThat(sharedSecret).isEqualTo(expected); 653 } 654 655 @Test computeSharedSecretWithPublicPointP521()656 public void computeSharedSecretWithPublicPointP521() throws Exception { 657 // test vector from golang's crypto/ecdh/ecdh_test.go. 658 ECPrivateKey ecPrivateKey = 659 EllipticCurves.getEcPrivateKey( 660 EllipticCurves.CurveType.NIST_P521, 661 Hex.decode( 662 "017eecc07ab4b329068fba65e56a1f8890aa935e57134ae0ffcce802735151f4eac6564f6ee9974c5e6887a1fefee5743ae2241bfeb95d5ce31ddcb6f9edb4d6fc47")); 663 ECPoint ecPublicPoint = 664 EllipticCurves.pointDecode( 665 EllipticCurves.CurveType.NIST_P521, 666 EllipticCurves.PointFormatType.UNCOMPRESSED, 667 Hex.decode( 668 "0400685a48e86c79f0f0875f7bc18d25eb5fc8c0b07e5da4f4370f3a9490340854334b1e1b87fa395464c60626124a4e70d0f785601d37c09870ebf176666877a2046d" 669 + "01ba52c56fc8776d9e8f5db4f0cc27636d0b741bbe05400697942e80b739884a83bde99e0f6716939e632bc8986fa18dccd443a348b6c3e522497955a4f3c302f676")); 670 byte[] expected = 671 Hex.decode( 672 "005fc70477c3e63bc3954bd0df3ea0d1f41ee21746ed95fc5e1fdf90930d5e136672d72cc770742d1711c3c3a4c334a0ad9759436a4d3c5bf6e74b9578fac148c831"); 673 674 byte[] sharedSecret = EllipticCurves.computeSharedSecret(ecPrivateKey, ecPublicPoint); 675 assertThat(sharedSecret).isEqualTo(expected); 676 } 677 678 @Test validateSharedSecret()679 public void validateSharedSecret() throws Exception { 680 // test vector from wycheproof's ecdh_secp256r1_ecpoint_test.json, normal case. 681 ECPrivateKey ecPrivateKey = 682 EllipticCurves.getEcPrivateKey( 683 EllipticCurves.CurveType.NIST_P256, 684 Hex.decode("0612465c89a023ab17855b0a6bcebfd3febb53aef84138647b5352e02c10c346")); 685 byte[] sharedSecret = 686 Hex.decode("53020d908b0219328b658b525f26780e3ae12bcd952bb25a93bc0895e1714285"); 687 EllipticCurves.validateSharedSecret(sharedSecret, ecPrivateKey); 688 689 // Most byte strings shorter than sharedSecret are valid. 690 byte[] emptySharedSecret = new byte[0]; 691 EllipticCurves.validateSharedSecret(emptySharedSecret, ecPrivateKey); 692 byte[] anotherSharedSecret = Hex.decode("00112233445566778899aabbccddeeff"); 693 EllipticCurves.validateSharedSecret(anotherSharedSecret, ecPrivateKey); 694 byte[] ffSharedSecret = Hex.decode("ffffffffffffffffffffffffffffffffffffffff"); 695 EllipticCurves.validateSharedSecret(ffSharedSecret, ecPrivateKey); 696 697 // The modulusMinus1 is not a valid secret, because computeY fails. 698 byte[] modulusMinus1 = 699 Hex.decode("00ffffffff00000001000000000000000000000000fffffffffffffffffffffffe"); 700 assertThrows( 701 GeneralSecurityException.class, 702 () -> EllipticCurves.validateSharedSecret(modulusMinus1, ecPrivateKey)); 703 704 // The modulus is not a valid secret, because it is out of range. 705 byte[] modulus = 706 Hex.decode("00ffffffff00000001000000000000000000000000ffffffffffffffffffffffff"); 707 assertThrows( 708 GeneralSecurityException.class, 709 () -> EllipticCurves.validateSharedSecret(modulus, ecPrivateKey)); 710 } 711 } 712