static byte[] buildDH(DHPublicKey key) { DataByteOutputStream out = new DataByteOutputStream(); BigInteger p = key.getParams().getP(); BigInteger g = key.getParams().getG(); BigInteger y = key.getY(); int pLength, gLength, yLength; if (g.equals(TWO) && (p.equals(DHPRIME768) || p.equals(DHPRIME1024))) { pLength = 1; gLength = 0; } else { pLength = BigIntegerLength(p); gLength = BigIntegerLength(g); } yLength = BigIntegerLength(y); out.writeShort(pLength); if (pLength == 1) { if (p.bitLength() == 768) out.writeByte((byte) 1); else out.writeByte((byte) 2); } else out.writeBigInteger(p); out.writeShort(gLength); if (gLength > 0) out.writeBigInteger(g); out.writeShort(yLength); out.writeBigInteger(y); return out.toByteArray(); }
/** * Returns whether the Diffie-Hellman public key is valid or not. * * <p>Per RFC 2631 and NIST SP800-56A, the following algorithm is used to validate Diffie-Hellman * public keys: 1. Verify that y lies within the interval [2,p-1]. If it does not, the key is * invalid. 2. Compute y^q mod p. If the result == 1, the key is valid. Otherwise the key is * invalid. */ private static void validateDHPublicKey(DHPublicKey publicKey) throws InvalidKeyException { DHParameterSpec paramSpec = publicKey.getParams(); BigInteger p = paramSpec.getP(); BigInteger g = paramSpec.getG(); BigInteger y = publicKey.getY(); validateDHPublicKey(p, g, y); }
public void setRemoteDHPublicKey(DHPublicKey dhPublicKey) { // Verifies that Alice's gy is a legal value (2 <= gy <= modulus-2) if (dhPublicKey.getY().compareTo(OtrCryptoEngine.MODULUS_MINUS_TWO) > 0) { throw new IllegalArgumentException("Illegal D-H Public Key value, Ignoring message."); } else if (dhPublicKey.getY().compareTo(OtrCryptoEngine.BIGINTEGER_TWO) < 0) { throw new IllegalArgumentException("Illegal D-H Public Key value, Ignoring message."); } logger.finest("Received D-H Public Key is a legal value."); this.remoteDHPublicKey = dhPublicKey; }
static DHPublicKeySpec getDHPublicKeySpec(PublicKey key) { if (key instanceof DHPublicKey) { DHPublicKey dhKey = (DHPublicKey) key; DHParameterSpec params = dhKey.getParams(); return new DHPublicKeySpec(dhKey.getY(), params.getP(), params.getG()); } try { KeyFactory factory = JsseJce.getKeyFactory("DH"); return (DHPublicKeySpec) factory.getKeySpec(key, DHPublicKeySpec.class); } catch (Exception e) { throw new RuntimeException(e); } }
/** * Create a set of public/private keys using ValueLinks defined parameters * * @return KeyPair object containing both public and private keys * @throws NoSuchAlgorithmException * @throws InvalidAlgorithmParameterException */ public KeyPair createKeys() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeySpecException { // initialize the parameter spec DHPublicKey publicKey = (DHPublicKey) this.getValueLinkPublicKey(); DHParameterSpec dhParamSpec = publicKey.getParams(); // Debug.logInfo(dhParamSpec.getP().toString() + " / " + dhParamSpec.getG().toString(), module); // create the public/private key pair using parameters defined by valuelink KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH"); keyGen.initialize(dhParamSpec); KeyPair keyPair = keyGen.generateKeyPair(); return keyPair; }
public void testIODHPublicKey() throws Exception { KeyPair pair = new OtrCryptoEngineImpl().generateDHKeyPair(); DHPublicKey source = (DHPublicKey) pair.getPublic(); ByteArrayOutputStream out = new ByteArrayOutputStream(); OtrOutputStream oos = new OtrOutputStream(out); oos.writeDHPublicKey(source); byte[] converted = out.toByteArray(); ByteArrayInputStream bin = new ByteArrayInputStream(converted); OtrInputStream ois = new OtrInputStream(bin); DHPublicKey result = ois.readDHPublicKey(); assertTrue(source.getY().compareTo(result.getY()) == 0); }
protected KeySpec engineGetKeySpec(Key key, Class spec) throws InvalidKeySpecException { if (spec.isAssignableFrom(PKCS8EncodedKeySpec.class) && key.getFormat().equals("PKCS#8")) { return new PKCS8EncodedKeySpec(key.getEncoded()); } else if (spec.isAssignableFrom(X509EncodedKeySpec.class) && key.getFormat().equals("X.509")) { return new X509EncodedKeySpec(key.getEncoded()); } else if (spec.isAssignableFrom(RSAPublicKeySpec.class) && key instanceof RSAPublicKey) { RSAPublicKey k = (RSAPublicKey) key; return new RSAPublicKeySpec(k.getModulus(), k.getPublicExponent()); } else if (spec.isAssignableFrom(RSAPrivateKeySpec.class) && key instanceof RSAPrivateKey) { RSAPrivateKey k = (RSAPrivateKey) key; return new RSAPrivateKeySpec(k.getModulus(), k.getPrivateExponent()); } else if (spec.isAssignableFrom(RSAPrivateCrtKeySpec.class) && key instanceof RSAPrivateCrtKey) { RSAPrivateCrtKey k = (RSAPrivateCrtKey) key; return new RSAPrivateCrtKeySpec( k.getModulus(), k.getPublicExponent(), k.getPrivateExponent(), k.getPrimeP(), k.getPrimeQ(), k.getPrimeExponentP(), k.getPrimeExponentQ(), k.getCrtCoefficient()); } else if (spec.isAssignableFrom(DHPrivateKeySpec.class) && key instanceof DHPrivateKey) { DHPrivateKey k = (DHPrivateKey) key; return new DHPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getG()); } else if (spec.isAssignableFrom(DHPublicKeySpec.class) && key instanceof DHPublicKey) { DHPublicKey k = (DHPublicKey) key; return new DHPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getG()); } throw new RuntimeException("not implemented yet " + key + " " + spec); }
@Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + Arrays.hashCode(ctr); result = prime * result + Arrays.hashCode(encryptedMessage); result = prime * result + flags; result = prime * result + Arrays.hashCode(mac); // TODO: Needs work. result = prime * result + ((nextDH == null) ? 0 : nextDH.hashCode()); result = prime * result + Arrays.hashCode(oldMACKeys); result = prime * result + recipientKeyID; result = prime * result + senderKeyID; return result; }
protected Key engineDoPhase(Key key, boolean lastPhase) throws InvalidKeyException, IllegalStateException { if (x == null) { throw new IllegalStateException("Diffie-Hellman not initialised."); } if (!(key instanceof DHPublicKey)) { throw new InvalidKeyException("DHKeyAgreement doPhase requires DHPublicKey"); } DHPublicKey pubKey = (DHPublicKey) key; if (!pubKey.getParams().getG().equals(g) || !pubKey.getParams().getP().equals(p)) { throw new InvalidKeyException("DHPublicKey not for this KeyAgreement!"); } if (lastPhase) { result = ((DHPublicKey) key).getY().modPow(x, p); return null; } else { result = ((DHPublicKey) key).getY().modPow(x, p); } return new BCDHPublicKey(result, pubKey.getParams()); }
@Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; DataMessage other = (DataMessage) obj; if (!Arrays.equals(ctr, other.ctr)) return false; if (!Arrays.equals(encryptedMessage, other.encryptedMessage)) return false; if (flags != other.flags) return false; if (!Arrays.equals(mac, other.mac)) return false; if (nextDH == null) { if (other.nextDH != null) return false; } else if (!nextDH.equals(other.nextDH)) return false; if (!Arrays.equals(oldMACKeys, other.oldMACKeys)) return false; if (recipientKeyID != other.recipientKeyID) return false; if (senderKeyID != other.senderKeyID) return false; return true; }
/** Given a DH key pair, return the BIND9-style text encoding */ private String generatePrivateDH(DHPrivateKey key, DHPublicKey pub, int algorithm) { StringWriter sw = new StringWriter(); PrintWriter out = new PrintWriter(sw); DnsKeyAlgorithm algs = DnsKeyAlgorithm.getInstance(); DHParameterSpec p = key.getParams(); out.println("Private-key-format: v1.2"); out.println("Algorithm: " + algorithm + " (" + algs.algToString(algorithm) + ")"); out.print("Prime(p): "); out.println(b64BigInt(p.getP())); out.print("Generator(g): "); out.println(b64BigInt(p.getG())); out.print("Private_value(x): "); out.println(b64BigInt(key.getX())); out.print("Public_value(y): "); out.println(b64BigInt(pub.getY())); return sw.toString(); }
/** * Return the generated public value for this key agreement operation as a <code>BigInteger</code> * . * * @return The diffie-hellman public value as a <code>BigInteger</code>. */ public BigInteger getPublicValue() { DHPublicKey pubKey = (DHPublicKey) keyPair.getPublic(); return pubKey.getY(); }
private void testGP(int size, int privateValueSize, BigInteger g, BigInteger p) throws Exception { DHParameterSpec elParams = new DHParameterSpec(p, g, privateValueSize); KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ElGamal", "BC"); byte[] in = "This is a test".getBytes(); keyGen.initialize(elParams); KeyPair keyPair = keyGen.generateKeyPair(); SecureRandom rand = new SecureRandom(); checkKeySize(privateValueSize, keyPair); Cipher cipher = Cipher.getInstance("ElGamal", "BC"); cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic(), rand); if (cipher.getOutputSize(in.length) != (size / 8) * 2) { fail("getOutputSize wrong on encryption"); } byte[] out = cipher.doFinal(in); cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); if (cipher.getOutputSize(out.length) != (size / 8) - 1) { fail("getOutputSize wrong on decryption"); } // // No Padding - maximum length // byte[] modBytes = ((DHPublicKey) keyPair.getPublic()).getParams().getP().toByteArray(); byte[] maxInput = new byte[modBytes.length - 1]; maxInput[0] |= 0x7f; cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic(), rand); out = cipher.doFinal(maxInput); cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); out = cipher.doFinal(out); if (!areEqual(out, maxInput)) { fail( "NoPadding test failed on decrypt expected " + new String(Hex.encode(maxInput)) + " got " + new String(Hex.encode(out))); } // // encrypt/decrypt // Cipher c1 = Cipher.getInstance("ElGamal", "BC"); Cipher c2 = Cipher.getInstance("ElGamal", "BC"); c1.init(Cipher.ENCRYPT_MODE, keyPair.getPublic(), rand); byte[] out1 = c1.doFinal(in); c2.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); byte[] out2 = c2.doFinal(out1); if (!areEqual(in, out2)) { fail(size + " encrypt test failed"); } // // encrypt/decrypt with update // int outLen = c1.update(in, 0, 2, out1, 0); outLen += c1.doFinal(in, 2, in.length - 2, out1, outLen); outLen = c2.update(out1, 0, 2, out2, 0); outLen += c2.doFinal(out1, 2, out1.length - 2, out2, outLen); if (!areEqual(in, out2)) { fail(size + " encrypt with update test failed"); } // // public key encoding test // byte[] pubEnc = keyPair.getPublic().getEncoded(); KeyFactory keyFac = KeyFactory.getInstance("ElGamal", "BC"); X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); DHPublicKey pubKey = (DHPublicKey) keyFac.generatePublic(pubX509); DHParameterSpec spec = pubKey.getParams(); if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) { fail(size + " bit public key encoding/decoding test failed on parameters"); } if (!((DHPublicKey) keyPair.getPublic()).getY().equals(pubKey.getY())) { fail(size + " bit public key encoding/decoding test failed on y value"); } // // public key serialisation test // pubKey = (DHPublicKey) serializeDeserialize(keyPair.getPublic()); spec = pubKey.getParams(); if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) { fail(size + " bit public key serialisation test failed on parameters"); } if (!((DHPublicKey) keyPair.getPublic()).getY().equals(pubKey.getY())) { fail(size + " bit public key serialisation test failed on y value"); } if (!keyPair.getPublic().equals(pubKey)) { fail("equals test failed"); } if (keyPair.getPublic().hashCode() != pubKey.hashCode()) { fail("hashCode test failed"); } // // private key encoding test // byte[] privEnc = keyPair.getPrivate().getEncoded(); PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); DHPrivateKey privKey = (DHPrivateKey) keyFac.generatePrivate(privPKCS8); spec = privKey.getParams(); if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) { fail(size + " bit private key encoding/decoding test failed on parameters"); } if (!((DHPrivateKey) keyPair.getPrivate()).getX().equals(privKey.getX())) { fail(size + " bit private key encoding/decoding test failed on y value"); } // // private key serialisation test // privKey = (DHPrivateKey) serializeDeserialize(keyPair.getPrivate()); spec = privKey.getParams(); if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) { fail(size + " bit private key serialisation test failed on parameters"); } if (!((DHPrivateKey) keyPair.getPrivate()).getX().equals(privKey.getX())) { fail(size + " bit private key serialisation test failed on y value"); } if (!keyPair.getPrivate().equals(privKey)) { fail("equals test failed"); } if (keyPair.getPrivate().hashCode() != privKey.hashCode()) { fail("hashCode test failed"); } if (!(privKey instanceof PKCS12BagAttributeCarrier)) { fail("private key not implementing PKCS12 attribute carrier"); } }
private void testDefault(int privateValueSize, BigInteger g, BigInteger p) throws Exception { DHParameterSpec elParams = new DHParameterSpec(p, g, privateValueSize); int size = p.bitLength(); new BouncyCastleProvider().setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, elParams); KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ElGamal", "BC"); byte[] in = "This is a test".getBytes(); keyGen.initialize(p.bitLength()); KeyPair keyPair = keyGen.generateKeyPair(); new BouncyCastleProvider().setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, elParams); SecureRandom rand = new SecureRandom(); checkKeySize(privateValueSize, keyPair); Cipher cipher = Cipher.getInstance("ElGamal", "BC"); cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic(), rand); if (cipher.getOutputSize(in.length) != (size / 8) * 2) { fail("getOutputSize wrong on encryption"); } byte[] out = cipher.doFinal(in); cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); if (cipher.getOutputSize(out.length) != (size / 8) - 1) { fail("getOutputSize wrong on decryption"); } // // No Padding - maximum length // byte[] modBytes = ((DHPublicKey) keyPair.getPublic()).getParams().getP().toByteArray(); byte[] maxInput = new byte[modBytes.length - 1]; maxInput[0] |= 0x7f; cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic(), rand); out = cipher.doFinal(maxInput); cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); out = cipher.doFinal(out); if (!areEqual(out, maxInput)) { fail( "NoPadding test failed on decrypt expected " + new String(Hex.encode(maxInput)) + " got " + new String(Hex.encode(out))); } // // encrypt/decrypt // Cipher c1 = Cipher.getInstance("ElGamal", "BC"); Cipher c2 = Cipher.getInstance("ElGamal", "BC"); c1.init(Cipher.ENCRYPT_MODE, keyPair.getPublic(), rand); byte[] out1 = c1.doFinal(in); c2.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); byte[] out2 = c2.doFinal(out1); if (!areEqual(in, out2)) { fail(size + " encrypt test failed"); } // // encrypt/decrypt with update // int outLen = c1.update(in, 0, 2, out1, 0); outLen += c1.doFinal(in, 2, in.length - 2, out1, outLen); outLen = c2.update(out1, 0, 2, out2, 0); outLen += c2.doFinal(out1, 2, out1.length - 2, out2, outLen); if (!areEqual(in, out2)) { fail(size + " encrypt with update test failed"); } // // public key encoding test // byte[] pubEnc = keyPair.getPublic().getEncoded(); KeyFactory keyFac = KeyFactory.getInstance("ElGamal", "BC"); X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); DHPublicKey pubKey = (DHPublicKey) keyFac.generatePublic(pubX509); DHParameterSpec spec = pubKey.getParams(); if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) { fail(size + " bit public key encoding/decoding test failed on parameters"); } if (!((DHPublicKey) keyPair.getPublic()).getY().equals(pubKey.getY())) { fail(size + " bit public key encoding/decoding test failed on y value"); } // // public key serialisation test // ByteArrayOutputStream bOut = new ByteArrayOutputStream(); ObjectOutputStream oOut = new ObjectOutputStream(bOut); oOut.writeObject(keyPair.getPublic()); ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); ObjectInputStream oIn = new ObjectInputStream(bIn); pubKey = (DHPublicKey) oIn.readObject(); spec = pubKey.getParams(); if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) { fail(size + " bit public key serialisation test failed on parameters"); } if (!((DHPublicKey) keyPair.getPublic()).getY().equals(pubKey.getY())) { fail(size + " bit public key serialisation test failed on y value"); } // // private key encoding test // byte[] privEnc = keyPair.getPrivate().getEncoded(); PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); DHPrivateKey privKey = (DHPrivateKey) keyFac.generatePrivate(privPKCS8); spec = privKey.getParams(); if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) { fail(size + " bit private key encoding/decoding test failed on parameters"); } if (!((DHPrivateKey) keyPair.getPrivate()).getX().equals(privKey.getX())) { fail(size + " bit private key encoding/decoding test failed on y value"); } // // private key serialisation test // bOut = new ByteArrayOutputStream(); oOut = new ObjectOutputStream(bOut); oOut.writeObject(keyPair.getPrivate()); bIn = new ByteArrayInputStream(bOut.toByteArray()); oIn = new ObjectInputStream(bIn); privKey = (DHPrivateKey) oIn.readObject(); spec = privKey.getParams(); if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) { fail(size + " bit private key serialisation test failed on parameters"); } if (!((DHPrivateKey) keyPair.getPrivate()).getX().equals(privKey.getX())) { fail(size + " bit private key serialisation test failed on y value"); } }
JCEElGamalPublicKey(DHPublicKey key) { this.y = key.getY(); this.elSpec = new ElGamalParameterSpec(key.getParams().getP(), key.getParams().getG()); }
private StringBuffer outputKeyCreation(int loop, boolean kekOnly, String kekTest) { StringBuffer buf = new StringBuffer(); loop++; if (loop > 100) { // only loop 100 times; then throw an exception throw new IllegalStateException("Unable to create 128 byte keys in 100 tries"); } // place holder for the keys DHPrivateKey privateKey = null; DHPublicKey publicKey = null; if (!kekOnly) { KeyPair keyPair = null; try { keyPair = this.createKeys(); } catch (NoSuchAlgorithmException e) { Debug.logError(e, module); } catch (InvalidAlgorithmParameterException e) { Debug.logError(e, module); } catch (InvalidKeySpecException e) { Debug.logError(e, module); } if (keyPair != null) { publicKey = (DHPublicKey) keyPair.getPublic(); privateKey = (DHPrivateKey) keyPair.getPrivate(); if (publicKey == null || publicKey.getY().toByteArray().length != 128) { // run again until we get a 128 byte public key for VL return this.outputKeyCreation(loop, kekOnly, kekTest); } } else { Debug.logInfo("Returned a null KeyPair", module); return this.outputKeyCreation(loop, kekOnly, kekTest); } } else { // use our existing private key to generate a KEK try { privateKey = (DHPrivateKey) this.getPrivateKey(); } catch (Exception e) { Debug.logError(e, module); } } // the KEK byte[] kekBytes = null; try { kekBytes = this.generateKek(privateKey); } catch (NoSuchAlgorithmException e) { Debug.logError(e, module); } catch (InvalidKeySpecException e) { Debug.logError(e, module); } catch (InvalidKeyException e) { Debug.logError(e, module); } // the 3DES KEK value SecretKey loadedKek = this.getDesEdeKey(kekBytes); byte[] loadKekBytes = loadedKek.getEncoded(); // test the KEK Cipher cipher = this.getCipher(this.getKekKey(), Cipher.ENCRYPT_MODE); byte[] kekTestB = {0, 0, 0, 0, 0, 0, 0, 0}; byte[] kekTestC = new byte[0]; if (kekTest != null) { kekTestB = StringUtil.fromHexString(kekTest); } // encrypt the test bytes try { kekTestC = cipher.doFinal(kekTestB); } catch (Exception e) { Debug.logError(e, module); } if (!kekOnly) { // public key (just Y) BigInteger y = publicKey.getY(); byte[] yBytes = y.toByteArray(); String yHex = StringUtil.toHexString(yBytes); buf.append("======== Begin Public Key (Y @ ") .append(yBytes.length) .append(" / ") .append(yHex.length()) .append(") ========\n"); buf.append(yHex).append("\n"); buf.append("======== End Public Key ========\n\n"); // private key (just X) BigInteger x = privateKey.getX(); byte[] xBytes = x.toByteArray(); String xHex = StringUtil.toHexString(xBytes); buf.append("======== Begin Private Key (X @ ") .append(xBytes.length) .append(" / ") .append(xHex.length()) .append(") ========\n"); buf.append(xHex).append("\n"); buf.append("======== End Private Key ========\n\n"); // private key (full) byte[] privateBytes = privateKey.getEncoded(); String privateHex = StringUtil.toHexString(privateBytes); buf.append("======== Begin Private Key (Full @ ") .append(privateBytes.length) .append(" / ") .append(privateHex.length()) .append(") ========\n"); buf.append(privateHex).append("\n"); buf.append("======== End Private Key ========\n\n"); } if (kekBytes != null) { buf.append("======== Begin KEK (").append(kekBytes.length).append(") ========\n"); buf.append(StringUtil.toHexString(kekBytes)).append("\n"); buf.append("======== End KEK ========\n\n"); buf.append("======== Begin KEK (DES) (").append(loadKekBytes.length).append(") ========\n"); buf.append(StringUtil.toHexString(loadKekBytes)).append("\n"); buf.append("======== End KEK (DES) ========\n\n"); buf.append("======== Begin KEK Test (").append(kekTestC.length).append(") ========\n"); buf.append(StringUtil.toHexString(kekTestC)).append("\n"); buf.append("======== End KEK Test ========\n\n"); } else { Debug.logError("KEK came back empty", module); } return buf; }
/** * Perform CA (Chip Authentication) part of EAC (version 1). For details see TR-03110 ver. 1.11. * In short, we authenticate the chip with (EC)DH key agreement protocol and create new secure * messaging keys. * * @param keyId passport's public key id (stored in DG14), -1 if none * @param publicKey passport's public key (stored in DG14) * @return the chip authentication result * @throws CardServiceException if CA failed or some error occurred */ public synchronized ChipAuthenticationResult doCA(BigInteger keyId, PublicKey publicKey) throws CardServiceException { if (publicKey == null) { throw new IllegalArgumentException("Public key is null"); } try { String agreementAlg = Util.inferKeyAgreementAlgorithm(publicKey); KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(agreementAlg); AlgorithmParameterSpec params = null; if ("DH".equals(agreementAlg)) { DHPublicKey dhPublicKey = (DHPublicKey) publicKey; params = dhPublicKey.getParams(); } else if ("ECDH".equals(agreementAlg)) { ECPublicKey ecPublicKey = (ECPublicKey) publicKey; params = ecPublicKey.getParams(); } else { throw new IllegalStateException("Unsupported algorithm \"" + agreementAlg + "\""); } keyPairGenerator.initialize(params); KeyPair keyPair = keyPairGenerator.generateKeyPair(); KeyAgreement agreement = KeyAgreement.getInstance(agreementAlg); agreement.init(keyPair.getPrivate()); agreement.doPhase(publicKey, true); byte[] secret = agreement.generateSecret(); // TODO: this SHA1ing may have to be removed? // TODO: this hashing is needed for our Java Card passport applet implementation // byte[] secret = md.digest(secret); byte[] keyData = null; byte[] idData = null; byte[] keyHash = new byte[0]; if ("DH".equals(agreementAlg)) { DHPublicKey dhPublicKey = (DHPublicKey) keyPair.getPublic(); keyData = dhPublicKey.getY().toByteArray(); // TODO: this is probably wrong, what should be hashed? MessageDigest md = MessageDigest.getInstance("SHA1"); md = MessageDigest.getInstance("SHA1"); keyHash = md.digest(keyData); } else if ("ECDH".equals(agreementAlg)) { org.bouncycastle.jce.interfaces.ECPublicKey ecPublicKey = (org.bouncycastle.jce.interfaces.ECPublicKey) keyPair.getPublic(); keyData = ecPublicKey.getQ().getEncoded(); byte[] t = Util.i2os(ecPublicKey.getQ().getX().toBigInteger()); keyHash = Util.alignKeyDataToSize(t, ecPublicKey.getParameters().getCurve().getFieldSize() / 8); } keyData = Util.wrapDO((byte) 0x91, keyData); if (keyId.compareTo(BigInteger.ZERO) >= 0) { byte[] keyIdBytes = keyId.toByteArray(); idData = Util.wrapDO((byte) 0x84, keyIdBytes); } sendMSEKAT(wrapper, keyData, idData); SecretKey ksEnc = Util.deriveKey(secret, Util.ENC_MODE); SecretKey ksMac = Util.deriveKey(secret, Util.MAC_MODE); long ssc = 0; wrapper = new DESedeSecureMessagingWrapper(ksEnc, ksMac, ssc); state = CA_AUTHENTICATED_STATE; return new ChipAuthenticationResult(keyId, publicKey, keyHash, keyPair); } catch (GeneralSecurityException e) { throw new CardServiceException(e.toString()); } }