1 /** 2 * @license 3 * Copyright 2016 Google Inc. All rights reserved. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.security.wycheproof; 18 19 import java.math.BigInteger; 20 import java.security.AlgorithmParameters; 21 import java.security.GeneralSecurityException; 22 import java.security.KeyPair; 23 import java.security.KeyPairGenerator; 24 import java.security.NoSuchAlgorithmException; 25 import java.security.interfaces.ECPublicKey; 26 import java.security.spec.ECField; 27 import java.security.spec.ECFieldFp; 28 import java.security.spec.ECGenParameterSpec; 29 import java.security.spec.ECParameterSpec; 30 import java.security.spec.ECPoint; 31 import java.security.spec.ECPublicKeySpec; 32 import java.security.spec.EllipticCurve; 33 import java.security.spec.InvalidParameterSpecException; 34 import java.util.Arrays; 35 36 /** 37 * Some utilities for testing Elliptic curve crypto. This code is for testing only and hasn't been 38 * reviewed for production. 39 */ 40 public class EcUtil { 41 /** 42 * Returns the ECParameterSpec for a named curve. Not every provider implements the 43 * AlgorithmParameters. Therefore, most test use alternative functions. 44 */ getCurveSpec(String name)45 public static ECParameterSpec getCurveSpec(String name) 46 throws NoSuchAlgorithmException, InvalidParameterSpecException { 47 AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC"); 48 parameters.init(new ECGenParameterSpec(name)); 49 return parameters.getParameterSpec(ECParameterSpec.class); 50 } 51 52 /** 53 * Returns the ECParameterSpec for a named curve. Only a handful curves that are used in the tests 54 * are implemented. 55 */ getCurveSpecRef(String name)56 public static ECParameterSpec getCurveSpecRef(String name) throws NoSuchAlgorithmException { 57 if (name.equals("secp224r1")) { 58 return getNistP224Params(); 59 } else if (name.equals("secp256r1")) { 60 return getNistP256Params(); 61 } else if (name.equals("secp384r1")) { 62 return getNistP384Params(); 63 } else if (name.equals("secp521r1")) { 64 return getNistP521Params(); 65 } else if (name.equals("brainpoolp256r1")) { 66 return getBrainpoolP256r1Params(); 67 } else { 68 throw new NoSuchAlgorithmException("Curve not implemented:" + name); 69 } 70 } 71 getNistCurveSpec( String decimalP, String decimalN, String hexB, String hexGX, String hexGY)72 public static ECParameterSpec getNistCurveSpec( 73 String decimalP, String decimalN, String hexB, String hexGX, String hexGY) { 74 final BigInteger p = new BigInteger(decimalP); 75 final BigInteger n = new BigInteger(decimalN); 76 final BigInteger three = new BigInteger("3"); 77 final BigInteger a = p.subtract(three); 78 final BigInteger b = new BigInteger(hexB, 16); 79 final BigInteger gx = new BigInteger(hexGX, 16); 80 final BigInteger gy = new BigInteger(hexGY, 16); 81 final int h = 1; 82 ECFieldFp fp = new ECFieldFp(p); 83 java.security.spec.EllipticCurve curveSpec = new java.security.spec.EllipticCurve(fp, a, b); 84 ECPoint g = new ECPoint(gx, gy); 85 ECParameterSpec ecSpec = new ECParameterSpec(curveSpec, g, n, h); 86 return ecSpec; 87 } 88 getNistP224Params()89 public static ECParameterSpec getNistP224Params() { 90 return getNistCurveSpec( 91 "26959946667150639794667015087019630673557916260026308143510066298881", 92 "26959946667150639794667015087019625940457807714424391721682722368061", 93 "b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 94 "b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", 95 "bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"); 96 } 97 getNistP256Params()98 public static ECParameterSpec getNistP256Params() { 99 return getNistCurveSpec( 100 "115792089210356248762697446949407573530086143415290314195533631308867097853951", 101 "115792089210356248762697446949407573529996955224135760342422259061068512044369", 102 "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 103 "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 104 "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"); 105 } 106 getNistP384Params()107 public static ECParameterSpec getNistP384Params() { 108 return getNistCurveSpec( 109 "3940200619639447921227904010014361380507973927046544666794829340" 110 + "4245721771496870329047266088258938001861606973112319", 111 "3940200619639447921227904010014361380507973927046544666794690527" 112 + "9627659399113263569398956308152294913554433653942643", 113 "b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a" 114 + "c656398d8a2ed19d2a85c8edd3ec2aef", 115 "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38" 116 + "5502f25dbf55296c3a545e3872760ab7", 117 "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0" 118 + "0a60b1ce1d7e819d7a431d7c90ea0e5f"); 119 } 120 getNistP521Params()121 public static ECParameterSpec getNistP521Params() { 122 return getNistCurveSpec( 123 "6864797660130609714981900799081393217269435300143305409394463459" 124 + "18554318339765605212255964066145455497729631139148085803712198" 125 + "7999716643812574028291115057151", 126 "6864797660130609714981900799081393217269435300143305409394463459" 127 + "18554318339765539424505774633321719753296399637136332111386476" 128 + "8612440380340372808892707005449", 129 "051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10" 130 + "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 131 "c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3d" 132 + "baa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", 133 "11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e6" 134 + "62c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"); 135 } 136 getBrainpoolP256r1Params()137 public static ECParameterSpec getBrainpoolP256r1Params() { 138 BigInteger p = 139 new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16); 140 BigInteger a = 141 new BigInteger("7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", 16); 142 BigInteger b = 143 new BigInteger("26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", 16); 144 BigInteger x = 145 new BigInteger("8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262", 16); 146 BigInteger y = 147 new BigInteger("547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", 16); 148 BigInteger n = 149 new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16); 150 final int h = 1; 151 ECFieldFp fp = new ECFieldFp(p); 152 EllipticCurve curve = new EllipticCurve(fp, a, b); 153 ECPoint g = new ECPoint(x, y); 154 return new ECParameterSpec(curve, g, n, h); 155 } 156 157 /** 158 * Compute the Legendre symbol of x mod p. This implementation is slow. Faster would be the 159 * computation for the Jacobi symbol. 160 * 161 * @param x an integer 162 * @param p a prime modulus 163 * @returns 1 if x is a quadratic residue, -1 if x is a non-quadratic residue and 0 if x and p are 164 * not coprime. 165 * @throws GeneralSecurityException when the computation shows that p is not prime. 166 */ legendre(BigInteger x, BigInteger p)167 public static int legendre(BigInteger x, BigInteger p) throws GeneralSecurityException { 168 BigInteger q = p.subtract(BigInteger.ONE).shiftRight(1); 169 BigInteger t = x.modPow(q, p); 170 if (t.equals(BigInteger.ONE)) { 171 return 1; 172 } else if (t.equals(BigInteger.ZERO)) { 173 return 0; 174 } else if (t.add(BigInteger.ONE).equals(p)) { 175 return -1; 176 } else { 177 throw new GeneralSecurityException("p is not prime"); 178 } 179 } 180 181 /** 182 * Computes a modular square root. Timing and exceptions can leak information about the inputs. 183 * Therefore this method must only be used in tests. 184 * 185 * @param x the square 186 * @param p the prime modulus 187 * @returns a value s such that s^2 mod p == x mod p 188 * @throws GeneralSecurityException if the square root could not be found. 189 */ modSqrt(BigInteger x, BigInteger p)190 public static BigInteger modSqrt(BigInteger x, BigInteger p) throws GeneralSecurityException { 191 if (p.signum() != 1) { 192 throw new GeneralSecurityException("p must be positive"); 193 } 194 x = x.mod(p); 195 BigInteger squareRoot = null; 196 // Special case for x == 0. 197 // This check is necessary for Cipolla's algorithm. 198 if (x.equals(BigInteger.ZERO)) { 199 return x; 200 } 201 if (p.testBit(0) && p.testBit(1)) { 202 // Case p % 4 == 3 203 // q = (p + 1) / 4 204 BigInteger q = p.add(BigInteger.ONE).shiftRight(2); 205 squareRoot = x.modPow(q, p); 206 } else if (p.testBit(0) && !p.testBit(1)) { 207 // Case p % 4 == 1 208 // For this case we use Cipolla's algorithm. 209 // This alogorithm is preferrable to Tonelli-Shanks for primes p where p-1 is divisible by 210 // a large power of 2, which is a frequent choice since it simplifies modular reduction. 211 BigInteger a = BigInteger.ONE; 212 BigInteger d = null; 213 while (true) { 214 d = a.multiply(a).subtract(x).mod(p); 215 // Computes the Legendre symbol. Using the Jacobi symbol would be a faster. Using Legendre 216 // has the advantage, that it detects a non prime p with high probability. 217 // On the other hand if p = q^2 then the Jacobi (d/p)==1 for almost all d's and thus 218 // using the Jacobi symbol here can result in an endless loop with invalid inputs. 219 int t = legendre(d, p); 220 if (t == -1) { 221 break; 222 } else { 223 a = a.add(BigInteger.ONE); 224 } 225 } 226 // Since d = a^2 - n is a non-residue modulo p, we have 227 // a - sqrt(d) == (a+sqrt(d))^p (mod p), 228 // and hence 229 // n == (a + sqrt(d))(a - sqrt(d) == (a+sqrt(d))^(p+1) (mod p). 230 // Thus if n is square then (a+sqrt(d))^((p+1)/2) (mod p) is a square root of n. 231 BigInteger q = p.add(BigInteger.ONE).shiftRight(1); 232 BigInteger u = a; 233 BigInteger v = BigInteger.ONE; 234 for (int bit = q.bitLength() - 2; bit >= 0; bit--) { 235 // Compute (u + v sqrt(d))^2 236 BigInteger tmp = u.multiply(v); 237 u = u.multiply(u).add(v.multiply(v).mod(p).multiply(d)).mod(p); 238 v = tmp.add(tmp).mod(p); 239 if (q.testBit(bit)) { 240 tmp = u.multiply(a).add(v.multiply(d)).mod(p); 241 v = a.multiply(v).add(u).mod(p); 242 u = tmp; 243 } 244 } 245 squareRoot = u; 246 } 247 // The methods used to compute the square root only guarantee a correct result if the 248 // preconditions (i.e. p prime and x is a square) are satisfied. Otherwise the value is 249 // undefined. Hence, it is important to verify that squareRoot is indeed a square root. 250 if (squareRoot != null && squareRoot.multiply(squareRoot).mod(p).compareTo(x) != 0) { 251 throw new GeneralSecurityException("Could not find square root"); 252 } 253 return squareRoot; 254 } 255 256 /** 257 * Returns the modulus of the field used by the curve specified in ecParams. 258 * 259 * @param curve must be a prime order elliptic curve 260 * @return the order of the finite field over which curve is defined. 261 */ getModulus(EllipticCurve curve)262 public static BigInteger getModulus(EllipticCurve curve) throws GeneralSecurityException { 263 java.security.spec.ECField field = curve.getField(); 264 if (field instanceof java.security.spec.ECFieldFp) { 265 return ((java.security.spec.ECFieldFp) field).getP(); 266 } else { 267 throw new GeneralSecurityException("Only curves over prime order fields are supported"); 268 } 269 } 270 271 /** 272 * Returns the size of an element of the field over which the curve is defined. 273 * 274 * @param curve must be a prime order elliptic curve 275 * @return the size of an element in bits 276 */ fieldSizeInBits(EllipticCurve curve)277 public static int fieldSizeInBits(EllipticCurve curve) throws GeneralSecurityException { 278 return getModulus(curve).subtract(BigInteger.ONE).bitLength(); 279 } 280 281 /** 282 * Returns the size of an element of the field over which the curve is defined. 283 * 284 * @param curve must be a prime order elliptic curve 285 * @return the size of an element in bytes. 286 */ fieldSizeInBytes(EllipticCurve curve)287 public static int fieldSizeInBytes(EllipticCurve curve) throws GeneralSecurityException { 288 return (fieldSizeInBits(curve) + 7) / 8; 289 } 290 291 /** 292 * Checks that a point is on a given elliptic curve. This method implements the partial public key 293 * validation routine from Section 5.6.2.6 of NIST SP 800-56A 294 * http://csrc.nist.gov/publications/nistpubs/800-56A/SP800-56A_Revision1_Mar08-2007.pdf A partial 295 * public key validation is sufficient for curves with cofactor 1. See Section B.3 of 296 * http://www.nsa.gov/ia/_files/SuiteB_Implementer_G-113808.pdf The point validations above are 297 * taken from recommendations for ECDH, because parameter checks in ECDH are much more important 298 * than for the case of ECDSA. Performing this test for ECDSA keys is mainly a sanity check. 299 * 300 * @param point the point that needs verification 301 * @param ec the elliptic curve. This must be a curve over a prime order field. 302 * @throws GeneralSecurityException if the field is binary or if the point is not on the curve. 303 */ checkPointOnCurve(ECPoint point, EllipticCurve ec)304 public static void checkPointOnCurve(ECPoint point, EllipticCurve ec) 305 throws GeneralSecurityException { 306 BigInteger p = getModulus(ec); 307 BigInteger x = point.getAffineX(); 308 BigInteger y = point.getAffineY(); 309 if (x == null || y == null) { 310 throw new GeneralSecurityException("point is at infinity"); 311 } 312 // Check 0 <= x < p and 0 <= y < p. 313 if (x.signum() == -1 || x.compareTo(p) != -1) { 314 throw new GeneralSecurityException("x is out of range"); 315 } 316 if (y.signum() == -1 || y.compareTo(p) != -1) { 317 throw new GeneralSecurityException("y is out of range"); 318 } 319 // Check y^2 == x^3 + a x + b (mod p) 320 BigInteger lhs = y.multiply(y).mod(p); 321 BigInteger rhs = x.multiply(x).add(ec.getA()).multiply(x).add(ec.getB()).mod(p); 322 if (!lhs.equals(rhs)) { 323 throw new GeneralSecurityException("Point is not on curve"); 324 } 325 } 326 327 /** 328 * Checks a public key. I.e. this checks that the point defining the public key is on the curve. 329 * 330 * @param key must be a key defined over a curve using a prime order field. 331 * @throws GeneralSecurityException if the key is not valid. 332 */ checkPublicKey(ECPublicKey key)333 public static void checkPublicKey(ECPublicKey key) throws GeneralSecurityException { 334 checkPointOnCurve(key.getW(), key.getParams().getCurve()); 335 } 336 337 /** 338 * Decompress a point 339 * 340 * @param x The x-coordinate of the point 341 * @param bit0 true if the least significant bit of y is set. 342 * @param ecParams contains the curve of the point. This must be over a prime order field. 343 */ getPoint(BigInteger x, boolean bit0, ECParameterSpec ecParams)344 public static ECPoint getPoint(BigInteger x, boolean bit0, ECParameterSpec ecParams) 345 throws GeneralSecurityException { 346 EllipticCurve ec = ecParams.getCurve(); 347 ECField field = ec.getField(); 348 if (!(field instanceof ECFieldFp)) { 349 throw new GeneralSecurityException("Only curves over prime order fields are supported"); 350 } 351 BigInteger p = ((java.security.spec.ECFieldFp) field).getP(); 352 if (x.compareTo(BigInteger.ZERO) == -1 || x.compareTo(p) != -1) { 353 throw new GeneralSecurityException("x is out of range"); 354 } 355 // Compute rhs == x^3 + a x + b (mod p) 356 BigInteger rhs = x.multiply(x).add(ec.getA()).multiply(x).add(ec.getB()).mod(p); 357 BigInteger y = modSqrt(rhs, p); 358 if (bit0 != y.testBit(0)) { 359 y = p.subtract(y).mod(p); 360 } 361 return new ECPoint(x, y); 362 } 363 364 /** 365 * Decompress a point on an elliptic curve. 366 * 367 * @param bytes The compressed point. Its representation is z || x where z is 2+lsb(y) and x is 368 * using a unsigned fixed length big-endian representation. 369 * @param ecParams the specification of the curve. Only Weierstrass curves over prime order fields 370 * are implemented. 371 */ decompressPoint(byte[] bytes, ECParameterSpec ecParams)372 public static ECPoint decompressPoint(byte[] bytes, ECParameterSpec ecParams) 373 throws GeneralSecurityException { 374 EllipticCurve ec = ecParams.getCurve(); 375 ECField field = ec.getField(); 376 if (!(field instanceof ECFieldFp)) { 377 throw new GeneralSecurityException("Only curves over prime order fields are supported"); 378 } 379 BigInteger p = ((java.security.spec.ECFieldFp) field).getP(); 380 int expectedLength = 1 + (p.bitLength() + 7) / 8; 381 if (bytes.length != expectedLength) { 382 throw new GeneralSecurityException("compressed point has wrong length"); 383 } 384 boolean lsb; 385 switch (bytes[0]) { 386 case 2: 387 lsb = false; 388 break; 389 case 3: 390 lsb = true; 391 break; 392 default: 393 throw new GeneralSecurityException("Invalid format"); 394 } 395 BigInteger x = new BigInteger(1, Arrays.copyOfRange(bytes, 1, bytes.length)); 396 if (x.compareTo(BigInteger.ZERO) == -1 || x.compareTo(p) != -1) { 397 throw new GeneralSecurityException("x is out of range"); 398 } 399 // Compute rhs == x^3 + a x + b (mod p) 400 BigInteger rhs = x.multiply(x).add(ec.getA()).multiply(x).add(ec.getB()).mod(p); 401 BigInteger y = modSqrt(rhs, p); 402 if (lsb != y.testBit(0)) { 403 y = p.subtract(y).mod(p); 404 } 405 return new ECPoint(x, y); 406 } 407 408 /** 409 * Returns a weak public key of order 3 such that the public key point is on the curve specified 410 * in ecParams. This method is used to check ECC implementations for missing step in the 411 * verification of the public key. E.g. implementations of ECDH must verify that the public key 412 * contains a point on the curve as well as public and secret key are using the same curve. 413 * 414 * @param ecParams the parameters of the key to attack. This must be a curve in Weierstrass form 415 * over a prime order field. 416 * @return a weak EC group with a genrator of order 3. 417 */ getWeakPublicKey(ECParameterSpec ecParams)418 public static ECPublicKeySpec getWeakPublicKey(ECParameterSpec ecParams) 419 throws GeneralSecurityException { 420 EllipticCurve curve = ecParams.getCurve(); 421 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); 422 keyGen.initialize(ecParams); 423 BigInteger p = getModulus(curve); 424 BigInteger three = new BigInteger("3"); 425 while (true) { 426 // Generate a point on the original curve 427 KeyPair keyPair = keyGen.generateKeyPair(); 428 ECPublicKey pub = (ECPublicKey) keyPair.getPublic(); 429 ECPoint w = pub.getW(); 430 BigInteger x = w.getAffineX(); 431 BigInteger y = w.getAffineY(); 432 // Find the curve parameters a,b such that 3*w = infinity. 433 // This is the case if the following equations are satisfied: 434 // 3x == l^2 (mod p) 435 // l == (3x^2 + a) / 2*y (mod p) 436 // y^2 == x^3 + ax + b (mod p) 437 BigInteger l; 438 try { 439 l = modSqrt(x.multiply(three), p); 440 } catch (GeneralSecurityException ex) { 441 continue; 442 } 443 BigInteger xSqr = x.multiply(x).mod(p); 444 BigInteger a = l.multiply(y.add(y)).subtract(xSqr.multiply(three)).mod(p); 445 BigInteger b = y.multiply(y).subtract(x.multiply(xSqr.add(a))).mod(p); 446 EllipticCurve newCurve = new EllipticCurve(curve.getField(), a, b); 447 // Just a sanity check. 448 checkPointOnCurve(w, newCurve); 449 // Cofactor and order are of course wrong. 450 ECParameterSpec spec = new ECParameterSpec(newCurve, w, p, 1); 451 return new ECPublicKeySpec(w, spec); 452 } 453 } 454 } 455