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 com.google.crypto.tink.internal.BigIntegerEncoding; 20 import com.google.crypto.tink.internal.EllipticCurvesUtil; 21 import java.math.BigInteger; 22 import java.security.GeneralSecurityException; 23 import java.security.InvalidAlgorithmParameterException; 24 import java.security.KeyFactory; 25 import java.security.KeyPair; 26 import java.security.KeyPairGenerator; 27 import java.security.NoSuchAlgorithmException; 28 import java.security.PublicKey; 29 import java.security.interfaces.ECPrivateKey; 30 import java.security.interfaces.ECPublicKey; 31 import java.security.spec.ECParameterSpec; 32 import java.security.spec.ECPoint; 33 import java.security.spec.ECPrivateKeySpec; 34 import java.security.spec.ECPublicKeySpec; 35 import java.security.spec.EllipticCurve; 36 import java.security.spec.PKCS8EncodedKeySpec; 37 import java.security.spec.X509EncodedKeySpec; 38 import java.util.Arrays; 39 import javax.crypto.KeyAgreement; 40 41 /** 42 * Utility functions and enums for elliptic curve crypto, used in ECDSA and ECDH. 43 * 44 * @since 1.0.0 45 */ 46 public final class EllipticCurves { 47 48 /** 49 * Point format types UNCOMPRESSED and COMPRESSED are defined in https://www.secg.org/sec1-v2.pdf, 50 * Sections 2.3.3 and 2.3.4. 51 */ 52 public enum PointFormatType { 53 UNCOMPRESSED, 54 COMPRESSED, 55 // Like UNCOMPRESSED but without the \x04 prefix. Crunchy uses this format. 56 // DO NOT USE unless you are a Crunchy user moving to Tink. 57 DO_NOT_USE_CRUNCHY_UNCOMPRESSED, 58 } 59 60 /** Elliptic curve types. */ 61 public enum CurveType { 62 NIST_P256, 63 NIST_P384, 64 NIST_P521, 65 } 66 67 /** Ecdsa signature encoding. */ 68 public enum EcdsaEncoding { 69 IEEE_P1363, 70 DER, 71 } 72 getNistP256Params()73 public static ECParameterSpec getNistP256Params() { 74 return EllipticCurvesUtil.NIST_P256_PARAMS; 75 } 76 getNistP384Params()77 public static ECParameterSpec getNistP384Params() { 78 return EllipticCurvesUtil.NIST_P384_PARAMS; 79 } 80 getNistP521Params()81 public static ECParameterSpec getNistP521Params() { 82 return EllipticCurvesUtil.NIST_P521_PARAMS; 83 } 84 85 86 /** 87 * Checks that the point of the public key is on the curve of the public key. 88 * 89 * <h3>Warning</h3> 90 * 91 * <p>Please use {@link #validatePublicKey} if you want to validate a public key to avoid invalid 92 * curve attacks or small subgroup attacks in ECDH. 93 * 94 * <p>This is a sanity check, because the curve of the public key might be under control of the 95 * adversary. 96 * 97 * @param key must be a key defined over a curve using a prime order field. 98 * @throws GeneralSecurityException if the key is not valid. 99 */ checkPublicKey(ECPublicKey key)100 static void checkPublicKey(ECPublicKey key) throws GeneralSecurityException { 101 EllipticCurvesUtil.checkPointOnCurve(key.getW(), key.getParams().getCurve()); 102 } 103 104 /** Returns whether {@code spec} is a {@link ECParameterSpec} of one of the NIST curves. */ isNistEcParameterSpec(ECParameterSpec spec)105 public static boolean isNistEcParameterSpec(ECParameterSpec spec) { 106 return EllipticCurvesUtil.isNistEcParameterSpec(spec); 107 } 108 109 /** Returns whether {@code one} is the same {@link ECParameterSpec} as {@code two}. */ isSameEcParameterSpec(ECParameterSpec one, ECParameterSpec two)110 public static boolean isSameEcParameterSpec(ECParameterSpec one, ECParameterSpec two) { 111 return EllipticCurvesUtil.isSameEcParameterSpec(one, two); 112 } 113 114 /** 115 * Checks that the public key's params is the same as the private key's params, and the public key 116 * is a valid point on the private key's curve. 117 * 118 * @since 1.1.0 119 */ validatePublicKey(ECPublicKey publicKey, ECPrivateKey privateKey)120 public static void validatePublicKey(ECPublicKey publicKey, ECPrivateKey privateKey) 121 throws GeneralSecurityException { 122 validatePublicKeySpec(publicKey, privateKey); 123 EllipticCurvesUtil.checkPointOnCurve(publicKey.getW(), privateKey.getParams().getCurve()); 124 } 125 126 /** Checks that the public key's params spec is the same as the private key's params spec. */ validatePublicKeySpec(ECPublicKey publicKey, ECPrivateKey privateKey)127 static void validatePublicKeySpec(ECPublicKey publicKey, ECPrivateKey privateKey) 128 throws GeneralSecurityException { 129 try { 130 ECParameterSpec publicKeySpec = publicKey.getParams(); 131 ECParameterSpec privateKeySpec = privateKey.getParams(); 132 if (!isSameEcParameterSpec(publicKeySpec, privateKeySpec)) { 133 throw new GeneralSecurityException("invalid public key spec"); 134 } 135 } catch (IllegalArgumentException | NullPointerException ex) { 136 // The Java security providers on Android K and Android L might throw these unchecked 137 // exceptions, converting them to a checked one to not crash the JVM. 138 throw new GeneralSecurityException(ex); 139 } 140 } 141 142 /** 143 * Returns the modulus of the field used by the curve specified in ecParams. 144 * 145 * @param curve must be a prime order elliptic curve 146 * @return the order of the finite field over which curve is defined. 147 */ getModulus(EllipticCurve curve)148 public static BigInteger getModulus(EllipticCurve curve) throws GeneralSecurityException { 149 return EllipticCurvesUtil.getModulus(curve); 150 } 151 152 /** 153 * Returns the size of an element of the field over which the curve is defined. 154 * 155 * @param curve must be a prime order elliptic curve 156 * @return the size of an element in bits 157 */ fieldSizeInBits(EllipticCurve curve)158 public static int fieldSizeInBits(EllipticCurve curve) throws GeneralSecurityException { 159 return getModulus(curve).subtract(BigInteger.ONE).bitLength(); 160 } 161 162 /** 163 * Returns the size of an element of the field over which the curve is defined. 164 * 165 * @param curve must be a prime order elliptic curve 166 * @return the size of an element in bytes. 167 */ fieldSizeInBytes(EllipticCurve curve)168 public static int fieldSizeInBytes(EllipticCurve curve) throws GeneralSecurityException { 169 return (fieldSizeInBits(curve) + 7) / 8; 170 } 171 172 /** 173 * Computes a square root modulo an odd prime. Timing and exceptions can leak information about 174 * the inputs. Therefore this method must only be used to decompress public keys. 175 * 176 * @param x the square 177 * @param p the prime modulus (the behaviour of the method is undefined if p is not prime). 178 * @return a value s such that s^2 mod p == x mod p 179 * @throws GeneralSecurityException if the square root could not be found. 180 */ modSqrt(BigInteger x, BigInteger p)181 private static BigInteger modSqrt(BigInteger x, BigInteger p) throws GeneralSecurityException { 182 if (p.signum() != 1) { 183 throw new InvalidAlgorithmParameterException("p must be positive"); 184 } 185 x = x.mod(p); 186 BigInteger squareRoot = null; 187 // Special case for x == 0. 188 // This check is necessary for Cipolla's algorithm. 189 if (x.equals(BigInteger.ZERO)) { 190 return BigInteger.ZERO; 191 } 192 if (p.testBit(0) && p.testBit(1)) { 193 // Case p % 4 == 3 194 // q = (p + 1) / 4 195 BigInteger q = p.add(BigInteger.ONE).shiftRight(2); 196 squareRoot = x.modPow(q, p); 197 } else if (p.testBit(0) && !p.testBit(1)) { 198 // Case p % 4 == 1 199 // For this case we use Cipolla's algorithm. 200 // This alogorithm is preferrable to Tonelli-Shanks for primes p where p-1 is divisible by 201 // a large power of 2, which is a frequent choice since it simplifies modular reduction. 202 BigInteger a = BigInteger.ONE; 203 BigInteger d = null; 204 BigInteger q1 = p.subtract(BigInteger.ONE).shiftRight(1); 205 int tries = 0; 206 while (true) { 207 d = a.multiply(a).subtract(x).mod(p); 208 // Special case d==0. We need d!=0 below. 209 if (d.equals(BigInteger.ZERO)) { 210 return a; 211 } 212 // Computes the Legendre symbol. Using the Jacobi symbol would be a faster. 213 BigInteger t = d.modPow(q1, p); 214 if (t.add(BigInteger.ONE).equals(p)) { 215 // d is a quadratic non-residue. 216 break; 217 } else if (!t.equals(BigInteger.ONE)) { 218 // p does not divide d. Hence, t != 1 implies that p is not a prime. 219 throw new InvalidAlgorithmParameterException("p is not prime"); 220 } else { 221 a = a.add(BigInteger.ONE); 222 } 223 tries++; 224 // If 128 tries were not enough to find a quadratic non-residue, then it is likely that 225 // p is not prime. To avoid an infinite loop in this case we perform a primality test. 226 // If p is prime then this test will be done with a negligible probability of 2^{-128}. 227 if (tries == 128) { 228 if (!p.isProbablePrime(80)) { 229 throw new InvalidAlgorithmParameterException("p is not prime"); 230 } 231 } 232 } 233 // Since d = a^2 - x is a quadratic non-residue modulo p, we have 234 // a - sqrt(d) == (a + sqrt(d))^p (mod p), 235 // and hence 236 // x == (a + sqrt(d))(a - sqrt(d)) == (a + sqrt(d))^(p+1) (mod p). 237 // Thus if x is square then (a + sqrt(d))^((p+1)/2) (mod p) is a square root of x. 238 BigInteger q = p.add(BigInteger.ONE).shiftRight(1); 239 BigInteger u = a; 240 BigInteger v = BigInteger.ONE; 241 for (int bit = q.bitLength() - 2; bit >= 0; bit--) { 242 // Square u + v sqrt(d) and reduce mod p. 243 BigInteger tmp = u.multiply(v); 244 u = u.multiply(u).add(v.multiply(v).mod(p).multiply(d)).mod(p); 245 v = tmp.add(tmp).mod(p); 246 if (q.testBit(bit)) { 247 // Multiply u + v sqrt(d) by a + sqrt(d) and reduce mod p. 248 tmp = u.multiply(a).add(v.multiply(d)).mod(p); 249 v = a.multiply(v).add(u).mod(p); 250 u = tmp; 251 } 252 } 253 squareRoot = u; 254 } 255 // The methods used to compute the square root only guarantees a correct result if the 256 // preconditions (i.e. p prime and x is a square) are satisfied. Otherwise the value is 257 // undefined. Hence it is important to verify that squareRoot is indeed a square root. 258 if (squareRoot != null && squareRoot.multiply(squareRoot).mod(p).compareTo(x) != 0) { 259 throw new GeneralSecurityException("Could not find a modular square root"); 260 } 261 return squareRoot; 262 } 263 264 /** 265 * Computes the y coordinate of a point on an elliptic curve. This method can be used to 266 * decompress elliptic curve points. 267 * 268 * @param x the x-coordinate of the point 269 * @param lsb the least significant bit of the y-coordinate of the point. 270 * @param curve this must be an elliptic curve over a prime field using Weierstrass 271 * representation. 272 * @return the y coordinate. 273 * @throws GeneralSecurityException if there is no point with coordinate x on the curve, or if 274 * curve is not supported. 275 */ computeY(BigInteger x, boolean lsb, EllipticCurve curve)276 private static BigInteger computeY(BigInteger x, boolean lsb, EllipticCurve curve) 277 throws GeneralSecurityException { 278 BigInteger p = getModulus(curve); 279 BigInteger a = curve.getA(); 280 BigInteger b = curve.getB(); 281 BigInteger rhs = x.multiply(x).add(a).multiply(x).add(b).mod(p); 282 BigInteger y = modSqrt(rhs, p); 283 if (lsb != y.testBit(0)) { 284 y = p.subtract(y).mod(p); 285 } 286 return y; 287 } 288 289 /** 290 * Computes the y coordinate of a point on an elliptic curve. 291 * 292 * @deprecated This shouldn't be used directly, use {@link pointDecode} to decompress points. 293 */ 294 @Deprecated getY(BigInteger x, boolean lsb, EllipticCurve curve)295 public static BigInteger getY(BigInteger x, boolean lsb, EllipticCurve curve) 296 throws GeneralSecurityException { 297 return computeY(x, lsb, curve); 298 } 299 300 /** 301 * Transforms a big integer to its minimal signed form, i.e., no extra zero byte at the beginning 302 * except single one when the highest bit is set. 303 */ toMinimalSignedNumber(byte[] bs)304 private static byte[] toMinimalSignedNumber(byte[] bs) { 305 // Remove zero prefixes. 306 int start = 0; 307 while (start < bs.length && bs[start] == 0) { 308 start++; 309 } 310 if (start == bs.length) { 311 start = bs.length - 1; 312 } 313 314 int extraZero = 0; 315 // If the 1st bit is not zero, add 1 zero byte. 316 if ((bs[start] & 0x80) == 0x80) { 317 // Add extra zero. 318 extraZero = 1; 319 } 320 byte[] res = new byte[bs.length - start + extraZero]; 321 System.arraycopy(bs, start, res, extraZero, bs.length - start); 322 return res; 323 } 324 325 /** 326 * Transforms ECDSA IEEE_P1363 signature encoding to DER encoding. 327 * 328 * <p>The IEEE_P1363 signature's format is r || s, where r and s are zero-padded and have the same 329 * size in bytes as the order of the curve. For example, for NIST P-256 curve, r and s are 330 * zero-padded to 32 bytes. 331 * 332 * <p>The DER signature is encoded using ASN.1 (https://tools.ietf.org/html/rfc5480#appendix-A): 333 * ECDSA-Sig-Value :: = SEQUENCE { r INTEGER, s INTEGER }. In particular, the encoding is: 0x30 || 334 * totalLength || 0x02 || r's length || r || 0x02 || s's length || s. 335 * 336 * @param ieee ECDSA's signature in IEEE_P1363 format. 337 * @return ECDSA's signature in DER format. 338 * @throws GeneralSecurityException if ieee's length is zero, greater than 132-byte (corresponding 339 * to NIST P521) or not divisible by 2. 340 */ ecdsaIeee2Der(byte[] ieee)341 public static byte[] ecdsaIeee2Der(byte[] ieee) throws GeneralSecurityException { 342 if (ieee.length % 2 != 0 || ieee.length == 0 || ieee.length > 132) { 343 throw new GeneralSecurityException("Invalid IEEE_P1363 encoding"); 344 } 345 byte[] r = toMinimalSignedNumber(Arrays.copyOf(ieee, ieee.length / 2)); 346 byte[] s = toMinimalSignedNumber(Arrays.copyOfRange(ieee, ieee.length / 2, ieee.length)); 347 348 int offset = 0; 349 int length = 1 + 1 + r.length + 1 + 1 + s.length; 350 byte[] der; 351 if (length >= 128) { 352 der = new byte[length + 3]; 353 der[offset++] = (byte) 0x30; 354 der[offset++] = (byte) (0x80 + 0x01); 355 der[offset++] = (byte) length; 356 } else { 357 der = new byte[length + 2]; 358 der[offset++] = (byte) 0x30; 359 der[offset++] = (byte) length; 360 } 361 der[offset++] = (byte) 0x02; 362 der[offset++] = (byte) r.length; 363 System.arraycopy(r, 0, der, offset, r.length); 364 offset += r.length; 365 der[offset++] = (byte) 0x02; 366 der[offset++] = (byte) s.length; 367 System.arraycopy(s, 0, der, offset, s.length); 368 return der; 369 } 370 371 /** 372 * Transforms ECDSA DER signature encoding to IEEE_P1363 encoding. 373 * 374 * <p>The IEEE_P1363 signature's format is r || s, where r and s are zero-padded and have the same 375 * size in bytes as the order of the curve. For example, for NIST P-256 curve, r and s are 376 * zero-padded to 32 bytes. 377 * 378 * <p>The DER signature is encoded using ASN.1 (https://tools.ietf.org/html/rfc5480#appendix-A): 379 * ECDSA-Sig-Value :: = SEQUENCE { r INTEGER, s INTEGER }. In particular, the encoding is: 0x30 || 380 * totalLength || 0x02 || r's length || r || 0x02 || s's length || s. 381 * 382 * @param der ECDSA's signature in DER encoding. 383 * @param ieeeLength length of ECDSA signature's in IEEE_P1363's format which equals to 2 * (size 384 * of elliptic curve's field in bytes). 385 * @return ECDSA's signature in IEEE_P1363 format. 386 * @throws GeneralSecurityException if the signature is not valid DER encoding. 387 */ ecdsaDer2Ieee(byte[] der, int ieeeLength)388 public static byte[] ecdsaDer2Ieee(byte[] der, int ieeeLength) throws GeneralSecurityException { 389 if (!isValidDerEncoding(der)) { 390 throw new GeneralSecurityException("Invalid DER encoding"); 391 } 392 byte[] ieee = new byte[ieeeLength]; 393 int length = der[1] & 0xff; 394 int offset = 1 /* 0x30 */ + 1 /* totalLength */; 395 if (length >= 128) { 396 offset++; // Long form length 397 } 398 offset++; // 0x02 399 int rLength = der[offset++]; 400 int extraZero = 0; 401 if (der[offset] == 0) { 402 extraZero = 1; 403 } 404 System.arraycopy( 405 der, offset + extraZero, ieee, ieeeLength / 2 - rLength + extraZero, rLength - extraZero); 406 offset += rLength /* r byte array */ + 1 /* 0x02 */; 407 int sLength = der[offset++]; 408 extraZero = 0; 409 if (der[offset] == 0) { 410 extraZero = 1; 411 } 412 System.arraycopy( 413 der, offset + extraZero, ieee, ieeeLength - sLength + extraZero, sLength - extraZero); 414 return ieee; 415 } 416 417 // Validates that the signature is in DER encoding, based on 418 // https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki. isValidDerEncoding(final byte[] sig)419 public static boolean isValidDerEncoding(final byte[] sig) { 420 // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] 421 // * total-length: 1-byte or 2-byte length descriptor of everything that follows. 422 // * R-length: 1-byte length descriptor of the R value that follows. 423 // * R: arbitrary-length big-endian encoded R value. It must use the shortest 424 // possible encoding for a positive integers (which means no null bytes at 425 // the start, except a single one when the next byte has its highest bit set). 426 // * S-length: 1-byte length descriptor of the S value that follows. 427 // * S: arbitrary-length big-endian encoded S value. The same rules apply. 428 429 if (sig.length 430 < 1 /* 0x30 */ 431 + 1 /* total-length */ 432 + 1 /* 0x02 */ 433 + 1 /* R-length */ 434 + 1 /* R */ 435 + 1 /* 0x02 */ 436 + 1 /* S-length */ 437 + 1 /* S */) { 438 // Signature is too short. 439 return false; 440 } 441 442 // Checking bytes from left to right. 443 444 // byte #1: a signature is of type 0x30 (compound). 445 if (sig[0] != 0x30) { 446 return false; 447 } 448 449 // byte #2 and maybe #3: the total length of the signature. 450 int totalLen = sig[1] & 0xff; 451 int totalLenLen = 1; // the length of the total length field, could be 2-byte. 452 if (totalLen == 129) { 453 // The signature is >= 128 bytes thus total length field is in long-form encoding and occupies 454 // 2 bytes. 455 totalLenLen = 2; 456 // byte #3 is the total length. 457 totalLen = sig[2] & 0xff; 458 if (totalLen < 128) { 459 // Length in long-form encoding must be >= 128. 460 return false; 461 } 462 } else if (totalLen == 128 || totalLen > 129) { 463 // Impossible values for the second byte. 464 return false; 465 } 466 467 // Make sure the length covers the entire sig. 468 if (totalLen != sig.length - 1 - totalLenLen) { 469 return false; 470 } 471 472 // Start checking R. 473 // Check whether the R element is an integer. 474 if (sig[1 + totalLenLen] != 0x02) { 475 return false; 476 } 477 // Extract the length of the R element. 478 int rLen = sig[1 /* 0x30 */ + totalLenLen + 1 /* 0x02 */] & 0xff; 479 // Make sure the length of the S element is still inside the signature. 480 if (1 /* 0x30 */ + totalLenLen + 1 /* 0x02 */ + 1 /* rLen */ + rLen + 1 /* 0x02 */ 481 >= sig.length) { 482 return false; 483 } 484 // Zero-length integers are not allowed for R. 485 if (rLen == 0) { 486 return false; 487 } 488 // Negative numbers are not allowed for R. 489 if ((sig[3 + totalLenLen] & 0xff) >= 128) { 490 return false; 491 } 492 // Null bytes at the start of R are not allowed, unless R would 493 // otherwise be interpreted as a negative number. 494 if (rLen > 1 && (sig[3 + totalLenLen] == 0x00) && ((sig[4 + totalLenLen] & 0xff) < 128)) { 495 return false; 496 } 497 498 // Start checking S. 499 // Check whether the S element is an integer. 500 if (sig[3 + totalLenLen + rLen] != 0x02) { 501 return false; 502 } 503 // Extract the length of the S element. 504 int sLen = 505 sig[1 /* 0x30 */ + totalLenLen + 1 /* 0x02 */ + 1 /* rLen */ + rLen + 1 /* 0x02 */] & 0xff; 506 // Verify that the length of the signature matches the sum of the length of the elements. 507 if (1 /* 0x30 */ 508 + totalLenLen 509 + 1 /* 0x02 */ 510 + 1 /* rLen */ 511 + rLen 512 + 1 /* 0x02 */ 513 + 1 /* sLen */ 514 + sLen 515 != sig.length) { 516 return false; 517 } 518 // Zero-length integers are not allowed for S. 519 if (sLen == 0) { 520 return false; 521 } 522 // Negative numbers are not allowed for S. 523 if ((sig[5 + totalLenLen + rLen] & 0xff) >= 128) { 524 return false; 525 } 526 // Null bytes at the start of S are not allowed, unless S would 527 // otherwise be interpreted as a negative number. 528 if (sLen > 1 529 && (sig[5 + totalLenLen + rLen] == 0x00) 530 && ((sig[6 + totalLenLen + rLen] & 0xff) < 128)) { 531 return false; 532 } 533 534 return true; 535 } 536 537 /** 538 * Returns the encoding size of a point on an elliptic curve. 539 * 540 * @param curve the elliptic curve 541 * @param format the format used to encode the point 542 * @return the size of an encoded point in bytes 543 * @throws GeneralSecurityException if the point format is unknown or if the elliptic curve is not 544 * supported 545 */ encodingSizeInBytes(EllipticCurve curve, PointFormatType format)546 public static int encodingSizeInBytes(EllipticCurve curve, PointFormatType format) 547 throws GeneralSecurityException { 548 int coordinateSize = fieldSizeInBytes(curve); 549 switch (format) { 550 case UNCOMPRESSED: 551 return 2 * coordinateSize + 1; 552 case DO_NOT_USE_CRUNCHY_UNCOMPRESSED: 553 return 2 * coordinateSize; 554 case COMPRESSED: 555 return coordinateSize + 1; 556 } 557 throw new GeneralSecurityException("unknown EC point format"); 558 } 559 560 /** 561 * Decodes an encoded point on an elliptic curve. This method checks that the encoded point is on 562 * the curve. 563 * 564 * @param curve the elliptic curve 565 * @param format the format used to enocde the point 566 * @param encoded the encoded point 567 * @return the point 568 * @throws GeneralSecurityException if the encoded point is invalid or if the curve or format are 569 * not supported. 570 */ ecPointDecode(EllipticCurve curve, PointFormatType format, byte[] encoded)571 public static ECPoint ecPointDecode(EllipticCurve curve, PointFormatType format, byte[] encoded) 572 throws GeneralSecurityException { 573 return pointDecode(curve, format, encoded); 574 } 575 576 /** 577 * Decodes an encoded point on an elliptic curve. This method checks that the encoded point is on 578 * the curve. 579 * 580 * @param curveType the elliptic curve 581 * @param format the format used to enocde the point 582 * @param encoded the encoded point 583 * @return the point 584 * @throws GeneralSecurityException if the encoded point is invalid or if the curve or format are 585 * not supported. 586 * @since 1.1.0 587 */ pointDecode(CurveType curveType, PointFormatType format, byte[] encoded)588 public static ECPoint pointDecode(CurveType curveType, PointFormatType format, byte[] encoded) 589 throws GeneralSecurityException { 590 return pointDecode(getCurveSpec(curveType).getCurve(), format, encoded); 591 } 592 593 /** 594 * Decodes an encoded point on an elliptic curve. This method checks that the encoded point is on 595 * the curve. 596 * 597 * @param curve the elliptic curve 598 * @param format the format used to enocde the point 599 * @param encoded the encoded point 600 * @return the point 601 * @throws GeneralSecurityException if the encoded point is invalid or if the curve or format are 602 * not supported. 603 * @since 1.1.0 604 */ pointDecode(EllipticCurve curve, PointFormatType format, byte[] encoded)605 public static ECPoint pointDecode(EllipticCurve curve, PointFormatType format, byte[] encoded) 606 throws GeneralSecurityException { 607 int coordinateSize = fieldSizeInBytes(curve); 608 switch (format) { 609 case UNCOMPRESSED: 610 { 611 if (encoded.length != 2 * coordinateSize + 1) { 612 throw new GeneralSecurityException("invalid point size"); 613 } 614 if (encoded[0] != 4) { 615 throw new GeneralSecurityException("invalid point format"); 616 } 617 BigInteger x = new BigInteger(1, Arrays.copyOfRange(encoded, 1, coordinateSize + 1)); 618 BigInteger y = 619 new BigInteger(1, Arrays.copyOfRange(encoded, coordinateSize + 1, encoded.length)); 620 ECPoint point = new ECPoint(x, y); 621 EllipticCurvesUtil.checkPointOnCurve(point, curve); 622 return point; 623 } 624 case DO_NOT_USE_CRUNCHY_UNCOMPRESSED: 625 { 626 if (encoded.length != 2 * coordinateSize) { 627 throw new GeneralSecurityException("invalid point size"); 628 } 629 BigInteger x = new BigInteger(1, Arrays.copyOf(encoded, coordinateSize)); 630 BigInteger y = 631 new BigInteger(1, Arrays.copyOfRange(encoded, coordinateSize, encoded.length)); 632 ECPoint point = new ECPoint(x, y); 633 EllipticCurvesUtil.checkPointOnCurve(point, curve); 634 return point; 635 } 636 case COMPRESSED: 637 { 638 BigInteger p = getModulus(curve); 639 if (encoded.length != coordinateSize + 1) { 640 throw new GeneralSecurityException("compressed point has wrong length"); 641 } 642 boolean lsb; 643 if (encoded[0] == 2) { 644 lsb = false; 645 } else if (encoded[0] == 3) { 646 lsb = true; 647 } else { 648 throw new GeneralSecurityException("invalid format"); 649 } 650 BigInteger x = new BigInteger(1, Arrays.copyOfRange(encoded, 1, encoded.length)); 651 if (x.signum() == -1 || x.compareTo(p) >= 0) { 652 throw new GeneralSecurityException("x is out of range"); 653 } 654 BigInteger y = computeY(x, lsb, curve); 655 return new ECPoint(x, y); 656 } 657 } 658 throw new GeneralSecurityException("invalid format:" + format); 659 } 660 661 /** 662 * Encodes a point on an elliptic curve. 663 * 664 * @param curveType the elliptic curve 665 * @param format the format for the encoding 666 * @param point the point to encode 667 * @return the encoded key exchange 668 * @throws GeneralSecurityException if the point is not on the curve or if the format is not 669 * supported. 670 * @since 1.1.0 671 */ pointEncode(CurveType curveType, PointFormatType format, ECPoint point)672 public static byte[] pointEncode(CurveType curveType, PointFormatType format, ECPoint point) 673 throws GeneralSecurityException { 674 return pointEncode(getCurveSpec(curveType).getCurve(), format, point); 675 } 676 677 /** 678 * Encodes a point on an elliptic curve. 679 * 680 * @param curve the elliptic curve 681 * @param format the format for the encoding 682 * @param point the point to encode 683 * @return the encoded key exchange 684 * @throws GeneralSecurityException if the point is not on the curve or if the format is not 685 * supported. 686 * @since 1.1.0 687 */ pointEncode(EllipticCurve curve, PointFormatType format, ECPoint point)688 public static byte[] pointEncode(EllipticCurve curve, PointFormatType format, ECPoint point) 689 throws GeneralSecurityException { 690 EllipticCurvesUtil.checkPointOnCurve(point, curve); 691 int coordinateSize = fieldSizeInBytes(curve); 692 switch (format) { 693 case UNCOMPRESSED: 694 { 695 byte[] encoded = new byte[2 * coordinateSize + 1]; 696 byte[] x = BigIntegerEncoding.toBigEndianBytes(point.getAffineX()); 697 byte[] y = BigIntegerEncoding.toBigEndianBytes(point.getAffineY()); 698 // Order of System.arraycopy is important because x,y can have leading 0's. 699 System.arraycopy(y, 0, encoded, 1 + 2 * coordinateSize - y.length, y.length); 700 System.arraycopy(x, 0, encoded, 1 + coordinateSize - x.length, x.length); 701 encoded[0] = 4; 702 return encoded; 703 } 704 case DO_NOT_USE_CRUNCHY_UNCOMPRESSED: 705 { 706 byte[] encoded = new byte[2 * coordinateSize]; 707 byte[] x = BigIntegerEncoding.toBigEndianBytes(point.getAffineX()); 708 if (x.length > coordinateSize) { 709 // x has leading 0's, strip them. 710 x = Arrays.copyOfRange(x, x.length - coordinateSize, x.length); 711 } 712 byte[] y = BigIntegerEncoding.toBigEndianBytes(point.getAffineY()); 713 if (y.length > coordinateSize) { 714 // y has leading 0's, strip them. 715 y = Arrays.copyOfRange(y, y.length - coordinateSize, y.length); 716 } 717 System.arraycopy(y, 0, encoded, 2 * coordinateSize - y.length, y.length); 718 System.arraycopy(x, 0, encoded, coordinateSize - x.length, x.length); 719 return encoded; 720 } 721 case COMPRESSED: 722 { 723 byte[] encoded = new byte[coordinateSize + 1]; 724 byte[] x = BigIntegerEncoding.toBigEndianBytes(point.getAffineX()); 725 System.arraycopy(x, 0, encoded, 1 + coordinateSize - x.length, x.length); 726 encoded[0] = (byte) (point.getAffineY().testBit(0) ? 3 : 2); 727 return encoded; 728 } 729 } 730 throw new GeneralSecurityException("invalid format:" + format); 731 } 732 733 /** 734 * Returns the ECParameterSpec for a named curve. 735 * 736 * @param curve the curve type 737 * @return the ECParameterSpec for the curve. 738 */ getCurveSpec(CurveType curve)739 public static ECParameterSpec getCurveSpec(CurveType curve) throws NoSuchAlgorithmException { 740 switch (curve) { 741 case NIST_P256: 742 return getNistP256Params(); 743 case NIST_P384: 744 return getNistP384Params(); 745 case NIST_P521: 746 return getNistP521Params(); 747 } 748 throw new NoSuchAlgorithmException("curve not implemented:" + curve); 749 } 750 751 /** 752 * Returns an {@link ECPublicKey} from {@code x509PublicKey} which is an encoding of a public key, 753 * encoded according to the ASN.1 type SubjectPublicKeyInfo. 754 * 755 * <p>TODO(b/68672497): test that in Java one can always get this representation by using {@link 756 * ECPublicKey#getEncoded}, regardless of the provider. 757 */ getEcPublicKey(final byte[] x509PublicKey)758 public static ECPublicKey getEcPublicKey(final byte[] x509PublicKey) 759 throws GeneralSecurityException { 760 KeyFactory kf = EngineFactory.KEY_FACTORY.getInstance("EC"); 761 return (ECPublicKey) kf.generatePublic(new X509EncodedKeySpec(x509PublicKey)); 762 } 763 764 /** 765 * Returns an {@link ECPublicKey} from {@code publicKey} that is a public key in point format 766 * {@code pointFormat} on {@code curve}. 767 */ getEcPublicKey( CurveType curve, PointFormatType pointFormat, final byte[] publicKey)768 public static ECPublicKey getEcPublicKey( 769 CurveType curve, PointFormatType pointFormat, final byte[] publicKey) 770 throws GeneralSecurityException { 771 return getEcPublicKey(getCurveSpec(curve), pointFormat, publicKey); 772 } 773 774 /** 775 * Returns an {@link ECPublicKey} from {@code publicKey} that is a public key in point format 776 * {@code pointFormat} on {@code curve}. 777 */ getEcPublicKey( ECParameterSpec spec, PointFormatType pointFormat, final byte[] publicKey)778 public static ECPublicKey getEcPublicKey( 779 ECParameterSpec spec, PointFormatType pointFormat, final byte[] publicKey) 780 throws GeneralSecurityException { 781 ECPoint point = pointDecode(spec.getCurve(), pointFormat, publicKey); 782 ECPublicKeySpec pubSpec = new ECPublicKeySpec(point, spec); 783 KeyFactory kf = EngineFactory.KEY_FACTORY.getInstance("EC"); 784 return (ECPublicKey) kf.generatePublic(pubSpec); 785 } 786 787 /** 788 * Returns an {@code ECPublicKey} from {@code curve} type and {@code x} and {@code y} coordinates. 789 */ getEcPublicKey(CurveType curve, final byte[] x, final byte[] y)790 public static ECPublicKey getEcPublicKey(CurveType curve, final byte[] x, final byte[] y) 791 throws GeneralSecurityException { 792 ECParameterSpec ecParams = getCurveSpec(curve); 793 BigInteger pubX = new BigInteger(1, x); 794 BigInteger pubY = new BigInteger(1, y); 795 ECPoint w = new ECPoint(pubX, pubY); 796 EllipticCurvesUtil.checkPointOnCurve(w, ecParams.getCurve()); 797 ECPublicKeySpec spec = new ECPublicKeySpec(w, ecParams); 798 KeyFactory kf = EngineFactory.KEY_FACTORY.getInstance("EC"); 799 return (ECPublicKey) kf.generatePublic(spec); 800 } 801 802 /** 803 * Returns an {@code ECPrivateKey} from {@code pkcs8PrivateKey} which is an encoding of a private 804 * key, encoded according to the ASN.1 type SubjectPublicKeyInfo. 805 * 806 * <p>TODO(b/68672497): test that in Java one can always get this representation by using {@link 807 * ECPrivateKey#getEncoded}, regardless of the provider. 808 */ getEcPrivateKey(final byte[] pkcs8PrivateKey)809 public static ECPrivateKey getEcPrivateKey(final byte[] pkcs8PrivateKey) 810 throws GeneralSecurityException { 811 KeyFactory kf = EngineFactory.KEY_FACTORY.getInstance("EC"); 812 return (ECPrivateKey) kf.generatePrivate(new PKCS8EncodedKeySpec(pkcs8PrivateKey)); 813 } 814 815 /** Returns an {@code ECPrivateKey} from {@code curve} type and {@code keyValue}. */ getEcPrivateKey(CurveType curve, final byte[] keyValue)816 public static ECPrivateKey getEcPrivateKey(CurveType curve, final byte[] keyValue) 817 throws GeneralSecurityException { 818 ECParameterSpec ecParams = getCurveSpec(curve); 819 BigInteger privValue = BigIntegerEncoding.fromUnsignedBigEndianBytes(keyValue); 820 ECPrivateKeySpec spec = new ECPrivateKeySpec(privValue, ecParams); 821 KeyFactory kf = EngineFactory.KEY_FACTORY.getInstance("EC"); 822 return (ECPrivateKey) kf.generatePrivate(spec); 823 } 824 825 /** Generates a new key pair for {@code curve}. */ generateKeyPair(CurveType curve)826 public static KeyPair generateKeyPair(CurveType curve) throws GeneralSecurityException { 827 return generateKeyPair(getCurveSpec(curve)); 828 } 829 830 /** Generates a new key pair for {@code spec}. */ generateKeyPair(ECParameterSpec spec)831 public static KeyPair generateKeyPair(ECParameterSpec spec) throws GeneralSecurityException { 832 KeyPairGenerator keyGen = EngineFactory.KEY_PAIR_GENERATOR.getInstance("EC"); 833 keyGen.initialize(spec); 834 return keyGen.generateKeyPair(); 835 } 836 837 /** 838 * Basic validation of the shared secret. 839 * 840 * <p>Checks that there exists a point on the curve of {@code privateKey} that has {@code secret} 841 * as x coordinate. This validation gives very limited protection against arithmetic errors 842 * or fault attacks. 843 * 844 * <p>Only visible for testing. 845 */ validateSharedSecret(byte[] secret, ECPrivateKey privateKey)846 static void validateSharedSecret(byte[] secret, ECPrivateKey privateKey) 847 throws GeneralSecurityException { 848 EllipticCurve privateKeyCurve = privateKey.getParams().getCurve(); 849 BigInteger x = new BigInteger(1, secret); 850 if (x.signum() == -1 || x.compareTo(getModulus(privateKeyCurve)) >= 0) { 851 throw new GeneralSecurityException("shared secret is out of range"); 852 } 853 // This will throw if x is not a valid coordinate. 854 Object unused = computeY(x, true /* lsb, doesn't matter here */, privateKeyCurve); 855 } 856 857 /* Generates the DH shared secret using {@code myPrivateKey} and {@code peerPublicKey} */ computeSharedSecret(ECPrivateKey myPrivateKey, ECPublicKey peerPublicKey)858 public static byte[] computeSharedSecret(ECPrivateKey myPrivateKey, ECPublicKey peerPublicKey) 859 throws GeneralSecurityException { 860 validatePublicKeySpec(peerPublicKey, myPrivateKey); 861 return computeSharedSecret(myPrivateKey, peerPublicKey.getW()); 862 } 863 864 /** 865 * Generates the DH shared secret using {@code myPrivateKey} and {@code publicPoint} 866 * 867 * @since 1.1.0 868 */ computeSharedSecret(ECPrivateKey myPrivateKey, ECPoint publicPoint)869 public static byte[] computeSharedSecret(ECPrivateKey myPrivateKey, ECPoint publicPoint) 870 throws GeneralSecurityException { 871 EllipticCurvesUtil.checkPointOnCurve(publicPoint, myPrivateKey.getParams().getCurve()); 872 // Explicitly reconstruct the peer public key using private key's spec. 873 ECParameterSpec privSpec = myPrivateKey.getParams(); 874 ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(publicPoint, privSpec); 875 KeyFactory kf = EngineFactory.KEY_FACTORY.getInstance("EC"); 876 PublicKey publicKey = kf.generatePublic(publicKeySpec); 877 KeyAgreement ka = EngineFactory.KEY_AGREEMENT.getInstance("ECDH"); 878 ka.init(myPrivateKey); 879 try { 880 ka.doPhase(publicKey, /* lastPhase= */ true); 881 byte[] secret = ka.generateSecret(); 882 validateSharedSecret(secret, myPrivateKey); 883 return secret; 884 } catch (IllegalStateException ex) { 885 // Due to CVE-2017-10176 some versions of OpenJDK might throw this unchecked exception, 886 // converting it to a checked one to not crash the JVM. See also b/73760761. 887 throw new GeneralSecurityException(ex); 888 } 889 } 890 EllipticCurves()891 private EllipticCurves() {} 892 } 893