public void test_key(BigInteger keyId, String passphrase) throws Exception { PGPSecretKeyRingCollection secretKeyRing = loadSecretKeyCollection("secring.gpg"); PGPSecretKeyRing secretKey = secretKeyRing.getSecretKeyRing(keyId.longValue()); assertNotNull("Could not locate secret keyring with Id=" + keyId.toString(16), secretKey); PGPSecretKey key = secretKey.getSecretKey(); assertNotNull("Could not locate secret key!", key); try { PGPDigestCalculatorProvider calcProvider = new JcaPGPDigestCalculatorProviderBuilder() .setProvider(BouncyCastleProvider.PROVIDER_NAME) .build(); PBESecretKeyDecryptor decryptor = new JcePBESecretKeyDecryptorBuilder(calcProvider) .setProvider(BouncyCastleProvider.PROVIDER_NAME) .build(passphrase.toCharArray()); PGPPrivateKey privateKey = key.extractPrivateKey(decryptor); assertTrue(privateKey.getKeyID() == keyId.longValue()); } catch (PGPException e) { throw new PGPException("Password incorrect!", e); } // all fine! }
private void createSignature(OutputStream out) throws Exception { PGPSecretKey pgpSec = readSecretKey(); PGPPrivateKey pgpPrivKey = pgpSec.extractPrivateKey( new JcePBESecretKeyDecryptorBuilder() .setProvider(getProvider()) .build("sdude".toCharArray())); PGPSignatureGenerator sGen = new PGPSignatureGenerator( new JcaPGPContentSignerBuilder(pgpSec.getPublicKey().getAlgorithm(), PGPUtil.SHA1) .setProvider(getProvider())); sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey); BCPGOutputStream bOut = new BCPGOutputStream(out); InputStream fIn = new ByteArrayInputStream("Test Signature".getBytes("UTF-8")); int ch; while ((ch = fIn.read()) >= 0) { sGen.update((byte) ch); } fIn.close(); sGen.generate().encode(bOut); }
/** * Reads private key from the provided InputStream * * @param input InputStream of the private key * @return PGPSecretKey * @throws LRException NO_KEY error if the key cannot be obtained from the input stream */ private PGPSecretKey readSecretKey(InputStream input) throws LRException { PGPSecretKeyRingCollection pgpSec; try { pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(input)); } catch (Exception e) { throw new LRException(LRException.NO_KEY); } java.util.Iterator keyRingIter = pgpSec.getKeyRings(); while (keyRingIter.hasNext()) { PGPSecretKeyRing keyRing = (PGPSecretKeyRing) keyRingIter.next(); java.util.Iterator keyIter = keyRing.getSecretKeys(); while (keyIter.hasNext()) { PGPSecretKey key = (PGPSecretKey) keyIter.next(); if (key.isSigningKey()) { return key; } } } throw new LRException(LRException.NO_KEY); }
/** * Encodes the provided message with the private key and pass phrase set in configuration * * @param message Message to encode * @return Encoded message * @throws LRException SIGNING_FAILED if the document cannot be signed, NO_KEY if the key cannot * be obtained */ private String signEnvelopeData(String message) throws LRException { // Get an InputStream for the private key InputStream privateKeyStream = getPrivateKeyStream(privateKey); // Get an OutputStream for the result ByteArrayOutputStream result = new ByteArrayOutputStream(); ArmoredOutputStream aOut = new ArmoredOutputStream(result); // Get the pass phrase char[] privateKeyPassword = passPhrase.toCharArray(); try { // Get the private key from the InputStream PGPSecretKey sk = readSecretKey(privateKeyStream); PGPPrivateKey pk = sk.extractPrivateKey(privateKeyPassword, "BC"); PGPSignatureGenerator pgp = new PGPSignatureGenerator(sk.getPublicKey().getAlgorithm(), PGPUtil.SHA256, "BC"); PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); // Clear sign the message java.util.Iterator it = sk.getPublicKey().getUserIDs(); if (it.hasNext()) { spGen.setSignerUserID(false, (String) it.next()); pgp.setHashedSubpackets(spGen.generate()); } aOut.beginClearText(PGPUtil.SHA256); pgp.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT, pk); byte[] msg = message.getBytes(); pgp.update(msg, 0, msg.length); aOut.write(msg, 0, msg.length); BCPGOutputStream bOut = new BCPGOutputStream(aOut); aOut.endClearText(); pgp.generate().encode(bOut); String strResult = result.toString("utf8"); return strResult; } catch (Exception e) { throw new LRException(LRException.SIGNING_FAILED); } finally { try { if (privateKeyStream != null) { privateKeyStream.close(); } aOut.close(); result.close(); } catch (IOException e) { // Could not close the streams } } }
/** Creates a {@link PersonalKey} from private and public key byte buffers. */ @SuppressWarnings("unchecked") public static PersonalKey load(byte[] privateKeyData, char[] passphrase, byte[] bridgeCertData) throws KonException, IOException, PGPException, CertificateException, NoSuchProviderException { PGPSecretKeyRing secRing = new PGPSecretKeyRing(privateKeyData, PGPUtils.FP_CALC); PGPSecretKey authKey = null; PGPSecretKey signKey = null; PGPSecretKey encrKey = null; // assign from key ring Iterator<PGPSecretKey> skeys = secRing.getSecretKeys(); while (skeys.hasNext()) { PGPSecretKey key = skeys.next(); if (key.isMasterKey()) { // master key: authentication / legacy: signing authKey = key; } else { // sub keys: encryption and signing / legacy: only encryption int keyFlags = PGPUtils.getKeyFlags(key.getPublicKey()); if ((keyFlags & PGPKeyFlags.CAN_SIGN) == PGPKeyFlags.CAN_SIGN) signKey = key; else encrKey = key; } } // legacy: auth key is actually signing key if (signKey == null && authKey != null && authKey.isSigningKey()) { LOGGER.info("loading legacy key"); signKey = authKey; } if (authKey == null || signKey == null || encrKey == null) throw new KonException( KonException.Error.LOAD_KEY, new PGPException("could not found all keys in key data")); // decrypt private PGPDigestCalculatorProvider calcProv = new JcaPGPDigestCalculatorProviderBuilder().build(); PBESecretKeyDecryptor decryptor = new JcePBESecretKeyDecryptorBuilder(calcProv) .setProvider(PGPUtils.PROVIDER) .build(passphrase); PGPKeyPair authKeyPair = PGPUtils.decrypt(authKey, decryptor); PGPKeyPair signKeyPair = PGPUtils.decrypt(signKey, decryptor); PGPKeyPair encryptKeyPair = PGPUtils.decrypt(encrKey, decryptor); // X.509 bridge certificate X509Certificate bridgeCert = PGPUtils.loadX509Cert(bridgeCertData); return new PersonalKey(authKeyPair, signKeyPair, encryptKeyPair, bridgeCert); }
/** * Replace the passed the public key on the passed in secret key. * * @param secretKey secret key to change * @param publicKey new public key. * @return a new secret key. * @throws IllegalArgumentException if keyIDs do not match. */ public static PGPSecretKey replacePublicKey(PGPSecretKey secretKey, PGPPublicKey publicKey) { if (publicKey.getKeyID() != secretKey.getKeyID()) { throw new IllegalArgumentException("keyIDs do not match"); } return new PGPSecretKey(secretKey.secret, publicKey); }
/** * Create a clear sign signature over the input data. (Not detached) * * @param input the content to be signed * @param keyring the keyring * @param keyId the 4 bytes identifier of the key, in hexadecimal format * @param passphrase the passphrase to retrieve the private key * @param output the output destination of the signature */ public static void clearSign( InputStream input, InputStream keyring, String keyId, String passphrase, OutputStream output) throws IOException, PGPException, GeneralSecurityException { PGPSecretKey secretKey = getSecretKey(keyring, keyId); PGPPrivateKey privateKey = secretKey.extractPrivateKey( new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()) .build(passphrase.toCharArray())); int digest = PGPUtil.SHA1; PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator( new BcPGPContentSignerBuilder(secretKey.getPublicKey().getAlgorithm(), digest)); signatureGenerator.init(PGPSignature.CANONICAL_TEXT_DOCUMENT, privateKey); ArmoredOutputStream armoredOutput = new ArmoredOutputStream(output); armoredOutput.beginClearText(digest); BufferedReader reader = new BufferedReader(new InputStreamReader(input)); String line; while ((line = reader.readLine()) != null) { // trailing spaces must be removed for signature calculation (see // http://tools.ietf.org/html/rfc4880#section-7.1) byte[] data = trim(line).getBytes("UTF-8"); armoredOutput.write(data); armoredOutput.write(EOL); signatureGenerator.update(data); signatureGenerator.update(EOL); } armoredOutput.endClearText(); PGPSignature signature = signatureGenerator.generate(); signature.encode(new BCPGOutputStream(armoredOutput)); armoredOutput.close(); }
static PGPSecretKey readSecretKey() throws Exception { InputStream input = new ByteArrayInputStream(getSecKeyRing()); PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(input)); @SuppressWarnings("rawtypes") Iterator keyRingIter = pgpSec.getKeyRings(); while (keyRingIter.hasNext()) { PGPSecretKeyRing keyRing = (PGPSecretKeyRing) keyRingIter.next(); @SuppressWarnings("rawtypes") Iterator keyIter = keyRing.getSecretKeys(); while (keyIter.hasNext()) { PGPSecretKey key = (PGPSecretKey) keyIter.next(); if (key.isSigningKey()) { return key; } } } throw new IllegalArgumentException("Can't find signing key in key ring."); }
/** * Returns the secret key matching the specified identifier. * * @param input the input stream containing the keyring collection * @param keyId the 4 bytes identifier of the key */ private static PGPSecretKey getSecretKey(InputStream input, String keyId) throws IOException, PGPException { PGPSecretKeyRingCollection keyrings = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(input)); Iterator rIt = keyrings.getKeyRings(); while (rIt.hasNext()) { PGPSecretKeyRing kRing = (PGPSecretKeyRing) rIt.next(); Iterator kIt = kRing.getSecretKeys(); while (kIt.hasNext()) { PGPSecretKey key = (PGPSecretKey) kIt.next(); if (key.isSigningKey() && Long.toHexString(key.getKeyID() & 0xFFFFFFFFL).equals(keyId.toLowerCase())) { return key; } } } return null; }
/** * Return a copy of the passed in secret key, encrypted using a new password and the passed in * algorithm. * * @param key the PGPSecretKey to be copied. * @param oldKeyDecryptor the current decryptor based on the current password for key. * @param newKeyEncryptor a new encryptor based on a new password for encrypting the secret key * material. */ public static PGPSecretKey copyWithNewPassword( PGPSecretKey key, PBESecretKeyDecryptor oldKeyDecryptor, PBESecretKeyEncryptor newKeyEncryptor) throws PGPException { if (key.isPrivateKeyEmpty()) { throw new PGPException("no private key in this SecretKey - public key present only."); } byte[] rawKeyData = key.extractKeyData(oldKeyDecryptor); int s2kUsage = key.secret.getS2KUsage(); byte[] iv = null; S2K s2k = null; byte[] keyData; int newEncAlgorithm = SymmetricKeyAlgorithmTags.NULL; if (newKeyEncryptor == null || (newKeyEncryptor.getAlgorithm() == SymmetricKeyAlgorithmTags.NULL && !(newKeyEncryptor instanceof GnuDivertToCardSecretKeyEncryptor))) { s2kUsage = SecretKeyPacket.USAGE_NONE; if (key.secret.getS2KUsage() == SecretKeyPacket.USAGE_SHA1) // SHA-1 hash, need to rewrite checksum { keyData = new byte[rawKeyData.length - 18]; System.arraycopy(rawKeyData, 0, keyData, 0, keyData.length - 2); byte[] check = checksum(null, keyData, keyData.length - 2); keyData[keyData.length - 2] = check[0]; keyData[keyData.length - 1] = check[1]; } else { keyData = rawKeyData; } } else { if (key.secret.getPublicKeyPacket().getVersion() < 4) { // Version 2 or 3 - RSA Keys only byte[] encKey = newKeyEncryptor.getKey(); keyData = new byte[rawKeyData.length]; if (newKeyEncryptor.getHashAlgorithm() != HashAlgorithmTags.MD5) { throw new PGPException("MD5 Digest Calculator required for version 3 key encryptor."); } // // process 4 numbers // int pos = 0; for (int i = 0; i != 4; i++) { int encLen = (((rawKeyData[pos] << 8) | (rawKeyData[pos + 1] & 0xff)) + 7) / 8; keyData[pos] = rawKeyData[pos]; keyData[pos + 1] = rawKeyData[pos + 1]; byte[] tmp; if (i == 0) { tmp = newKeyEncryptor.encryptKeyData(encKey, rawKeyData, pos + 2, encLen); iv = newKeyEncryptor.getCipherIV(); } else { byte[] tmpIv = new byte[iv.length]; System.arraycopy(keyData, pos - iv.length, tmpIv, 0, tmpIv.length); tmp = newKeyEncryptor.encryptKeyData(encKey, tmpIv, rawKeyData, pos + 2, encLen); } System.arraycopy(tmp, 0, keyData, pos + 2, tmp.length); pos += 2 + encLen; } // // copy in checksum. // keyData[pos] = rawKeyData[pos]; keyData[pos + 1] = rawKeyData[pos + 1]; s2k = newKeyEncryptor.getS2K(); newEncAlgorithm = newKeyEncryptor.getAlgorithm(); } else { if (s2kUsage == SecretKeyPacket.USAGE_NONE) { s2kUsage = SecretKeyPacket.USAGE_SHA1; } keyData = newKeyEncryptor.encryptKeyData(rawKeyData, 0, rawKeyData.length); iv = newKeyEncryptor.getCipherIV(); s2k = newKeyEncryptor.getS2K(); newEncAlgorithm = newKeyEncryptor.getAlgorithm(); } } SecretKeyPacket secret; if (key.secret instanceof SecretSubkeyPacket) { secret = new SecretSubkeyPacket( key.secret.getPublicKeyPacket(), newEncAlgorithm, s2kUsage, s2k, iv, keyData); } else { secret = new SecretKeyPacket( key.secret.getPublicKeyPacket(), newEncAlgorithm, s2kUsage, s2k, iv, keyData); } return new PGPSecretKey(secret, key.pub); }