Example #1
0
  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();
  }
Example #2
0
  /**
   * 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;
  }
Example #4
0
 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);
   }
 }
Example #5
0
  /**
   * 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;
  }
Example #6
0
  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;
 }
Example #9
0
  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();
 }
Example #13
0
  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");
    }
  }
Example #14
0
  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());
 }
Example #16
0
  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;
  }
Example #17
0
  /**
   * 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());
    }
  }