/** * Extract a PGPPrivate key from the SecretKey's encrypted contents. * * @param decryptorFactory factory to use to generate a decryptor for the passed in secretKey. * @return PGPPrivateKey the unencrypted private key. * @throws PGPException on failure. */ public PGPPrivateKey extractPrivateKey(PBESecretKeyDecryptor decryptorFactory) throws PGPException { if (isPrivateKeyEmpty()) { return null; } PublicKeyPacket pubPk = secret.getPublicKeyPacket(); try { byte[] data = extractKeyData(decryptorFactory); BCPGInputStream in = new BCPGInputStream(new ByteArrayInputStream(data)); switch (pubPk.getAlgorithm()) { case PGPPublicKey.RSA_ENCRYPT: case PGPPublicKey.RSA_GENERAL: case PGPPublicKey.RSA_SIGN: RSASecretBCPGKey rsaPriv = new RSASecretBCPGKey(in); return new PGPPrivateKey(this.getKeyID(), pubPk, rsaPriv); case PGPPublicKey.DSA: DSASecretBCPGKey dsaPriv = new DSASecretBCPGKey(in); return new PGPPrivateKey(this.getKeyID(), pubPk, dsaPriv); case PGPPublicKey.ELGAMAL_ENCRYPT: case PGPPublicKey.ELGAMAL_GENERAL: ElGamalSecretBCPGKey elPriv = new ElGamalSecretBCPGKey(in); return new PGPPrivateKey(this.getKeyID(), pubPk, elPriv); default: throw new PGPException("unknown public key algorithm encountered"); } } catch (PGPException e) { throw e; } catch (Exception e) { throw new PGPException("Exception constructing key", e); } }
private byte[] extractKeyData(PBESecretKeyDecryptor decryptorFactory) throws PGPException { byte[] encData = secret.getSecretKeyData(); byte[] data = null; if (secret.getEncAlgorithm() != SymmetricKeyAlgorithmTags.NULL) { try { if (secret.getPublicKeyPacket().getVersion() == 4) { byte[] key = decryptorFactory.makeKeyFromPassPhrase(secret.getEncAlgorithm(), secret.getS2K()); data = decryptorFactory.recoverKeyData( secret.getEncAlgorithm(), key, secret.getIV(), encData, 0, encData.length); boolean useSHA1 = secret.getS2KUsage() == SecretKeyPacket.USAGE_SHA1; byte[] check = checksum( useSHA1 ? decryptorFactory.getChecksumCalculator(HashAlgorithmTags.SHA1) : null, data, (useSHA1) ? data.length - 20 : data.length - 2); for (int i = 0; i != check.length; i++) { if (check[i] != data[data.length - check.length + i]) { throw new PGPException("checksum mismatch at " + i + " of " + check.length); } } } else // version 2 or 3, RSA only. { byte[] key = decryptorFactory.makeKeyFromPassPhrase(secret.getEncAlgorithm(), secret.getS2K()); data = new byte[encData.length]; byte[] iv = new byte[secret.getIV().length]; System.arraycopy(secret.getIV(), 0, iv, 0, iv.length); // // read in the four numbers // int pos = 0; for (int i = 0; i != 4; i++) { int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8; data[pos] = encData[pos]; data[pos + 1] = encData[pos + 1]; byte[] tmp = decryptorFactory.recoverKeyData( secret.getEncAlgorithm(), key, iv, encData, pos + 2, encLen); System.arraycopy(tmp, 0, data, pos + 2, tmp.length); pos += 2 + encLen; if (i != 3) { System.arraycopy(encData, pos - iv.length, iv, 0, iv.length); } } // // verify and copy checksum // data[pos] = encData[pos]; data[pos + 1] = encData[pos + 1]; int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff); int calcCs = 0; for (int j = 0; j < data.length - 2; j++) { calcCs += data[j] & 0xff; } calcCs &= 0xffff; if (calcCs != cs) { throw new PGPException( "checksum mismatch: passphrase wrong, expected " + Integer.toHexString(cs) + " found " + Integer.toHexString(calcCs)); } } } catch (PGPException e) { throw e; } catch (Exception e) { throw new PGPException("Exception decrypting key", e); } } else { data = encData; } return data; }