1package org.bouncycastle.jcajce.provider.asymmetric.ec; 2 3import java.math.BigInteger; 4import java.security.InvalidAlgorithmParameterException; 5import java.security.InvalidKeyException; 6import java.security.Key; 7import java.security.PrivateKey; 8import java.security.PublicKey; 9import java.security.SecureRandom; 10import java.security.spec.AlgorithmParameterSpec; 11 12import org.bouncycastle.asn1.x9.X9IntegerConverter; 13import org.bouncycastle.crypto.BasicAgreement; 14import org.bouncycastle.crypto.CipherParameters; 15import org.bouncycastle.crypto.DerivationFunction; 16import org.bouncycastle.crypto.agreement.ECDHBasicAgreement; 17// BEGIN android-removed 18// import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement; 19// import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement; 20// import org.bouncycastle.crypto.agreement.kdf.ConcatenationKDFGenerator; 21// import org.bouncycastle.crypto.generators.KDF2BytesGenerator; 22// END android-removed 23import org.bouncycastle.crypto.params.ECDomainParameters; 24import org.bouncycastle.crypto.params.ECPrivateKeyParameters; 25import org.bouncycastle.crypto.params.ECPublicKeyParameters; 26// BEGIN android-removed 27// import org.bouncycastle.crypto.params.MQVPrivateParameters; 28// import org.bouncycastle.crypto.params.MQVPublicParameters; 29// import org.bouncycastle.crypto.util.DigestFactory; 30// END android-removed 31import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi; 32import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; 33// BEGIN android-removed 34// import org.bouncycastle.jcajce.spec.MQVParameterSpec; 35// END android-removed 36import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec; 37import org.bouncycastle.jce.interfaces.ECPrivateKey; 38import org.bouncycastle.jce.interfaces.ECPublicKey; 39// BEGIN android-removed 40// import org.bouncycastle.jce.interfaces.MQVPrivateKey; 41// import org.bouncycastle.jce.interfaces.MQVPublicKey; 42// END android-removed 43 44/** 45 * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363 46 * both the simple one, and the simple one with cofactors are supported. 47 * 48 * Also, MQV key agreement per SEC-1 49 */ 50public class KeyAgreementSpi 51 extends BaseAgreementSpi 52{ 53 private static final X9IntegerConverter converter = new X9IntegerConverter(); 54 55 private String kaAlgorithm; 56 57 private ECDomainParameters parameters; 58 private BasicAgreement agreement; 59 60 // BEGIN android-removed 61 // private MQVParameterSpec mqvParameters; 62 // END android-removed 63 private BigInteger result; 64 65 protected KeyAgreementSpi( 66 String kaAlgorithm, 67 BasicAgreement agreement, 68 DerivationFunction kdf) 69 { 70 super(kaAlgorithm, kdf); 71 72 this.kaAlgorithm = kaAlgorithm; 73 this.agreement = agreement; 74 } 75 76 protected byte[] bigIntToBytes( 77 BigInteger r) 78 { 79 return converter.integerToBytes(r, converter.getByteLength(parameters.getCurve())); 80 } 81 82 protected Key engineDoPhase( 83 Key key, 84 boolean lastPhase) 85 throws InvalidKeyException, IllegalStateException 86 { 87 if (parameters == null) 88 { 89 throw new IllegalStateException(kaAlgorithm + " not initialised."); 90 } 91 92 if (!lastPhase) 93 { 94 throw new IllegalStateException(kaAlgorithm + " can only be between two parties."); 95 } 96 97 CipherParameters pubKey; 98 // BEGIN android-removed 99 // if (agreement instanceof ECMQVBasicAgreement) 100 // { 101 // if (!(key instanceof MQVPublicKey)) 102 // { 103 // ECPublicKeyParameters staticKey = (ECPublicKeyParameters) 104 // ECUtils.generatePublicKeyParameter((PublicKey)key); 105 // ECPublicKeyParameters ephemKey = (ECPublicKeyParameters) 106 // ECUtils.generatePublicKeyParameter(mqvParameters.getOtherPartyEphemeralKey()); 107 // 108 // pubKey = new MQVPublicParameters(staticKey, ephemKey); 109 // } 110 // else 111 // { 112 // MQVPublicKey mqvPubKey = (MQVPublicKey)key; 113 // ECPublicKeyParameters staticKey = (ECPublicKeyParameters) 114 // ECUtils.generatePublicKeyParameter(mqvPubKey.getStaticKey()); 115 // ECPublicKeyParameters ephemKey = (ECPublicKeyParameters) 116 // ECUtils.generatePublicKeyParameter(mqvPubKey.getEphemeralKey()); 117 // 118 // pubKey = new MQVPublicParameters(staticKey, ephemKey); 119 // } 120 // } 121 // else 122 // END android-removed 123 { 124 if (!(key instanceof PublicKey)) 125 { 126 throw new InvalidKeyException(kaAlgorithm + " key agreement requires " 127 + getSimpleName(ECPublicKey.class) + " for doPhase"); 128 } 129 130 pubKey = ECUtils.generatePublicKeyParameter((PublicKey)key); 131 } 132 133 try 134 { 135 result = agreement.calculateAgreement(pubKey); 136 } catch (final Exception e) { 137 throw new InvalidKeyException("calculation failed: " + e.getMessage()) 138 { 139 public Throwable getCause() 140 { 141 return e; 142 } 143 }; 144 } 145 return null; 146 } 147 148 protected void engineInit( 149 Key key, 150 AlgorithmParameterSpec params, 151 SecureRandom random) 152 throws InvalidKeyException, InvalidAlgorithmParameterException 153 { 154 // BEGIN android-changed 155 if (params != null && !(params instanceof UserKeyingMaterialSpec)) 156 // END android-changed 157 { 158 throw new InvalidAlgorithmParameterException("No algorithm parameters supported"); 159 } 160 161 initFromKey(key, params); 162 } 163 164 protected void engineInit( 165 Key key, 166 SecureRandom random) 167 throws InvalidKeyException 168 { 169 initFromKey(key, null); 170 } 171 172 private void initFromKey(Key key, AlgorithmParameterSpec parameterSpec) 173 throws InvalidKeyException 174 { 175 // BEGIN android-removed 176 // if (agreement instanceof ECMQVBasicAgreement) 177 // { 178 // mqvParameters = null; 179 // if (!(key instanceof MQVPrivateKey) && !(parameterSpec instanceof MQVParameterSpec)) 180 // { 181 // throw new InvalidKeyException(kaAlgorithm + " key agreement requires " 182 // + getSimpleName(MQVParameterSpec.class) + " for initialisation"); 183 // } 184 // 185 // ECPrivateKeyParameters staticPrivKey; 186 // ECPrivateKeyParameters ephemPrivKey; 187 // ECPublicKeyParameters ephemPubKey; 188 // if (key instanceof MQVPrivateKey) 189 // { 190 // MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key; 191 // staticPrivKey = (ECPrivateKeyParameters) 192 // ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey()); 193 // ephemPrivKey = (ECPrivateKeyParameters) 194 // ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey()); 195 // 196 // ephemPubKey = null; 197 // if (mqvPrivKey.getEphemeralPublicKey() != null) 198 // { 199 // ephemPubKey = (ECPublicKeyParameters) 200 // ECUtils.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey()); 201 // } 202 // } 203 // else 204 // { 205 // MQVParameterSpec mqvParameterSpec = (MQVParameterSpec)parameterSpec; 206 // 207 // staticPrivKey = (ECPrivateKeyParameters) 208 // ECUtil.generatePrivateKeyParameter((PrivateKey)key); 209 // ephemPrivKey = (ECPrivateKeyParameters) 210 // ECUtil.generatePrivateKeyParameter(mqvParameterSpec.getEphemeralPrivateKey()); 211 // 212 // ephemPubKey = null; 213 // if (mqvParameterSpec.getEphemeralPublicKey() != null) 214 // { 215 // ephemPubKey = (ECPublicKeyParameters) 216 // ECUtils.generatePublicKeyParameter(mqvParameterSpec.getEphemeralPublicKey()); 217 // } 218 // mqvParameters = mqvParameterSpec; 219 // ukmParameters = mqvParameterSpec.getUserKeyingMaterial(); 220 // } 221 // 222 // MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey); 223 // this.parameters = staticPrivKey.getParameters(); 224 // 225 // // TODO Validate that all the keys are using the same parameters? 226 // 227 // agreement.init(localParams); 228 // } 229 // else 230 // END android-removed 231 { 232 if (!(key instanceof PrivateKey)) 233 { 234 throw new InvalidKeyException(kaAlgorithm + " key agreement requires " 235 + getSimpleName(ECPrivateKey.class) + " for initialisation"); 236 } 237 238 ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)ECUtil.generatePrivateKeyParameter((PrivateKey)key); 239 this.parameters = privKey.getParameters(); 240 ukmParameters = (parameterSpec instanceof UserKeyingMaterialSpec) ? ((UserKeyingMaterialSpec)parameterSpec).getUserKeyingMaterial() : null; 241 agreement.init(privKey); 242 } 243 } 244 245 private static String getSimpleName(Class clazz) 246 { 247 String fullName = clazz.getName(); 248 249 return fullName.substring(fullName.lastIndexOf('.') + 1); 250 } 251 252 253 protected byte[] calcSecret() 254 { 255 return bigIntToBytes(result); 256 } 257 258 public static class DH 259 extends KeyAgreementSpi 260 { 261 public DH() 262 { 263 super("ECDH", new ECDHBasicAgreement(), null); 264 } 265 } 266 267 // BEGIN android-removed 268 // public static class DHC 269 // extends KeyAgreementSpi 270 // { 271 // public DHC() 272 // { 273 // super("ECDHC", new ECDHCBasicAgreement(), null); 274 // } 275 // } 276 277 // public static class MQV 278 // extends KeyAgreementSpi 279 // { 280 // public MQV() 281 // { 282 // super("ECMQV", new ECMQVBasicAgreement(), null); 283 // } 284 // } 285 286 // public static class DHwithSHA1KDF 287 // extends KeyAgreementSpi 288 // { 289 // public DHwithSHA1KDF() 290 // { 291 // super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1())); 292 // } 293 // } 294 295 // public static class DHwithSHA1KDFAndSharedInfo 296 // extends KeyAgreementSpi 297 // { 298 // public DHwithSHA1KDFAndSharedInfo() 299 // { 300 // super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1())); 301 // } 302 // } 303 304 // public static class CDHwithSHA1KDFAndSharedInfo 305 // extends KeyAgreementSpi 306 // { 307 // public CDHwithSHA1KDFAndSharedInfo() 308 // { 309 // super("ECCDHwithSHA1KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1())); 310 // } 311 // } 312 313 // public static class DHwithSHA224KDFAndSharedInfo 314 // extends KeyAgreementSpi 315 // { 316 // public DHwithSHA224KDFAndSharedInfo() 317 // { 318 // super("ECDHwithSHA224KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224())); 319 // } 320 // } 321 322 // public static class CDHwithSHA224KDFAndSharedInfo 323 // extends KeyAgreementSpi 324 // { 325 // public CDHwithSHA224KDFAndSharedInfo() 326 // { 327 // super("ECCDHwithSHA224KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224())); 328 // } 329 // } 330 331 // public static class DHwithSHA256KDFAndSharedInfo 332 // extends KeyAgreementSpi 333 // { 334 // public DHwithSHA256KDFAndSharedInfo() 335 // { 336 // super("ECDHwithSHA256KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256())); 337 // } 338 // } 339 340 // public static class CDHwithSHA256KDFAndSharedInfo 341 // extends KeyAgreementSpi 342 // { 343 // public CDHwithSHA256KDFAndSharedInfo() 344 // { 345 // super("ECCDHwithSHA256KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256())); 346 // } 347 // } 348 349 // public static class DHwithSHA384KDFAndSharedInfo 350 // extends KeyAgreementSpi 351 // { 352 // public DHwithSHA384KDFAndSharedInfo() 353 // { 354 // super("ECDHwithSHA384KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384())); 355 // } 356 // } 357 358 // public static class CDHwithSHA384KDFAndSharedInfo 359 // extends KeyAgreementSpi 360 // { 361 // public CDHwithSHA384KDFAndSharedInfo() 362 // { 363 // super("ECCDHwithSHA384KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384())); 364 // } 365 // } 366 367 // public static class DHwithSHA512KDFAndSharedInfo 368 // extends KeyAgreementSpi 369 // { 370 // public DHwithSHA512KDFAndSharedInfo() 371 // { 372 // super("ECDHwithSHA512KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512())); 373 // } 374 // } 375 376 // public static class CDHwithSHA512KDFAndSharedInfo 377 // extends KeyAgreementSpi 378 // { 379 // public CDHwithSHA512KDFAndSharedInfo() 380 // { 381 // super("ECCDHwithSHA512KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512())); 382 // } 383 // } 384 385 // public static class MQVwithSHA1KDFAndSharedInfo 386 // extends KeyAgreementSpi 387 // { 388 // public MQVwithSHA1KDFAndSharedInfo() 389 // { 390 // super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1())); 391 // } 392 // } 393 394 // public static class MQVwithSHA224KDFAndSharedInfo 395 // extends KeyAgreementSpi 396 // { 397 // public MQVwithSHA224KDFAndSharedInfo() 398 // { 399 // super("ECMQVwithSHA224KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224())); 400 // } 401 // } 402 403 // public static class MQVwithSHA256KDFAndSharedInfo 404 // extends KeyAgreementSpi 405 // { 406 // public MQVwithSHA256KDFAndSharedInfo() 407 // { 408 // super("ECMQVwithSHA256KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256())); 409 // } 410 // } 411 412 // public static class MQVwithSHA384KDFAndSharedInfo 413 // extends KeyAgreementSpi 414 // { 415 // public MQVwithSHA384KDFAndSharedInfo() 416 // { 417 // super("ECMQVwithSHA384KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384())); 418 // } 419 // } 420 421 // public static class MQVwithSHA512KDFAndSharedInfo 422 // extends KeyAgreementSpi 423 // { 424 // public MQVwithSHA512KDFAndSharedInfo() 425 // { 426 // super("ECMQVwithSHA512KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512())); 427 // } 428 // } 429 430 // public static class DHwithSHA1CKDF 431 // extends KeyAgreementSpi 432 // { 433 // public DHwithSHA1CKDF() 434 // { 435 // super("ECDHwithSHA1CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1())); 436 // } 437 // } 438 439 // public static class DHwithSHA256CKDF 440 // extends KeyAgreementSpi 441 // { 442 // public DHwithSHA256CKDF() 443 // { 444 // super("ECDHwithSHA256CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256())); 445 // } 446 // } 447 448 // public static class DHwithSHA384CKDF 449 // extends KeyAgreementSpi 450 // { 451 // public DHwithSHA384CKDF() 452 // { 453 // super("ECDHwithSHA384CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384())); 454 // } 455 // } 456 457 // public static class DHwithSHA512CKDF 458 // extends KeyAgreementSpi 459 // { 460 // public DHwithSHA512CKDF() 461 // { 462 // super("ECDHwithSHA512CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512())); 463 // } 464 // } 465 466 // public static class MQVwithSHA1CKDF 467 // extends KeyAgreementSpi 468 // { 469 // public MQVwithSHA1CKDF() 470 // { 471 // super("ECMQVwithSHA1CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1())); 472 // } 473 // } 474 475 // public static class MQVwithSHA224CKDF 476 // extends KeyAgreementSpi 477 // { 478 // public MQVwithSHA224CKDF() 479 // { 480 // super("ECMQVwithSHA224CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA224())); 481 // } 482 // } 483 484 // public static class MQVwithSHA256CKDF 485 // extends KeyAgreementSpi 486 // { 487 // public MQVwithSHA256CKDF() 488 // { 489 // super("ECMQVwithSHA256CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256())); 490 // } 491 // } 492 493 // public static class MQVwithSHA384CKDF 494 // extends KeyAgreementSpi 495 // { 496 // public MQVwithSHA384CKDF() 497 // { 498 // super("ECMQVwithSHA384CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384())); 499 // } 500 // } 501 502 // public static class MQVwithSHA512CKDF 503 // extends KeyAgreementSpi 504 // { 505 // public MQVwithSHA512CKDF() 506 // { 507 // super("ECMQVwithSHA512CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512())); 508 // } 509 // } 510 // END android-removed 511} 512