1package org.bouncycastle.jcajce.provider.asymmetric.util; 2 3import java.math.BigInteger; 4import java.security.InvalidKeyException; 5import java.security.PrivateKey; 6import java.security.PublicKey; 7import java.util.Enumeration; 8import java.util.Map; 9 10import org.bouncycastle.asn1.ASN1ObjectIdentifier; 11// BEGIN android-removed 12// import org.bouncycastle.asn1.anssi.ANSSINamedCurves; 13// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; 14// END android-removed 15import org.bouncycastle.asn1.nist.NISTNamedCurves; 16import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; 17import org.bouncycastle.asn1.sec.SECNamedCurves; 18// BEGIN android-removed 19// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves; 20// END android-removed 21import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 22import org.bouncycastle.asn1.x9.ECNamedCurveTable; 23import org.bouncycastle.asn1.x9.X962NamedCurves; 24import org.bouncycastle.asn1.x9.X962Parameters; 25import org.bouncycastle.asn1.x9.X9ECParameters; 26import org.bouncycastle.crypto.ec.CustomNamedCurves; 27import org.bouncycastle.crypto.params.AsymmetricKeyParameter; 28import org.bouncycastle.crypto.params.ECDomainParameters; 29import org.bouncycastle.crypto.params.ECNamedDomainParameters; 30import org.bouncycastle.crypto.params.ECPrivateKeyParameters; 31import org.bouncycastle.crypto.params.ECPublicKeyParameters; 32import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; 33import org.bouncycastle.jce.interfaces.ECPrivateKey; 34import org.bouncycastle.jce.interfaces.ECPublicKey; 35import org.bouncycastle.jce.provider.BouncyCastleProvider; 36import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; 37import org.bouncycastle.jce.spec.ECParameterSpec; 38 39/** 40 * utility class for converting jce/jca ECDSA, ECDH, and ECDHC 41 * objects into their org.bouncycastle.crypto counterparts. 42 */ 43public class ECUtil 44{ 45 /** 46 * Returns a sorted array of middle terms of the reduction polynomial. 47 * @param k The unsorted array of middle terms of the reduction polynomial 48 * of length 1 or 3. 49 * @return the sorted array of middle terms of the reduction polynomial. 50 * This array always has length 3. 51 */ 52 static int[] convertMidTerms( 53 int[] k) 54 { 55 int[] res = new int[3]; 56 57 if (k.length == 1) 58 { 59 res[0] = k[0]; 60 } 61 else 62 { 63 if (k.length != 3) 64 { 65 throw new IllegalArgumentException("Only Trinomials and pentanomials supported"); 66 } 67 68 if (k[0] < k[1] && k[0] < k[2]) 69 { 70 res[0] = k[0]; 71 if (k[1] < k[2]) 72 { 73 res[1] = k[1]; 74 res[2] = k[2]; 75 } 76 else 77 { 78 res[1] = k[2]; 79 res[2] = k[1]; 80 } 81 } 82 else if (k[1] < k[2]) 83 { 84 res[0] = k[1]; 85 if (k[0] < k[2]) 86 { 87 res[1] = k[0]; 88 res[2] = k[2]; 89 } 90 else 91 { 92 res[1] = k[2]; 93 res[2] = k[0]; 94 } 95 } 96 else 97 { 98 res[0] = k[2]; 99 if (k[0] < k[1]) 100 { 101 res[1] = k[0]; 102 res[2] = k[1]; 103 } 104 else 105 { 106 res[1] = k[1]; 107 res[2] = k[0]; 108 } 109 } 110 } 111 112 return res; 113 } 114 115 public static ECDomainParameters getDomainParameters( 116 ProviderConfiguration configuration, 117 org.bouncycastle.jce.spec.ECParameterSpec params) 118 { 119 ECDomainParameters domainParameters; 120 121 if (params instanceof ECNamedCurveParameterSpec) 122 { 123 ECNamedCurveParameterSpec nParams = (ECNamedCurveParameterSpec)params; 124 ASN1ObjectIdentifier nameOid = ECUtil.getNamedCurveOid(nParams.getName()); 125 126 domainParameters = new ECNamedDomainParameters(nameOid, nParams.getCurve(), nParams.getG(), nParams.getN(), nParams.getH(), nParams.getSeed()); 127 } 128 else if (params == null) 129 { 130 org.bouncycastle.jce.spec.ECParameterSpec iSpec = configuration.getEcImplicitlyCa(); 131 132 domainParameters = new ECDomainParameters(iSpec.getCurve(), iSpec.getG(), iSpec.getN(), iSpec.getH(), iSpec.getSeed()); 133 } 134 else 135 { 136 domainParameters = new ECDomainParameters(params.getCurve(), params.getG(), params.getN(), params.getH(), params.getSeed()); 137 } 138 139 return domainParameters; 140 } 141 142 public static ECDomainParameters getDomainParameters( 143 ProviderConfiguration configuration, 144 X962Parameters params) 145 { 146 ECDomainParameters domainParameters; 147 148 if (params.isNamedCurve()) 149 { 150 ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); 151 X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid); 152 if (ecP == null) 153 { 154 Map extraCurves = configuration.getAdditionalECParameters(); 155 156 ecP = (X9ECParameters)extraCurves.get(oid); 157 } 158 domainParameters = new ECNamedDomainParameters(oid, ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed()); 159 } 160 else if (params.isImplicitlyCA()) 161 { 162 org.bouncycastle.jce.spec.ECParameterSpec iSpec = configuration.getEcImplicitlyCa(); 163 164 domainParameters = new ECDomainParameters(iSpec.getCurve(), iSpec.getG(), iSpec.getN(), iSpec.getH(), iSpec.getSeed()); 165 } 166 else 167 { 168 X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters()); 169 170 domainParameters = new ECDomainParameters(ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed()); 171 } 172 173 return domainParameters; 174 } 175 176 public static AsymmetricKeyParameter generatePublicKeyParameter( 177 PublicKey key) 178 throws InvalidKeyException 179 { 180 if (key instanceof ECPublicKey) 181 { 182 ECPublicKey k = (ECPublicKey)key; 183 ECParameterSpec s = k.getParameters(); 184 185 return new ECPublicKeyParameters( 186 k.getQ(), 187 new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); 188 } 189 else if (key instanceof java.security.interfaces.ECPublicKey) 190 { 191 java.security.interfaces.ECPublicKey pubKey = (java.security.interfaces.ECPublicKey)key; 192 ECParameterSpec s = EC5Util.convertSpec(pubKey.getParams(), false); 193 return new ECPublicKeyParameters( 194 EC5Util.convertPoint(pubKey.getParams(), pubKey.getW(), false), 195 new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); 196 } 197 else 198 { 199 // see if we can build a key from key.getEncoded() 200 try 201 { 202 byte[] bytes = key.getEncoded(); 203 204 if (bytes == null) 205 { 206 throw new InvalidKeyException("no encoding for EC public key"); 207 } 208 209 PublicKey publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes)); 210 211 if (publicKey instanceof java.security.interfaces.ECPublicKey) 212 { 213 return ECUtil.generatePublicKeyParameter(publicKey); 214 } 215 } 216 catch (Exception e) 217 { 218 throw new InvalidKeyException("cannot identify EC public key: " + e.toString()); 219 } 220 } 221 222 throw new InvalidKeyException("cannot identify EC public key."); 223 } 224 225 public static AsymmetricKeyParameter generatePrivateKeyParameter( 226 PrivateKey key) 227 throws InvalidKeyException 228 { 229 if (key instanceof ECPrivateKey) 230 { 231 ECPrivateKey k = (ECPrivateKey)key; 232 ECParameterSpec s = k.getParameters(); 233 234 if (s == null) 235 { 236 s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); 237 } 238 239 return new ECPrivateKeyParameters( 240 k.getD(), 241 new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); 242 } 243 else if (key instanceof java.security.interfaces.ECPrivateKey) 244 { 245 java.security.interfaces.ECPrivateKey privKey = (java.security.interfaces.ECPrivateKey)key; 246 ECParameterSpec s = EC5Util.convertSpec(privKey.getParams(), false); 247 return new ECPrivateKeyParameters( 248 privKey.getS(), 249 new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); 250 } 251 else 252 { 253 // see if we can build a key from key.getEncoded() 254 try 255 { 256 byte[] bytes = key.getEncoded(); 257 258 if (bytes == null) 259 { 260 throw new InvalidKeyException("no encoding for EC private key"); 261 } 262 263 PrivateKey privateKey = BouncyCastleProvider.getPrivateKey(PrivateKeyInfo.getInstance(bytes)); 264 265 if (privateKey instanceof java.security.interfaces.ECPrivateKey) 266 { 267 return ECUtil.generatePrivateKeyParameter(privateKey); 268 } 269 } 270 catch (Exception e) 271 { 272 throw new InvalidKeyException("cannot identify EC private key: " + e.toString()); 273 } 274 } 275 276 throw new InvalidKeyException("can't identify EC private key."); 277 } 278 279 public static int getOrderBitLength(ProviderConfiguration configuration, BigInteger order, BigInteger privateValue) 280 { 281 if (order == null) // implicitly CA 282 { 283 ECParameterSpec implicitCA = configuration.getEcImplicitlyCa(); 284 285 if (implicitCA == null) 286 { 287 return privateValue.bitLength(); // a guess but better than an exception! 288 } 289 290 return implicitCA.getN().bitLength(); 291 } 292 else 293 { 294 return order.bitLength(); 295 } 296 } 297 298 public static ASN1ObjectIdentifier getNamedCurveOid( 299 String curveName) 300 { 301 String name; 302 303 if (curveName.indexOf(' ') > 0) 304 { 305 name = curveName.substring(curveName.indexOf(' ') + 1); 306 } 307 else 308 { 309 name = curveName; 310 } 311 312 try 313 { 314 if (name.charAt(0) >= '0' && name.charAt(0) <= '2') 315 { 316 return new ASN1ObjectIdentifier(name); 317 } 318 else 319 { 320 return lookupOidByName(name); 321 } 322 } 323 catch (IllegalArgumentException ex) 324 { 325 return lookupOidByName(name); 326 } 327 } 328 329 private static ASN1ObjectIdentifier lookupOidByName(String name) 330 { 331 ASN1ObjectIdentifier oid = X962NamedCurves.getOID(name); 332 333 if (oid == null) 334 { 335 oid = SECNamedCurves.getOID(name); 336 if (oid == null) 337 { 338 oid = NISTNamedCurves.getOID(name); 339 } 340 // BEGIN android-removed 341 // if (oid == null) 342 // { 343 // oid = TeleTrusTNamedCurves.getOID(name); 344 // } 345 // if (oid == null) 346 // { 347 // oid = ECGOST3410NamedCurves.getOID(name); 348 // } 349 // if (oid == null) 350 // { 351 // oid = ANSSINamedCurves.getOID(name); 352 // } 353 // END android-removed 354 } 355 356 return oid; 357 } 358 359 public static ASN1ObjectIdentifier getNamedCurveOid( 360 ECParameterSpec ecParameterSpec) 361 { 362 for (Enumeration names = ECNamedCurveTable.getNames(); names.hasMoreElements();) 363 { 364 String name = (String)names.nextElement(); 365 366 X9ECParameters params = ECNamedCurveTable.getByName(name); 367 368 if (params.getN().equals(ecParameterSpec.getN()) 369 && params.getH().equals(ecParameterSpec.getH()) 370 && params.getCurve().equals(ecParameterSpec.getCurve()) 371 && params.getG().equals(ecParameterSpec.getG())) 372 { 373 return org.bouncycastle.asn1.x9.ECNamedCurveTable.getOID(name); 374 } 375 } 376 377 return null; 378 } 379 380 public static X9ECParameters getNamedCurveByOid( 381 ASN1ObjectIdentifier oid) 382 { 383 X9ECParameters params = CustomNamedCurves.getByOID(oid); 384 385 if (params == null) 386 { 387 params = X962NamedCurves.getByOID(oid); 388 if (params == null) 389 { 390 params = SECNamedCurves.getByOID(oid); 391 } 392 if (params == null) 393 { 394 params = NISTNamedCurves.getByOID(oid); 395 } 396 // BEGIN android-removed 397 // if (params == null) 398 // { 399 // params = TeleTrusTNamedCurves.getByOID(oid); 400 // } 401 // END android-removed 402 } 403 404 return params; 405 } 406 407 public static X9ECParameters getNamedCurveByName( 408 String curveName) 409 { 410 X9ECParameters params = CustomNamedCurves.getByName(curveName); 411 412 if (params == null) 413 { 414 params = X962NamedCurves.getByName(curveName); 415 if (params == null) 416 { 417 params = SECNamedCurves.getByName(curveName); 418 } 419 if (params == null) 420 { 421 params = NISTNamedCurves.getByName(curveName); 422 } 423 // BEGIN android-removed 424 // if (params == null) 425 // { 426 // params = TeleTrusTNamedCurves.getByName(curveName); 427 // } 428 // END android-removed 429 } 430 431 return params; 432 } 433 434 public static String getCurveName( 435 ASN1ObjectIdentifier oid) 436 { 437 String name = X962NamedCurves.getName(oid); 438 439 if (name == null) 440 { 441 name = SECNamedCurves.getName(oid); 442 if (name == null) 443 { 444 name = NISTNamedCurves.getName(oid); 445 } 446 // BEGIN android-removed 447 // if (name == null) 448 // { 449 // name = TeleTrusTNamedCurves.getName(oid); 450 // } 451 // if (name == null) 452 // { 453 // name = ECGOST3410NamedCurves.getName(oid); 454 // } 455 // END android-removed 456 } 457 458 return name; 459 } 460} 461