1package org.bouncycastle.jcajce.provider.asymmetric.ec; 2 3import java.math.BigInteger; 4import java.security.InvalidAlgorithmParameterException; 5import java.security.InvalidParameterException; 6import java.security.KeyPair; 7import java.security.SecureRandom; 8import java.security.spec.AlgorithmParameterSpec; 9import java.security.spec.ECGenParameterSpec; 10import java.util.Hashtable; 11import java.util.Map; 12 13import org.bouncycastle.asn1.ASN1ObjectIdentifier; 14import org.bouncycastle.asn1.x9.ECNamedCurveTable; 15import org.bouncycastle.asn1.x9.X9ECParameters; 16import org.bouncycastle.crypto.AsymmetricCipherKeyPair; 17import org.bouncycastle.crypto.generators.ECKeyPairGenerator; 18import org.bouncycastle.crypto.params.ECDomainParameters; 19import org.bouncycastle.crypto.params.ECKeyGenerationParameters; 20import org.bouncycastle.crypto.params.ECPrivateKeyParameters; 21import org.bouncycastle.crypto.params.ECPublicKeyParameters; 22import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; 23import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; 24import org.bouncycastle.jce.provider.BouncyCastleProvider; 25import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; 26import org.bouncycastle.jce.spec.ECNamedCurveSpec; 27import org.bouncycastle.jce.spec.ECParameterSpec; 28import org.bouncycastle.math.ec.ECCurve; 29import org.bouncycastle.math.ec.ECPoint; 30import org.bouncycastle.util.Integers; 31 32public abstract class KeyPairGeneratorSpi 33 extends java.security.KeyPairGenerator 34{ 35 public KeyPairGeneratorSpi(String algorithmName) 36 { 37 super(algorithmName); 38 } 39 40 public static class EC 41 extends KeyPairGeneratorSpi 42 { 43 ECKeyGenerationParameters param; 44 ECKeyPairGenerator engine = new ECKeyPairGenerator(); 45 Object ecParams = null; 46 // BEGIN android-changed 47 int strength = 256; 48 // BEGIN android-changed 49 int certainty = 50; 50 SecureRandom random = new SecureRandom(); 51 boolean initialised = false; 52 String algorithm; 53 ProviderConfiguration configuration; 54 55 static private Hashtable ecParameters; 56 57 static { 58 ecParameters = new Hashtable(); 59 60 ecParameters.put(Integers.valueOf(192), new ECGenParameterSpec("prime192v1")); // a.k.a P-192 61 ecParameters.put(Integers.valueOf(239), new ECGenParameterSpec("prime239v1")); 62 ecParameters.put(Integers.valueOf(256), new ECGenParameterSpec("prime256v1")); // a.k.a P-256 63 64 ecParameters.put(Integers.valueOf(224), new ECGenParameterSpec("P-224")); 65 ecParameters.put(Integers.valueOf(384), new ECGenParameterSpec("P-384")); 66 ecParameters.put(Integers.valueOf(521), new ECGenParameterSpec("P-521")); 67 } 68 69 public EC() 70 { 71 super("EC"); 72 this.algorithm = "EC"; 73 this.configuration = BouncyCastleProvider.CONFIGURATION; 74 } 75 76 public EC( 77 String algorithm, 78 ProviderConfiguration configuration) 79 { 80 super(algorithm); 81 this.algorithm = algorithm; 82 this.configuration = configuration; 83 } 84 85 public void initialize( 86 int strength, 87 SecureRandom random) 88 { 89 this.strength = strength; 90 // BEGIN android-added 91 if (random != null) { 92 // END android-added 93 this.random = random; 94 // BEGIN android-added 95 } 96 // END android-added 97 98 ECGenParameterSpec ecParams = (ECGenParameterSpec)ecParameters.get(Integers.valueOf(strength)); 99 if (ecParams == null) 100 { 101 throw new InvalidParameterException("unknown key size."); 102 } 103 104 try 105 { 106 initialize(ecParams, random); 107 } 108 catch (InvalidAlgorithmParameterException e) 109 { 110 throw new InvalidParameterException("key size not configurable."); 111 } 112 } 113 114 public void initialize( 115 AlgorithmParameterSpec params, 116 SecureRandom random) 117 throws InvalidAlgorithmParameterException 118 { 119 // BEGIN android-added 120 if (random == null) { 121 random = this.random; 122 } 123 // END android-added 124 if (params == null) 125 { 126 ECParameterSpec implicitCA = configuration.getEcImplicitlyCa(); 127 if (implicitCA == null) 128 { 129 throw new InvalidAlgorithmParameterException("null parameter passed but no implicitCA set"); 130 } 131 132 this.ecParams = null; 133 this.param = createKeyGenParamsBC(implicitCA, random); 134 } 135 else if (params instanceof ECParameterSpec) 136 { 137 this.ecParams = params; 138 this.param = createKeyGenParamsBC((ECParameterSpec)params, random); 139 } 140 else if (params instanceof java.security.spec.ECParameterSpec) 141 { 142 this.ecParams = params; 143 this.param = createKeyGenParamsJCE((java.security.spec.ECParameterSpec)params, random); 144 } 145 else if (params instanceof ECGenParameterSpec) 146 { 147 initializeNamedCurve(((ECGenParameterSpec)params).getName(), random); 148 } 149 else if (params instanceof ECNamedCurveGenParameterSpec) 150 { 151 initializeNamedCurve(((ECNamedCurveGenParameterSpec)params).getName(), random); 152 } 153 else 154 { 155 throw new InvalidAlgorithmParameterException("parameter object not a ECParameterSpec"); 156 } 157 158 engine.init(param); 159 initialised = true; 160 } 161 162 public KeyPair generateKeyPair() 163 { 164 if (!initialised) 165 { 166 initialize(strength, new SecureRandom()); 167 } 168 169 AsymmetricCipherKeyPair pair = engine.generateKeyPair(); 170 ECPublicKeyParameters pub = (ECPublicKeyParameters)pair.getPublic(); 171 ECPrivateKeyParameters priv = (ECPrivateKeyParameters)pair.getPrivate(); 172 173 if (ecParams instanceof ECParameterSpec) 174 { 175 ECParameterSpec p = (ECParameterSpec)ecParams; 176 177 BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration); 178 return new KeyPair(pubKey, 179 new BCECPrivateKey(algorithm, priv, pubKey, p, configuration)); 180 } 181 else if (ecParams == null) 182 { 183 return new KeyPair(new BCECPublicKey(algorithm, pub, configuration), 184 new BCECPrivateKey(algorithm, priv, configuration)); 185 } 186 else 187 { 188 java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams; 189 190 BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration); 191 192 return new KeyPair(pubKey, new BCECPrivateKey(algorithm, priv, pubKey, p, configuration)); 193 } 194 } 195 196 protected ECKeyGenerationParameters createKeyGenParamsBC(ECParameterSpec p, SecureRandom r) 197 { 198 return new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()), r); 199 } 200 201 protected ECKeyGenerationParameters createKeyGenParamsJCE(java.security.spec.ECParameterSpec p, SecureRandom r) 202 { 203 ECCurve curve = EC5Util.convertCurve(p.getCurve()); 204 ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false); 205 BigInteger n = p.getOrder(); 206 BigInteger h = BigInteger.valueOf(p.getCofactor()); 207 ECDomainParameters dp = new ECDomainParameters(curve, g, n, h); 208 return new ECKeyGenerationParameters(dp, r); 209 } 210 211 protected ECNamedCurveSpec createNamedCurveSpec(String curveName) 212 throws InvalidAlgorithmParameterException 213 { 214 // NOTE: Don't bother with custom curves here as the curve will be converted to JCE type shortly 215 216 X9ECParameters p = ECUtils.getDomainParametersFromName(curveName); 217 if (p == null) 218 { 219 try 220 { 221 // Check whether it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug) 222 p = ECNamedCurveTable.getByOID(new ASN1ObjectIdentifier(curveName)); 223 if (p == null) 224 { 225 Map extraCurves = configuration.getAdditionalECParameters(); 226 227 p = (X9ECParameters)extraCurves.get(new ASN1ObjectIdentifier(curveName)); 228 229 if (p == null) 230 { 231 throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName); 232 } 233 } 234 } 235 catch (IllegalArgumentException ex) 236 { 237 throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName); 238 } 239 } 240 241 // Work-around for JDK bug -- it won't look up named curves properly if seed is present 242 byte[] seed = null; //p.getSeed(); 243 244 return new ECNamedCurveSpec(curveName, p.getCurve(), p.getG(), p.getN(), p.getH(), seed); 245 } 246 247 protected void initializeNamedCurve(String curveName, SecureRandom random) 248 throws InvalidAlgorithmParameterException 249 { 250 ECNamedCurveSpec namedCurve = createNamedCurveSpec(curveName); 251 this.ecParams = namedCurve; 252 this.param = createKeyGenParamsJCE(namedCurve, random); 253 } 254 } 255 256 public static class ECDSA 257 extends EC 258 { 259 public ECDSA() 260 { 261 super("ECDSA", BouncyCastleProvider.CONFIGURATION); 262 } 263 } 264 265 public static class ECDH 266 extends EC 267 { 268 public ECDH() 269 { 270 super("ECDH", BouncyCastleProvider.CONFIGURATION); 271 } 272 } 273 274 public static class ECDHC 275 extends EC 276 { 277 public ECDHC() 278 { 279 super("ECDHC", BouncyCastleProvider.CONFIGURATION); 280 } 281 } 282 283 public static class ECMQV 284 extends EC 285 { 286 public ECMQV() 287 { 288 super("ECMQV", BouncyCastleProvider.CONFIGURATION); 289 } 290 } 291} 292