package org.bouncycastle.openpgp.test; import org.bouncycastle.bcpg.CompressionAlgorithmTags; import org.bouncycastle.bcpg.HashAlgorithmTags; import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; import org.bouncycastle.bcpg.SignatureSubpacketTags; import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; import org.bouncycastle.bcpg.sig.KeyFlags; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPLiteralData; import org.bouncycastle.openpgp.PGPLiteralDataGenerator; import org.bouncycastle.openpgp.PGPObjectFactory; import org.bouncycastle.openpgp.PGPOnePassSignature; import org.bouncycastle.openpgp.PGPOnePassSignatureList; import org.bouncycastle.openpgp.PGPPrivateKey; import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureGenerator; import org.bouncycastle.openpgp.PGPSignatureList; import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; import org.bouncycastle.openpgp.PGPV3SignatureGenerator; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.test.SimpleTest; import org.bouncycastle.util.test.UncloseableOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.NoSuchProviderException; import java.security.Security; import java.security.SignatureException; import java.util.Date; public class PGPSignatureTest extends SimpleTest { private static final int[] NO_PREFERENCES = null; private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[] { SymmetricKeyAlgorithmTags.AES_128, SymmetricKeyAlgorithmTags.TRIPLE_DES }; private static final int[] PREFERRED_HASH_ALGORITHMS = new int[] { HashAlgorithmTags.SHA1, HashAlgorithmTags.SHA256 }; private static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[] { CompressionAlgorithmTags.ZLIB }; private static final int TEST_EXPIRATION_TIME = 10000; private static final String TEST_USER_ID = "test user id"; private static final byte[] TEST_DATA = "hello world!\nhello world!\n".getBytes(); private static final byte[] TEST_DATA_WITH_CRLF = "hello world!\r\nhello world!\r\n".getBytes(); byte[] dsaKeyRing = Base64.decode( "lQHhBD9HBzURBACzkxRCVGJg5+Ld9DU4Xpnd4LCKgMq7YOY7Gi0EgK92gbaa6+zQ" + "oQFqz1tt3QUmpz3YVkm/zLESBBtC1ACIXGggUdFMUr5I87+1Cb6vzefAtGt8N5VV" + "1F/MXv1gJz4Bu6HyxL/ncfe71jsNhav0i4yAjf2etWFj53zK6R+Ojg5H6wCgpL9/" + "tXVfGP8SqFvyrN/437MlFSUEAIN3V6j/MUllyrZglrtr2+RWIwRrG/ACmrF6hTug" + "Ol4cQxaDYNcntXbhlTlJs9MxjTH3xxzylyirCyq7HzGJxZzSt6FTeh1DFYzhJ7Qu" + "YR1xrSdA6Y0mUv0ixD5A4nPHjupQ5QCqHGeRfFD/oHzD4zqBnJp/BJ3LvQ66bERJ" + "mKl5A/4uj3HoVxpb0vvyENfRqKMmGBISycY4MoH5uWfb23FffsT9r9KL6nJ4syLz" + "aRR0gvcbcjkc9Z3epI7gr3jTrb4d8WPxsDbT/W1tv9bG/EHawomLcihtuUU68Uej" + "6/wZot1XJqu2nQlku57+M/V2X1y26VKsipolPfja4uyBOOyvbP4DAwIDIBTxWjkC" + "GGAWQO2jy9CTvLHJEoTO7moHrp1FxOVpQ8iJHyRqZzLllO26OzgohbiPYz8u9qCu" + "lZ9Xn7QzRXJpYyBFY2hpZG5hIChEU0EgVGVzdCBLZXkpIDxlcmljQGJvdW5jeWNh" + "c3RsZS5vcmc+iFkEExECABkFAj9HBzUECwcDAgMVAgMDFgIBAh4BAheAAAoJEM0j" + "9enEyjRDAlwAnjTjjt57NKIgyym7OTCwzIU3xgFpAJ0VO5m5PfQKmGJRhaewLSZD" + "4nXkHg=="); char[] dsaPass = "hello world".toCharArray(); byte[] rsaKeyRing = Base64.decode( "lQIEBEBXUNMBBADScQczBibewnbCzCswc/9ut8R0fwlltBRxMW0NMdKJY2LF" + "7k2COeLOCIU95loJGV6ulbpDCXEO2Jyq8/qGw1qD3SCZNXxKs3GS8Iyh9Uwd" + "VL07nMMYl5NiQRsFB7wOb86+94tYWgvikVA5BRP5y3+O3GItnXnpWSJyREUy" + "6WI2QQAGKf4JAwIVmnRs4jtTX2DD05zy2mepEQ8bsqVAKIx7lEwvMVNcvg4Y" + "8vFLh9Mf/uNciwL4Se/ehfKQ/AT0JmBZduYMqRU2zhiBmxj4cXUQ0s36ysj7" + "fyDngGocDnM3cwPxaTF1ZRBQHSLewP7dqE7M73usFSz8vwD/0xNOHFRLKbsO" + "RqDlLA1Cg2Yd0wWPS0o7+qqk9ndqrjjSwMM8ftnzFGjShAdg4Ca7fFkcNePP" + "/rrwIH472FuRb7RbWzwXA4+4ZBdl8D4An0dwtfvAO+jCZSrLjmSpxEOveJxY" + "GduyR4IA4lemvAG51YHTHd4NXheuEqsIkn1yarwaaj47lFPnxNOElOREMdZb" + "nkWQb1jfgqO24imEZgrLMkK9bJfoDnlF4k6r6hZOp5FSFvc5kJB4cVo1QJl4" + "pwCSdoU6luwCggrlZhDnkGCSuQUUW45NE7Br22NGqn4/gHs0KCsWbAezApGj" + "qYUCfX1bcpPzUMzUlBaD5rz2vPeO58CDtBJ0ZXN0ZXIgPHRlc3RAdGVzdD6I" + "sgQTAQIAHAUCQFdQ0wIbAwQLBwMCAxUCAwMWAgECHgECF4AACgkQs8JyyQfH" + "97I1QgP8Cd+35maM2cbWV9iVRO+c5456KDi3oIUSNdPf1NQrCAtJqEUhmMSt" + "QbdiaFEkPrORISI/2htXruYn0aIpkCfbUheHOu0sef7s6pHmI2kOQPzR+C/j" + "8D9QvWsPOOso81KU2axUY8zIer64Uzqc4szMIlLw06c8vea27RfgjBpSCryw" + "AgAA"); char[] rsaPass = "2002 Buffalo Sabres".toCharArray(); byte[] nullPacketsSubKeyBinding = Base64.decode( "iDYEGBECAAAAACp9AJ9PlJCrFpi+INwG7z61eku2Wg1HaQCgl33X5Egj+Kf7F9CXIWj2iFCvQDo="); public void performTest() throws Exception { // // RSA tests // PGPSecretKeyRing pgpPriv = new PGPSecretKeyRing(rsaKeyRing); PGPSecretKey secretKey = pgpPriv.getSecretKey(); PGPPrivateKey pgpPrivKey = secretKey.extractPrivateKey(rsaPass, "BC"); try { testSig(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1, secretKey.getPublicKey(), pgpPrivKey); fail("RSA wrong key test failed."); } catch (PGPException e) { // expected } try { testSigV3(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1, secretKey.getPublicKey(), pgpPrivKey); fail("RSA V3 wrong key test failed."); } catch (PGPException e) { // expected } // // certifications // PGPSignatureGenerator sGen = new PGPSignatureGenerator(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1, "BC"); sGen.initSign(PGPSignature.KEY_REVOCATION, pgpPrivKey); PGPSignature sig = sGen.generateCertification(secretKey.getPublicKey()); sig.initVerify(secretKey.getPublicKey(), "BC"); if (!sig.verifyCertification(secretKey.getPublicKey())) { fail("revocation verification failed."); } PGPSecretKeyRing pgpDSAPriv = new PGPSecretKeyRing(dsaKeyRing); PGPSecretKey secretDSAKey = pgpDSAPriv.getSecretKey(); PGPPrivateKey pgpPrivDSAKey = secretDSAKey.extractPrivateKey(dsaPass, "BC"); sGen = new PGPSignatureGenerator(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1, "BC"); sGen.initSign(PGPSignature.SUBKEY_BINDING, pgpPrivDSAKey); PGPSignatureSubpacketGenerator unhashedGen = new PGPSignatureSubpacketGenerator(); PGPSignatureSubpacketGenerator hashedGen = new PGPSignatureSubpacketGenerator(); hashedGen.setSignatureExpirationTime(false, TEST_EXPIRATION_TIME); hashedGen.setSignerUserID(true, TEST_USER_ID); hashedGen.setPreferredCompressionAlgorithms(false, PREFERRED_COMPRESSION_ALGORITHMS); hashedGen.setPreferredHashAlgorithms(false, PREFERRED_HASH_ALGORITHMS); hashedGen.setPreferredSymmetricAlgorithms(false, PREFERRED_SYMMETRIC_ALGORITHMS); sGen.setHashedSubpackets(hashedGen.generate()); sGen.setUnhashedSubpackets(unhashedGen.generate()); sig = sGen.generateCertification(secretDSAKey.getPublicKey(), secretKey.getPublicKey()); byte[] sigBytes = sig.getEncoded(); PGPObjectFactory f = new PGPObjectFactory(sigBytes); sig = ((PGPSignatureList) f.nextObject()).get(0); sig.initVerify(secretDSAKey.getPublicKey(), "BC"); if (!sig.verifyCertification(secretDSAKey.getPublicKey(), secretKey.getPublicKey())) { fail("subkey binding verification failed."); } PGPSignatureSubpacketVector hashedPcks = sig.getHashedSubPackets(); PGPSignatureSubpacketVector unhashedPcks = sig.getUnhashedSubPackets(); if (hashedPcks.size() != 6) { fail("wrong number of hashed packets found."); } if (unhashedPcks.size() != 1) { fail("wrong number of unhashed packets found."); } if (!hashedPcks.getSignerUserID().equals(TEST_USER_ID)) { fail("test userid not matching"); } if (hashedPcks.getSignatureExpirationTime() != TEST_EXPIRATION_TIME) { fail("test signature expiration time not matching"); } if (unhashedPcks.getIssuerKeyID() != secretDSAKey.getKeyID()) { fail("wrong issuer key ID found in certification"); } int[] prefAlgs = hashedPcks.getPreferredCompressionAlgorithms(); preferredAlgorithmCheck("compression", PREFERRED_COMPRESSION_ALGORITHMS, prefAlgs); prefAlgs = hashedPcks.getPreferredHashAlgorithms(); preferredAlgorithmCheck("hash", PREFERRED_HASH_ALGORITHMS, prefAlgs); prefAlgs = hashedPcks.getPreferredSymmetricAlgorithms(); preferredAlgorithmCheck("symmetric", PREFERRED_SYMMETRIC_ALGORITHMS, prefAlgs); int[] criticalHashed = hashedPcks.getCriticalTags(); if (criticalHashed.length != 1) { fail("wrong number of critical packets found."); } if (criticalHashed[0] != SignatureSubpacketTags.SIGNER_USER_ID) { fail("wrong critical packet found in tag list."); } // // no packets passed // sGen = new PGPSignatureGenerator(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1, "BC"); sGen.initSign(PGPSignature.SUBKEY_BINDING, pgpPrivDSAKey); sGen.setHashedSubpackets(null); sGen.setUnhashedSubpackets(null); sig = sGen.generateCertification(TEST_USER_ID, secretKey.getPublicKey()); sig.initVerify(secretDSAKey.getPublicKey(), "BC"); if (!sig.verifyCertification(TEST_USER_ID, secretKey.getPublicKey())) { fail("subkey binding verification failed."); } hashedPcks = sig.getHashedSubPackets(); if (hashedPcks.size() != 1) { fail("found wrong number of hashed packets"); } unhashedPcks = sig.getUnhashedSubPackets(); if (unhashedPcks.size() != 1) { fail("found wrong number of unhashed packets"); } try { sig.verifyCertification(secretKey.getPublicKey()); fail("failed to detect non-key signature."); } catch (IllegalStateException e) { // expected } // // override hash packets // sGen = new PGPSignatureGenerator(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1, "BC"); sGen.initSign(PGPSignature.SUBKEY_BINDING, pgpPrivDSAKey); hashedGen = new PGPSignatureSubpacketGenerator(); hashedGen.setSignatureCreationTime(false, new Date(0L)); sGen.setHashedSubpackets(hashedGen.generate()); sGen.setUnhashedSubpackets(null); sig = sGen.generateCertification(TEST_USER_ID, secretKey.getPublicKey()); sig.initVerify(secretDSAKey.getPublicKey(), "BC"); if (!sig.verifyCertification(TEST_USER_ID, secretKey.getPublicKey())) { fail("subkey binding verification failed."); } hashedPcks = sig.getHashedSubPackets(); if (hashedPcks.size() != 1) { fail("found wrong number of hashed packets in override test"); } if (!hashedPcks.hasSubpacket(SignatureSubpacketTags.CREATION_TIME)) { fail("hasSubpacket test for creation time failed"); } if (!hashedPcks.getSignatureCreationTime().equals(new Date(0L))) { fail("creation of overriden date failed."); } prefAlgs = hashedPcks.getPreferredCompressionAlgorithms(); preferredAlgorithmCheck("compression", NO_PREFERENCES, prefAlgs); prefAlgs = hashedPcks.getPreferredHashAlgorithms(); preferredAlgorithmCheck("hash", NO_PREFERENCES, prefAlgs); prefAlgs = hashedPcks.getPreferredSymmetricAlgorithms(); preferredAlgorithmCheck("symmetric", NO_PREFERENCES, prefAlgs); if (hashedPcks.getKeyExpirationTime() != 0) { fail("unexpected key expiration time found"); } if (hashedPcks.getSignatureExpirationTime() != 0) { fail("unexpected signature expiration time found"); } if (hashedPcks.getSignerUserID() != null) { fail("unexpected signer user ID found"); } criticalHashed = hashedPcks.getCriticalTags(); if (criticalHashed.length != 0) { fail("critical packets found when none expected"); } unhashedPcks = sig.getUnhashedSubPackets(); if (unhashedPcks.size() != 1) { fail("found wrong number of unhashed packets in override test"); } // // general signatures // testSig(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA256, secretKey.getPublicKey(), pgpPrivKey); testSig(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA384, secretKey.getPublicKey(), pgpPrivKey); testSig(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA512, secretKey.getPublicKey(), pgpPrivKey); testSigV3(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1, secretKey.getPublicKey(), pgpPrivKey); testTextSig(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1, secretKey.getPublicKey(), pgpPrivKey, TEST_DATA_WITH_CRLF, TEST_DATA_WITH_CRLF); testTextSig(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1, secretKey.getPublicKey(), pgpPrivKey, TEST_DATA, TEST_DATA_WITH_CRLF); testTextSigV3(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1, secretKey.getPublicKey(), pgpPrivKey, TEST_DATA_WITH_CRLF, TEST_DATA_WITH_CRLF); testTextSigV3(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1, secretKey.getPublicKey(), pgpPrivKey, TEST_DATA, TEST_DATA_WITH_CRLF); // // DSA Tests // pgpPriv = new PGPSecretKeyRing(dsaKeyRing); secretKey = pgpPriv.getSecretKey(); pgpPrivKey = secretKey.extractPrivateKey(dsaPass, "BC"); try { testSig(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1, secretKey.getPublicKey(), pgpPrivKey); fail("DSA wrong key test failed."); } catch (PGPException e) { // expected } try { testSigV3(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1, secretKey.getPublicKey(), pgpPrivKey); fail("DSA V3 wrong key test failed."); } catch (PGPException e) { // expected } testSig(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1, secretKey.getPublicKey(), pgpPrivKey); testSigV3(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1, secretKey.getPublicKey(), pgpPrivKey); testTextSig(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1, secretKey.getPublicKey(), pgpPrivKey, TEST_DATA_WITH_CRLF, TEST_DATA_WITH_CRLF); testTextSig(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1, secretKey.getPublicKey(), pgpPrivKey, TEST_DATA, TEST_DATA_WITH_CRLF); testTextSigV3(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1, secretKey.getPublicKey(), pgpPrivKey, TEST_DATA_WITH_CRLF, TEST_DATA_WITH_CRLF); testTextSigV3(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1, secretKey.getPublicKey(), pgpPrivKey, TEST_DATA, TEST_DATA_WITH_CRLF); // special cases // testMissingSubpackets(nullPacketsSubKeyBinding); testMissingSubpackets(generateV3BinarySig(pgpPrivKey, PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1)); // keyflags testKeyFlagsValues(); } private void testKeyFlagsValues() { checkValue(KeyFlags.CERTIFY_OTHER, 0x01); checkValue(KeyFlags.SIGN_DATA, 0x02); checkValue(KeyFlags.ENCRYPT_COMMS, 0x04); checkValue(KeyFlags.ENCRYPT_STORAGE, 0x08); checkValue(KeyFlags.SPLIT, 0x10); checkValue(KeyFlags.AUTHENTICATION, 0x20); checkValue(KeyFlags.SHARED, 0x80); // yes this actually happens checkValue(new byte[] { 4, 0, 0, 0 }, 0x04); checkValue(new byte[] { 4, 0, 0 }, 0x04); checkValue(new byte[] { 4, 0 }, 0x04); checkValue(new byte[] { 4 }, 0x04); } private void checkValue(int flag, int value) { KeyFlags f = new KeyFlags(true, flag); if (f.getFlags() != value) { fail("flag value mismatch"); } } private void checkValue(byte[] flag, int value) { KeyFlags f = new KeyFlags(true, flag); if (f.getFlags() != value) { fail("flag value mismatch"); } } private void testMissingSubpackets(byte[] signature) throws IOException { PGPObjectFactory f = new PGPObjectFactory(signature); Object obj = f.nextObject(); while (!(obj instanceof PGPSignatureList)) { obj = f.nextObject(); if (obj instanceof PGPLiteralData) { InputStream in = ((PGPLiteralData)obj).getDataStream(); Streams.drain(in); } } PGPSignature sig = ((PGPSignatureList)obj).get(0); if (sig.getVersion() > 3) { PGPSignatureSubpacketVector v = sig.getHashedSubPackets(); if (v.getKeyExpirationTime() != 0) { fail("key expiration time not zero for missing subpackets"); } if (!sig.hasSubpackets()) { fail("hasSubpackets() returns false with packets"); } } else { if (sig.getHashedSubPackets() != null) { fail("hashed sub packets found when none expected"); } if (sig.getUnhashedSubPackets() != null) { fail("unhashed sub packets found when none expected"); } if (sig.hasSubpackets()) { fail("hasSubpackets() returns true with no packets"); } } } private void preferredAlgorithmCheck( String type, int[] expected, int[] prefAlgs) { if (expected == null) { if (prefAlgs != null) { fail("preferences for " + type + " found when none expected"); } } else { if (prefAlgs.length != expected.length) { fail("wrong number of preferred " + type + " algorithms found"); } for (int i = 0; i != expected.length; i++) { if (expected[i] != prefAlgs[i]) { fail("wrong algorithm found for " + type + ": expected " + expected[i] + " got " + prefAlgs); } } } } private void testSig( int encAlgorithm, int hashAlgorithm, PGPPublicKey pubKey, PGPPrivateKey privKey) throws Exception { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); ByteArrayInputStream testIn = new ByteArrayInputStream(TEST_DATA); PGPSignatureGenerator sGen = new PGPSignatureGenerator(encAlgorithm, hashAlgorithm, "BC"); sGen.initSign(PGPSignature.BINARY_DOCUMENT, privKey); sGen.generateOnePassVersion(false).encode(bOut); PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); OutputStream lOut = lGen.open( new UncloseableOutputStream(bOut), PGPLiteralData.BINARY, "_CONSOLE", TEST_DATA.length * 2, new Date()); int ch; while ((ch = testIn.read()) >= 0) { lOut.write(ch); sGen.update((byte)ch); } lOut.write(TEST_DATA); sGen.update(TEST_DATA); lGen.close(); sGen.generate().encode(bOut); verifySignature(bOut.toByteArray(), hashAlgorithm, pubKey, TEST_DATA); } private void testTextSig( int encAlgorithm, int hashAlgorithm, PGPPublicKey pubKey, PGPPrivateKey privKey, byte[] data, byte[] canonicalData) throws Exception { PGPSignatureGenerator sGen = new PGPSignatureGenerator(encAlgorithm, HashAlgorithmTags.SHA1, "BC"); ByteArrayOutputStream bOut = new ByteArrayOutputStream(); ByteArrayInputStream testIn = new ByteArrayInputStream(data); Date creationTime = new Date(); sGen.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT, privKey); sGen.generateOnePassVersion(false).encode(bOut); PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); OutputStream lOut = lGen.open( new UncloseableOutputStream(bOut), PGPLiteralData.TEXT, "_CONSOLE", data.length * 2, creationTime); int ch; while ((ch = testIn.read()) >= 0) { lOut.write(ch); sGen.update((byte)ch); } lOut.write(data); sGen.update(data); lGen.close(); PGPSignature sig = sGen.generate(); if (sig.getCreationTime().getTime() == 0) { fail("creation time not set in v4 signature"); } sig.encode(bOut); verifySignature(bOut.toByteArray(), hashAlgorithm, pubKey, canonicalData); } private void testSigV3( int encAlgorithm, int hashAlgorithm, PGPPublicKey pubKey, PGPPrivateKey privKey) throws Exception { byte[] bytes = generateV3BinarySig(privKey, encAlgorithm, hashAlgorithm); verifySignature(bytes, hashAlgorithm, pubKey, TEST_DATA); } private byte[] generateV3BinarySig(PGPPrivateKey privKey, int encAlgorithm, int hashAlgorithm) throws Exception { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); ByteArrayInputStream testIn = new ByteArrayInputStream(TEST_DATA); PGPV3SignatureGenerator sGen = new PGPV3SignatureGenerator(encAlgorithm, hashAlgorithm, "BC"); sGen.initSign(PGPSignature.BINARY_DOCUMENT, privKey); sGen.generateOnePassVersion(false).encode(bOut); PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); OutputStream lOut = lGen.open( new UncloseableOutputStream(bOut), PGPLiteralData.BINARY, "_CONSOLE", TEST_DATA.length * 2, new Date()); int ch; while ((ch = testIn.read()) >= 0) { lOut.write(ch); sGen.update((byte)ch); } lOut.write(TEST_DATA); sGen.update(TEST_DATA); lGen.close(); sGen.generate().encode(bOut); return bOut.toByteArray(); } private void testTextSigV3( int encAlgorithm, int hashAlgorithm, PGPPublicKey pubKey, PGPPrivateKey privKey, byte[] data, byte[] canonicalData) throws Exception { PGPV3SignatureGenerator sGen = new PGPV3SignatureGenerator(encAlgorithm, HashAlgorithmTags.SHA1, "BC"); ByteArrayOutputStream bOut = new ByteArrayOutputStream(); ByteArrayInputStream testIn = new ByteArrayInputStream(data); sGen.initSign(PGPSignature.CANONICAL_TEXT_DOCUMENT, privKey); sGen.generateOnePassVersion(false).encode(bOut); PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); OutputStream lOut = lGen.open( new UncloseableOutputStream(bOut), PGPLiteralData.TEXT, "_CONSOLE", data.length * 2, new Date()); int ch; while ((ch = testIn.read()) >= 0) { lOut.write(ch); sGen.update((byte)ch); } lOut.write(data); sGen.update(data); lGen.close(); PGPSignature sig = sGen.generate(); if (sig.getCreationTime().getTime() == 0) { fail("creation time not set in v3 signature"); } sig.encode(bOut); verifySignature(bOut.toByteArray(), hashAlgorithm, pubKey, canonicalData); } private void verifySignature( byte[] encodedSig, int hashAlgorithm, PGPPublicKey pubKey, byte[] original) throws IOException, PGPException, NoSuchProviderException, SignatureException { PGPObjectFactory pgpFact = new PGPObjectFactory(encodedSig); PGPOnePassSignatureList p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); PGPOnePassSignature ops = p1.get(0); PGPLiteralData p2 = (PGPLiteralData)pgpFact.nextObject(); InputStream dIn = p2.getInputStream(); ops.initVerify(pubKey, "BC"); int ch; while ((ch = dIn.read()) >= 0) { ops.update((byte)ch); } PGPSignatureList p3 = (PGPSignatureList)pgpFact.nextObject(); PGPSignature sig = p3.get(0); Date creationTime = sig.getCreationTime(); Date now = new Date(); // Check creationTime is recent if (creationTime.after(now) || creationTime.before(new Date(now.getTime() - 10 * 60 * 1000))) { fail("bad creation time in signature: " + creationTime); } if (sig.getKeyID() != pubKey.getKeyID()) { fail("key id mismatch in signature"); } if (!ops.verify(sig)) { fail("Failed generated signature check - " + hashAlgorithm); } sig.initVerify(pubKey, "BC"); for (int i = 0; i != original.length; i++) { sig.update(original[i]); } sig.update(original); if (!sig.verify()) { fail("Failed generated signature check against original data"); } } public String getName() { return "PGPSignatureTest"; } public static void main( String[] args) { Security.addProvider(new BouncyCastleProvider()); runTest(new PGPSignatureTest()); } }