diff options
Diffstat (limited to 'pg/src/test/java/org/spongycastle')
26 files changed, 15771 insertions, 0 deletions
diff --git a/pg/src/test/java/org/spongycastle/openpgp/examples/test/AllTests.java b/pg/src/test/java/org/spongycastle/openpgp/examples/test/AllTests.java new file mode 100644 index 00000000..f015de6f --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/examples/test/AllTests.java @@ -0,0 +1,415 @@ +package org.spongycastle.openpgp.examples.test; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.spongycastle.openpgp.examples.ClearSignedFileProcessor; +import org.spongycastle.openpgp.examples.DSAElGamalKeyRingGenerator; +import org.spongycastle.openpgp.examples.KeyBasedFileProcessor; +import org.spongycastle.openpgp.examples.KeyBasedLargeFileProcessor; +import org.spongycastle.openpgp.examples.PBEFileProcessor; +import org.spongycastle.openpgp.examples.RSAKeyPairGenerator; +import org.spongycastle.openpgp.examples.SignedFileProcessor; +import org.spongycastle.util.encoders.Base64; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; + +public class AllTests + extends TestCase +{ + byte[] clearSignedPublicKey = Base64.decode( + "mQELBEQh2+wBCAD26kte0hO6flr7Y2aetpPYutHY4qsmDPy+GwmmqVeCDkX+" + + "r1g7DuFbMhVeu0NkKDnVl7GsJ9VarYsFYyqu0NzLa9XS2qlTIkmJV+2/xKa1" + + "tzjn18fT/cnAWL88ZLCOWUr241aPVhLuIc6vpHnySpEMkCh4rvMaimnTrKwO" + + "42kgeDGd5cXfs4J4ovRcTbc4hmU2BRVsRjiYMZWWx0kkyL2zDVyaJSs4yVX7" + + "Jm4/LSR1uC/wDT0IJJuZT/gQPCMJNMEsVCziRgYkAxQK3OWojPSuv4rXpyd4" + + "Gvo6IbvyTgIskfpSkCnQtORNLIudQSuK7pW+LkL62N+ohuKdMvdxauOnAAYp" + + "tBNnZ2dnZ2dnZyA8Z2dnQGdnZ2c+iQE2BBMBAgAgBQJEIdvsAhsDBgsJCAcD" + + "AgQVAggDBBYCAwECHgECF4AACgkQ4M/Ier3f9xagdAf/fbKWBjLQM8xR7JkR" + + "P4ri8YKOQPhK+VrddGUD59/wzVnvaGyl9MZE7TXFUeniQq5iXKnm22EQbYch" + + "v2Jcxyt2H9yptpzyh4tP6tEHl1C887p2J4qe7F2ATua9CzVGwXQSUbKtj2fg" + + "UZP5SsNp25guhPiZdtkf2sHMeiotmykFErzqGMrvOAUThrO63GiYsRk4hF6r" + + "cQ01d+EUVpY/sBcCxgNyOiB7a84sDtrxnX5BTEZDTEj8LvuEyEV3TMUuAjx1" + + "7Eyd+9JtKzwV4v3hlTaWOvGro9nPS7YaPuG+RtufzXCUJPbPfTjTvtGOqvEz" + + "oztls8tuWA0OGHba9XfX9rfgorACAAM="); + + String crOnlyMessage = + "\r" + + " hello world!\r" + + "\r" + + "- dash\r"; + + String nlOnlyMessage = + "\n" + + " hello world!\n" + + "\n" + + "- dash\n"; + + String crNlMessage = + "\r\n" + + " hello world!\r\n" + + "\r\n" + + "- dash\r\n"; + + String crNlMessageTrailingWhiteSpace = + "\r\n" + + " hello world! \t\r\n" + + "\r\n" + + "\r\n"; + + String crOnlySignedMessage = + "-----BEGIN PGP SIGNED MESSAGE-----\r" + + "Hash: SHA256\r" + + "\r" + + "\r" + + " hello world!\r" + + "\r" + + "- - dash\r" + + "-----BEGIN PGP SIGNATURE-----\r" + + "Version: GnuPG v1.4.2.1 (GNU/Linux)\r" + + "\r" + + "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\r" + + "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\r" + + "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\r" + + "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\r" + + "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\r" + + "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\r" + + "=84Nd\r" + + "-----END PGP SIGNATURE-----\r"; + + + String nlOnlySignedMessage = + "-----BEGIN PGP SIGNED MESSAGE-----\n" + + "Hash: SHA256\n" + + "\n" + + "\n" + + " hello world!\n" + + "\n" + + "- - dash\n" + + "-----BEGIN PGP SIGNATURE-----\n" + + "Version: GnuPG v1.4.2.1 (GNU/Linux)\n" + + "\n" + + "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\n" + + "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\n" + + "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\n" + + "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\n" + + "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\n" + + "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\n" + + "=84Nd\n" + + "-----END PGP SIGNATURE-----\n"; + + String crNlSignedMessage = + "-----BEGIN PGP SIGNED MESSAGE-----\r\n" + + "Hash: SHA256\r\n" + + "\r\n" + + "\r\n" + + " hello world!\r\n" + + "\r\n" + + "- - dash\r\n" + + "-----BEGIN PGP SIGNATURE-----\r\n" + + "Version: GnuPG v1.4.2.1 (GNU/Linux)\r\n" + + "\r\n" + + "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\r\n" + + "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\r\n" + + "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\r\n" + + "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\r\n" + + "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\r\n" + + "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\r\n" + + "=84Nd\r" + + "-----END PGP SIGNATURE-----\r\n"; + + String crNlSignedMessageTrailingWhiteSpace = + "-----BEGIN PGP SIGNED MESSAGE-----\r\n" + + "Hash: SHA256\r\n" + + "\r\n" + + "\r\n" + + " hello world! \t\r\n" + + "\r\n" + + "- - dash\r\n" + + "-----BEGIN PGP SIGNATURE-----\r\n" + + "Version: GnuPG v1.4.2.1 (GNU/Linux)\r\n" + + "\r\n" + + "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\r\n" + + "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\r\n" + + "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\r\n" + + "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\r\n" + + "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\r\n" + + "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\r\n" + + "=84Nd\r" + + "-----END PGP SIGNATURE-----\r\n"; + + private PrintStream _oldOut; + private PrintStream _oldErr; + + private ByteArrayOutputStream _currentOut; + private ByteArrayOutputStream _currentErr; + + public void setUp() + throws Exception + { + _oldOut = System.out; + _oldErr = System.err; + _currentOut = new ByteArrayOutputStream(); + _currentErr = new ByteArrayOutputStream(); + + System.setOut(new PrintStream(_currentOut)); + System.setErr(new PrintStream(_currentErr)); + } + + public void tearDown() + { + System.setOut(_oldOut); + System.setErr(_oldErr); + } + + public void testRSAKeyGeneration() + throws Exception + { + RSAKeyPairGenerator.main(new String[] { "test", "password" }); + + createSmallTestInput(); + createLargeTestInput(); + + checkSigning("bpg"); + checkKeyBasedEncryption("bpg"); + checkLargeKeyBasedEncryption("bpg"); + + RSAKeyPairGenerator.main(new String[] { "-a", "test", "password" }); + + checkSigning("asc"); + checkKeyBasedEncryption("asc"); + checkLargeKeyBasedEncryption("asc"); + } + + public void testDSAElGamaleKeyGeneration() + throws Exception + { + DSAElGamalKeyRingGenerator.main(new String[] { "test", "password" }); + + createSmallTestInput(); + createLargeTestInput(); + + checkSigning("bpg"); + checkKeyBasedEncryption("bpg"); + checkLargeKeyBasedEncryption("bpg"); + + DSAElGamalKeyRingGenerator.main(new String[] { "-a", "test", "password" }); + + checkSigning("asc"); + checkKeyBasedEncryption("asc"); + checkLargeKeyBasedEncryption("asc"); + } + + public void testPBEEncryption() + throws Exception + { + _currentErr.reset(); + + PBEFileProcessor.main(new String[] { "-e", "test.txt", "password" }); + + PBEFileProcessor.main(new String[] { "-d", "test.txt.bpg", "password" }); + + assertEquals("no message integrity check", getLine(_currentErr)); + + PBEFileProcessor.main(new String[] { "-e", "-i", "test.txt", "password" }); + + PBEFileProcessor.main(new String[] { "-d", "test.txt.bpg", "password" }); + + assertEquals("message integrity check passed", getLine(_currentErr)); + + PBEFileProcessor.main(new String[] { "-e", "-ai", "test.txt", "password" }); + + PBEFileProcessor.main(new String[] { "-d", "test.txt.asc", "password" }); + + assertEquals("message integrity check passed", getLine(_currentErr)); + } + + public void testClearSigned() + throws Exception + { + createTestFile(clearSignedPublicKey, "pub.bpg"); + + checkClearSignedVerify(nlOnlySignedMessage); + checkClearSignedVerify(crOnlySignedMessage); + checkClearSignedVerify(crNlSignedMessage); + checkClearSignedVerify(crNlSignedMessageTrailingWhiteSpace); + + ClearSignedFileProcessor.main(new String[] { "-v", "test.txt.asc", "pub.bpg" }); + + RSAKeyPairGenerator.main(new String[] { "test", "password" }); + + checkClearSigned(crOnlyMessage); + checkClearSigned(nlOnlyMessage); + checkClearSigned(crNlMessage); + checkClearSigned(crNlMessageTrailingWhiteSpace); + } + + public void testClearSignedBogusInput() + throws Exception + { + createTestFile(clearSignedPublicKey, "test.txt"); + + ClearSignedFileProcessor.main(new String[] { "-s", "test.txt", "secret.bpg", "password" }); + } + + private void checkClearSignedVerify(String message) + throws Exception + { + createTestData(message, "test.txt.asc"); + + ClearSignedFileProcessor.main(new String[] { "-v", "test.txt.asc", "pub.bpg" }); + } + + private void checkClearSigned(String message) + throws Exception + { + createTestData(message, "test.txt"); + + ClearSignedFileProcessor.main(new String[] { "-s", "test.txt", "secret.bpg", "password" }); + ClearSignedFileProcessor.main(new String[] { "-v", "test.txt.asc", "pub.bpg" }); + } + + private void checkSigning(String type) + throws Exception + { + _currentOut.reset(); + + SignedFileProcessor.main(new String[] { "-s", "test.txt", "secret." + type, "password" }); + + SignedFileProcessor.main(new String[] { "-v", "test.txt.bpg", "pub." + type }); + + assertEquals("signature verified.", getLine(_currentOut)); + + SignedFileProcessor.main(new String[] { "-s", "-a", "test.txt", "secret." + type, "password" }); + + SignedFileProcessor.main(new String[] { "-v", "test.txt.asc", "pub." + type }); + + assertEquals("signature verified.", getLine(_currentOut)); + } + + private void checkKeyBasedEncryption(String type) + throws Exception + { + _currentErr.reset(); + + KeyBasedFileProcessor.main(new String[] { "-e", "test.txt", "pub." + type }); + + KeyBasedFileProcessor.main(new String[] { "-d", "test.txt.bpg", "secret." + type, "password" }); + + assertEquals("no message integrity check", getLine(_currentErr)); + + KeyBasedFileProcessor.main(new String[] { "-e", "-i", "test.txt", "pub." + type }); + + KeyBasedFileProcessor.main(new String[] { "-d", "test.txt.bpg", "secret." + type, "password" }); + + assertEquals("message integrity check passed", getLine(_currentErr)); + + KeyBasedFileProcessor.main(new String[] { "-e", "-ai", "test.txt", "pub." + type }); + + KeyBasedFileProcessor.main(new String[] { "-d", "test.txt.asc", "secret." + type, "password" }); + + assertEquals("message integrity check passed", getLine(_currentErr)); + } + + private void checkLargeKeyBasedEncryption(String type) + throws Exception + { + _currentErr.reset(); + + KeyBasedLargeFileProcessor.main(new String[] { "-e", "large.txt", "pub." + type }); + + KeyBasedLargeFileProcessor.main(new String[] { "-d", "large.txt.bpg", "secret." + type, "password" }); + + assertEquals("no message integrity check", getLine(_currentErr)); + + KeyBasedLargeFileProcessor.main(new String[] { "-e", "-i", "large.txt", "pub." + type }); + + KeyBasedLargeFileProcessor.main(new String[] { "-d", "large.txt.bpg", "secret." + type, "password" }); + + assertEquals("message integrity check passed", getLine(_currentErr)); + + KeyBasedLargeFileProcessor.main(new String[] { "-e", "-ai", "large.txt", "pub." + type }); + + KeyBasedLargeFileProcessor.main(new String[] { "-d", "large.txt.asc", "secret." + type, "password" }); + + assertEquals("message integrity check passed", getLine(_currentErr)); + } + + private void createSmallTestInput() + throws IOException + { + BufferedWriter bfOut = new BufferedWriter(new FileWriter("test.txt")); + + bfOut.write("hello world!"); + bfOut.newLine(); + + bfOut.close(); + } + + private void createLargeTestInput() + throws IOException + { + BufferedWriter bfOut = new BufferedWriter(new FileWriter("large.txt")); + + for (int i = 0; i != 2000; i++) + { + bfOut.write("hello world!"); + bfOut.newLine(); + } + + bfOut.close(); + } + + private void createTestData(String testData, String name) + throws IOException + { + BufferedWriter bfOut = new BufferedWriter(new FileWriter(name)); + + bfOut.write(testData); + + bfOut.close(); + } + + private void createTestFile(byte[] keyData, String name) + throws IOException + { + FileOutputStream fOut = new FileOutputStream(name); + + fOut.write(keyData); + + fOut.close(); + } + + private String getLine( + ByteArrayOutputStream out) + throws IOException + { + BufferedReader bRd = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(out.toByteArray()))); + + out.reset(); + + return bRd.readLine(); + } + + public static void main (String[] args) + { + junit.textui.TestRunner.run(suite()); + } + + public static Test suite() + { + TestSuite suite = new TestSuite("OpenPGP Example Tests"); + + suite.addTestSuite(AllTests.class); + + return suite; + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/AllTests.java b/pg/src/test/java/org/spongycastle/openpgp/test/AllTests.java new file mode 100644 index 00000000..81bfa301 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/AllTests.java @@ -0,0 +1,46 @@ +package org.spongycastle.openpgp.test; + +import java.security.Security; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.util.test.SimpleTestResult; + +public class AllTests + extends TestCase +{ + public void testPGP() + { + Security.addProvider(new BouncyCastleProvider()); + + org.spongycastle.util.test.Test[] tests = RegressionTest.tests; + + for (int i = 0; i != tests.length; i++) + { + SimpleTestResult result = (SimpleTestResult)tests[i].perform(); + + if (!result.isSuccessful()) + { + fail(result.toString()); + } + } + } + + public static void main (String[] args) + { + junit.textui.TestRunner.run(suite()); + } + + public static Test suite() + { + TestSuite suite = new TestSuite("OpenPGP Tests"); + + suite.addTestSuite(AllTests.class); + suite.addTestSuite(DSA2Test.class); + suite.addTestSuite(PGPUnicodeTest.class); + + return suite; + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/BcPGPDSAElGamalTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/BcPGPDSAElGamalTest.java new file mode 100644 index 00000000..b8311b46 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/BcPGPDSAElGamalTest.java @@ -0,0 +1,565 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.AlgorithmParameterGenerator; +import java.security.AlgorithmParameters; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Date; +import java.util.Iterator; + +import javax.crypto.spec.DHParameterSpec; + +import org.spongycastle.bcpg.BCPGOutputStream; +import org.spongycastle.bcpg.PublicKeyAlgorithmTags; +import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.spongycastle.crypto.AsymmetricBlockCipher; +import org.spongycastle.crypto.encodings.PKCS1Encoding; +import org.spongycastle.crypto.engines.ElGamalEngine; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.jce.spec.ElGamalParameterSpec; +import org.spongycastle.openpgp.PGPCompressedData; +import org.spongycastle.openpgp.PGPCompressedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedDataList; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPKeyPair; +import org.spongycastle.openpgp.PGPLiteralData; +import org.spongycastle.openpgp.PGPLiteralDataGenerator; +import org.spongycastle.openpgp.PGPOnePassSignature; +import org.spongycastle.openpgp.PGPOnePassSignatureList; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPUtil; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder; +import org.spongycastle.openpgp.operator.bc.BcPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder; +import org.spongycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; +import org.spongycastle.openpgp.operator.bc.BcPGPKeyConverter; +import org.spongycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory; +import org.spongycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.test.SimpleTest; +import org.spongycastle.util.test.UncloseableOutputStream; + +public class BcPGPDSAElGamalTest + extends SimpleTest +{ + + byte[] testPubKeyRing = + Base64.decode( + "mQGiBEAR8jYRBADNifuSopd20JOQ5x30ljIaY0M6927+vo09NeNxS3KqItba" + + "nz9o5e2aqdT0W1xgdHYZmdElOHTTsugZxdXTEhghyxoo3KhVcNnTABQyrrvX" + + "qouvmP2fEDEw0Vpyk+90BpyY9YlgeX/dEA8OfooRLCJde/iDTl7r9FT+mts8" + + "g3azjwCgx+pOLD9LPBF5E4FhUOdXISJ0f4EEAKXSOi9nZzajpdhe8W2ZL9gc" + + "BpzZi6AcrRZBHOEMqd69gtUxA4eD8xycUQ42yH89imEcwLz8XdJ98uHUxGJi" + + "qp6hq4oakmw8GQfiL7yQIFgaM0dOAI9Afe3m84cEYZsoAFYpB4/s9pVMpPRH" + + "NsVspU0qd3NHnSZ0QXs8L8DXGO1uBACjDUj+8GsfDCIP2QF3JC+nPUNa0Y5t" + + "wKPKl+T8hX/0FBD7fnNeC6c9j5Ir/Fp/QtdaDAOoBKiyNLh1JaB1NY6US5zc" + + "qFks2seZPjXEiE6OIDXYra494mjNKGUobA4hqT2peKWXt/uBcuL1mjKOy8Qf" + + "JxgEd0MOcGJO+1PFFZWGzLQ3RXJpYyBILiBFY2hpZG5hICh0ZXN0IGtleSBv" + + "bmx5KSA8ZXJpY0Bib3VuY3ljYXN0bGUub3JnPohZBBMRAgAZBQJAEfI2BAsH" + + "AwIDFQIDAxYCAQIeAQIXgAAKCRAOtk6iUOgnkDdnAKC/CfLWikSBdbngY6OK" + + "5UN3+o7q1ACcDRqjT3yjBU3WmRUNlxBg3tSuljmwAgAAuQENBEAR8jgQBAC2" + + "kr57iuOaV7Ga1xcU14MNbKcA0PVembRCjcVjei/3yVfT/fuCVtGHOmYLEBqH" + + "bn5aaJ0P/6vMbLCHKuN61NZlts+LEctfwoya43RtcubqMc7eKw4k0JnnoYgB" + + "ocLXOtloCb7jfubOsnfORvrUkK0+Ne6anRhFBYfaBmGU75cQgwADBQP/XxR2" + + "qGHiwn+0YiMioRDRiIAxp6UiC/JQIri2AKSqAi0zeAMdrRsBN7kyzYVVpWwN" + + "5u13gPdQ2HnJ7d4wLWAuizUdKIQxBG8VoCxkbipnwh2RR4xCXFDhJrJFQUm+" + + "4nKx9JvAmZTBIlI5Wsi5qxst/9p5MgP3flXsNi1tRbTmRhqIRgQYEQIABgUC" + + "QBHyOAAKCRAOtk6iUOgnkBStAJoCZBVM61B1LG2xip294MZecMtCwQCbBbsk" + + "JVCXP0/Szm05GB+WN+MOCT2wAgAA"); + + byte[] testPrivKeyRing = + Base64.decode( + "lQHhBEAR8jYRBADNifuSopd20JOQ5x30ljIaY0M6927+vo09NeNxS3KqItba" + + "nz9o5e2aqdT0W1xgdHYZmdElOHTTsugZxdXTEhghyxoo3KhVcNnTABQyrrvX" + + "qouvmP2fEDEw0Vpyk+90BpyY9YlgeX/dEA8OfooRLCJde/iDTl7r9FT+mts8" + + "g3azjwCgx+pOLD9LPBF5E4FhUOdXISJ0f4EEAKXSOi9nZzajpdhe8W2ZL9gc" + + "BpzZi6AcrRZBHOEMqd69gtUxA4eD8xycUQ42yH89imEcwLz8XdJ98uHUxGJi" + + "qp6hq4oakmw8GQfiL7yQIFgaM0dOAI9Afe3m84cEYZsoAFYpB4/s9pVMpPRH" + + "NsVspU0qd3NHnSZ0QXs8L8DXGO1uBACjDUj+8GsfDCIP2QF3JC+nPUNa0Y5t" + + "wKPKl+T8hX/0FBD7fnNeC6c9j5Ir/Fp/QtdaDAOoBKiyNLh1JaB1NY6US5zc" + + "qFks2seZPjXEiE6OIDXYra494mjNKGUobA4hqT2peKWXt/uBcuL1mjKOy8Qf" + + "JxgEd0MOcGJO+1PFFZWGzP4DAwLeUcsVxIC2s2Bb9ab2XD860TQ2BI2rMD/r" + + "7/psx9WQ+Vz/aFAT3rXkEJ97nFeqEACgKmUCAEk9939EwLQ3RXJpYyBILiBF" + + "Y2hpZG5hICh0ZXN0IGtleSBvbmx5KSA8ZXJpY0Bib3VuY3ljYXN0bGUub3Jn" + + "PohZBBMRAgAZBQJAEfI2BAsHAwIDFQIDAxYCAQIeAQIXgAAKCRAOtk6iUOgn" + + "kDdnAJ9Ala3OcwEV1DbK906CheYWo4zIQwCfUqUOLMp/zj6QAk02bbJAhV1r" + + "sAewAgAAnQFYBEAR8jgQBAC2kr57iuOaV7Ga1xcU14MNbKcA0PVembRCjcVj" + + "ei/3yVfT/fuCVtGHOmYLEBqHbn5aaJ0P/6vMbLCHKuN61NZlts+LEctfwoya" + + "43RtcubqMc7eKw4k0JnnoYgBocLXOtloCb7jfubOsnfORvrUkK0+Ne6anRhF" + + "BYfaBmGU75cQgwADBQP/XxR2qGHiwn+0YiMioRDRiIAxp6UiC/JQIri2AKSq" + + "Ai0zeAMdrRsBN7kyzYVVpWwN5u13gPdQ2HnJ7d4wLWAuizUdKIQxBG8VoCxk" + + "bipnwh2RR4xCXFDhJrJFQUm+4nKx9JvAmZTBIlI5Wsi5qxst/9p5MgP3flXs" + + "Ni1tRbTmRhr+AwMC3lHLFcSAtrNg/EiWFLAnKNXH27zjwuhje8u2r+9iMTYs" + + "GjbRxaxRY0GKRhttCwqe2BC0lHhzifdlEcc9yjIjuKfepG2fnnSIRgQYEQIA" + + "BgUCQBHyOAAKCRAOtk6iUOgnkBStAJ9HFejVtVJ/A9LM/mDPe0ExhEXt/QCg" + + "m/KM7hJ/JrfnLQl7IaZsdg1F6vCwAgAA"); + + byte[] encMessage = + Base64.decode( + "hQEOAynbo4lhNjcHEAP/dgCkMtPB6mIgjFvNiotjaoh4sAXf4vFNkSeehQ2c" + + "r+IMt9CgIYodJI3FoJXxOuTcwesqTp5hRzgUBJS0adLDJwcNubFMy0M2tp5o" + + "KTWpXulIiqyO6f5jI/oEDHPzFoYgBmR4x72l/YpMy8UoYGtNxNvR7LVOfqJv" + + "uDY/71KMtPQEAIadOWpf1P5Td+61Zqn2VH2UV7H8eI6hGa6Lsy4sb9iZNE7f" + + "c+spGJlgkiOt8TrQoq3iOK9UN9nHZLiCSIEGCzsEn3uNuorD++Qs065ij+Oy" + + "36TKeuJ+38CfT7u47dEshHCPqWhBKEYrxZWHUJU/izw2Q1Yxd2XRxN+nafTL" + + "X1fQ0lABQUASa18s0BkkEERIdcKQXVLEswWcGqWNv1ZghC7xO2VDBX4HrPjp" + + "drjL63p2UHzJ7/4gPWGGtnqq1Xita/1mrImn7pzLThDWiT55vjw6Hw=="); + + byte[] signedAndEncMessage = + Base64.decode( + "hQEOAynbo4lhNjcHEAP+K20MVhzdX57hf/cU8TH0prP0VePr9mmeBedzqqMn" + + "fp2p8Zb68zmcMlI/WiL5XMNLYRmCgEcXyWbKdP/XV9m9LDBe1CMAGrkCeGBy" + + "je69IQQ5LS9vDPyEMF4iAAv/EqACjqHkizdY/a/FRx/t2ioXYdEC2jA6kS9C" + + "McpsNz16DE8EAIk3uKn4bGo/+15TXkyFYzW5Cf71SfRoHNmU2zAI93zhjN+T" + + "B7mGJwWXzsMkIO6FkMU5TCSrwZS3DBWCIaJ6SYoaawE/C/2j9D7bX1Jv8kum" + + "4cq+eZM7z6JYs6xend+WAwittpUxbEiyC2AJb3fBSXPAbLqWd6J6xbZZ7GDK" + + "r2Ca0pwBxwGhbMDyi2zpHLzw95H7Ah2wMcGU6kMLB+hzBSZ6mSTGFehqFQE3" + + "2BnAj7MtnbghiefogacJ891jj8Y2ggJeKDuRz8j2iICaTOy+Y2rXnnJwfYzm" + + "BMWcd2h1C5+UeBJ9CrrLniCCI8s5u8z36Rno3sfhBnXdRmWSxExXtocbg1Ht" + + "dyiThf6TK3W29Yy/T6x45Ws5zOasaJdsFKM="); + char[] pass = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' }; + + public void performTest() + throws Exception + { + try + { + PGPPublicKey pubKey; + + PGPUtil.setDefaultProvider("SC"); + + // + // Read the public key + // + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(testPubKeyRing); + + PGPPublicKeyRing pgpPub = (PGPPublicKeyRing)pgpFact.nextObject(); + + pubKey = pgpPub.getPublicKey(); + + if (pubKey.getBitStrength() != 1024) + { + fail("failed - key strength reported incorrectly."); + } + + // + // Read the private key + // + PGPSecretKeyRing sKey = new PGPSecretKeyRing(testPrivKeyRing, new BcKeyFingerprintCalculator()); + PGPPrivateKey pgpPrivKey = sKey.getSecretKey().extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass)); + + // + // signature generation + // + String data = "hello world!"; + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ByteArrayInputStream testIn = new ByteArrayInputStream(data.getBytes()); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(PGPPublicKey.DSA, PGPUtil.SHA1)); + + sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey); + + PGPCompressedDataGenerator cGen = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + BCPGOutputStream bcOut = new BCPGOutputStream( + cGen.open(new UncloseableOutputStream(bOut))); + + sGen.generateOnePassVersion(false).encode(bcOut); + + PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); + + Date testDate = new Date((System.currentTimeMillis() / 1000) * 1000); + OutputStream lOut = lGen.open( + new UncloseableOutputStream(bcOut), + PGPLiteralData.BINARY, + "_CONSOLE", + data.getBytes().length, + testDate); + + int ch; + while ((ch = testIn.read()) >= 0) + { + lOut.write(ch); + sGen.update((byte)ch); + } + + lGen.close(); + + sGen.generate().encode(bcOut); + + cGen.close(); + + // + // verify generated signature + // + pgpFact = new JcaPGPObjectFactory(bOut.toByteArray()); + + PGPCompressedData c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + PGPOnePassSignatureList p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + + PGPOnePassSignature ops = p1.get(0); + + PGPLiteralData p2 = (PGPLiteralData)pgpFact.nextObject(); + if (!p2.getModificationTime().equals(testDate)) + { + fail("Modification time not preserved"); + } + + InputStream dIn = p2.getInputStream(); + + ops.init(new BcPGPContentVerifierBuilderProvider(), pubKey); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + PGPSignatureList p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed generated signature check"); + } + + // + // test encryption + // + + // + // find a key suitable for encryption + // + long pgpKeyID = 0; + AsymmetricKeyParameter pKey = null; + BcPGPKeyConverter keyConverter = new BcPGPKeyConverter(); + + Iterator it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + PGPPublicKey pgpKey = (PGPPublicKey)it.next(); + + if (pgpKey.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT + || pgpKey.getAlgorithm() == PGPPublicKey.ELGAMAL_GENERAL) + { + pKey = keyConverter.getPublicKey(pgpKey); + pgpKeyID = pgpKey.getKeyID(); + if (pgpKey.getBitStrength() != 1024) + { + fail("failed - key strength reported incorrectly."); + } + + // + // verify the key + // + + } + } + + AsymmetricBlockCipher c = new PKCS1Encoding(new ElGamalEngine()); + + c.init(true, pKey); + + byte[] in = "hello world".getBytes(); + + byte[] out = c.processBlock(in, 0, in.length); + + pgpPrivKey = sKey.getSecretKey(pgpKeyID).extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass)); + + c.init(false, keyConverter.getPrivateKey(pgpPrivKey)); + + out = c.processBlock(out, 0, out.length); + + if (!areEqual(in, out)) + { + fail("decryption failed."); + } + + // + // encrypted message + // + byte[] text = { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)' ', (byte)'w', (byte)'o', (byte)'r', (byte)'l', (byte)'d', (byte)'!', (byte)'\n' }; + + JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(encMessage); + + PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpF.nextObject(); + + PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0); + + InputStream clear = encP.getDataStream(new BcPublicKeyDataDecryptorFactory(pgpPrivKey)); + + pgpFact = new JcaPGPObjectFactory(clear); + + c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + PGPLiteralData ld = (PGPLiteralData)pgpFact.nextObject(); + + bOut = new ByteArrayOutputStream(); + + if (!ld.getFileName().equals("test.txt")) + { + throw new RuntimeException("wrong filename in packet"); + } + + InputStream inLd = ld.getDataStream(); + + while ((ch = inLd.read()) >= 0) + { + bOut.write(ch); + } + + if (!areEqual(bOut.toByteArray(), text)) + { + fail("wrong plain text in decrypted packet"); + } + + // + // signed and encrypted message + // + pgpF = new JcaPGPObjectFactory(signedAndEncMessage); + + encList = (PGPEncryptedDataList)pgpF.nextObject(); + + encP = (PGPPublicKeyEncryptedData)encList.get(0); + + clear = encP.getDataStream(new BcPublicKeyDataDecryptorFactory(pgpPrivKey)); + + pgpFact = new JcaPGPObjectFactory(clear); + + c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + + ops = p1.get(0); + + ld = (PGPLiteralData)pgpFact.nextObject(); + + bOut = new ByteArrayOutputStream(); + + if (!ld.getFileName().equals("test.txt")) + { + throw new RuntimeException("wrong filename in packet"); + } + + inLd = ld.getDataStream(); + + // + // note: we use the DSA public key here. + // + ops.init(new BcPGPContentVerifierBuilderProvider(), pgpPub.getPublicKey()); + + while ((ch = inLd.read()) >= 0) + { + ops.update((byte)ch); + bOut.write(ch); + } + + p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed signature check"); + } + + if (!areEqual(bOut.toByteArray(), text)) + { + fail("wrong plain text in decrypted packet"); + } + + // + // encrypt + // + ByteArrayOutputStream cbOut = new ByteArrayOutputStream(); + PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.TRIPLE_DES).setSecureRandom(new SecureRandom())); + PGPPublicKey puK = sKey.getSecretKey(pgpKeyID).getPublicKey(); + + cPk.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(puK)); + + OutputStream cOut = cPk.open(new UncloseableOutputStream(cbOut), bOut.toByteArray().length); + + cOut.write(text); + + cOut.close(); + + pgpF = new JcaPGPObjectFactory(cbOut.toByteArray()); + + encList = (PGPEncryptedDataList)pgpF.nextObject(); + + encP = (PGPPublicKeyEncryptedData)encList.get(0); + + pgpPrivKey = sKey.getSecretKey(pgpKeyID).extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass)); + + clear = encP.getDataStream(new BcPublicKeyDataDecryptorFactory(pgpPrivKey)); + + bOut.reset(); + + while ((ch = clear.read()) >= 0) + { + bOut.write(ch); + } + + out = bOut.toByteArray(); + + if (!areEqual(out, text)) + { + fail("wrong plain text in generated packet"); + } + + // + // use of PGPKeyPair + // + BigInteger g = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + BigInteger p = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + KeyPairGenerator kpg = KeyPairGenerator.getInstance("ElGamal", "SC"); + + ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g); + + kpg.initialize(elParams); + + KeyPair kp = kpg.generateKeyPair(); + + PGPKeyPair pgpKp = new JcaPGPKeyPair(PGPPublicKey.ELGAMAL_GENERAL , kp, new Date()); + + PGPPublicKey k1 = pgpKp.getPublicKey(); + + PGPPrivateKey k2 = pgpKp.getPrivateKey(); + + + + // Test bug with ElGamal P size != 0 mod 8 (don't use these sizes at home!) + SecureRandom random = new SecureRandom(); + for (int pSize = 257; pSize < 264; ++pSize) + { + // Generate some parameters of the given size + AlgorithmParameterGenerator a = AlgorithmParameterGenerator.getInstance("ElGamal", "SC"); + a.init(pSize, new SecureRandom()); + AlgorithmParameters params = a.generateParameters(); + + DHParameterSpec elP = (DHParameterSpec)params.getParameterSpec(DHParameterSpec.class); + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ElGamal", "SC"); + + keyGen.initialize(elP); + + + // Run a short encrypt/decrypt test with random key for the given parameters + kp = keyGen.generateKeyPair(); + + PGPKeyPair elGamalKeyPair = new JcaPGPKeyPair( + PublicKeyAlgorithmTags.ELGAMAL_GENERAL, kp, new Date()); + + cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5).setSecureRandom(random)); + + puK = elGamalKeyPair.getPublicKey(); + + cPk.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(puK)); + + cbOut = new ByteArrayOutputStream(); + + cOut = cPk.open(cbOut, text.length); + + cOut.write(text); + + cOut.close(); + + pgpF = new JcaPGPObjectFactory(cbOut.toByteArray()); + + encList = (PGPEncryptedDataList)pgpF.nextObject(); + + encP = (PGPPublicKeyEncryptedData)encList.get(0); + + pgpPrivKey = elGamalKeyPair.getPrivateKey(); + + // Note: This is where an exception would be expected if the P size causes problems + clear = encP.getDataStream(new BcPublicKeyDataDecryptorFactory(pgpPrivKey)); + + ByteArrayOutputStream dec = new ByteArrayOutputStream(); + + int b; + while ((b = clear.read()) >= 0) + { + dec.write(b); + } + + byte[] decText = dec.toByteArray(); + + if (!areEqual(text, decText)) + { + fail("decrypted message incorrect"); + } + } + + // check sub key encoding + + it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + PGPPublicKey pgpKey = (PGPPublicKey)it.next(); + + if (!pgpKey.isMasterKey()) + { + byte[] kEnc = pgpKey.getEncoded(); + + JcaPGPObjectFactory objF = new JcaPGPObjectFactory(kEnc); + + PGPPublicKey k = (PGPPublicKey)objF.nextObject(); + + pKey = keyConverter.getPublicKey(k); + pgpKeyID = k.getKeyID(); + if (k.getBitStrength() != 1024) + { + fail("failed - key strength reported incorrectly."); + } + + if (objF.nextObject() != null) + { + fail("failed - stream not fully parsed."); + } + } + } + + } + catch (PGPException e) + { + fail("exception: " + e.getMessage(), e.getUnderlyingException()); + } + } + + public String getName() + { + return "PGPDSAElGamalTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new BcPGPDSAElGamalTest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/BcPGPDSATest.java b/pg/src/test/java/org/spongycastle/openpgp/test/BcPGPDSATest.java new file mode 100644 index 00000000..9bb70ba6 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/BcPGPDSATest.java @@ -0,0 +1,637 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.Security; +import java.util.Date; +import java.util.Iterator; + +import org.spongycastle.bcpg.BCPGOutputStream; +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.bcpg.PublicKeyAlgorithmTags; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPCompressedData; +import org.spongycastle.openpgp.PGPCompressedDataGenerator; +import org.spongycastle.openpgp.PGPKeyPair; +import org.spongycastle.openpgp.PGPLiteralData; +import org.spongycastle.openpgp.PGPLiteralDataGenerator; +import org.spongycastle.openpgp.PGPOnePassSignature; +import org.spongycastle.openpgp.PGPOnePassSignatureList; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; +import org.spongycastle.openpgp.PGPUtil; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder; +import org.spongycastle.openpgp.operator.bc.BcPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyConverter; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.test.SimpleTest; +import org.spongycastle.util.test.UncloseableOutputStream; + +public class BcPGPDSATest + extends SimpleTest +{ + byte[] testPubKey = + Base64.decode( + "mQGiBD9HBzURBACzkxRCVGJg5+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/V2X1y26VKsipolPfja4uyBOOyvbLQzRXJpYyBFY2hp" + + "ZG5hIChEU0EgVGVzdCBLZXkpIDxlcmljQGJvdW5jeWNhc3RsZS5vcmc+iFkEExEC" + + "ABkFAj9HBzUECwcDAgMVAgMDFgIBAh4BAheAAAoJEM0j9enEyjRDAlwAn2rrom0s" + + "MhufWK5vIRwg7gj5qsLEAJ4vnT5dPBVblofsG+pDoCVeJXGGng=="); + + byte[] testPrivKey = + 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=="); + + byte[] testPrivKey2 = + Base64.decode( + "lQHhBEAnoewRBADRvKgDhbV6pMzqYfUgBsLxSHzmycpuxGbjMrpyKHDOEemj" + + "iQb6TyyBKUoR28/pfshFP9R5urtKIT7wjVrDuOkxYkgRhNm+xmPXW2Lw3D++" + + "MQrC5VWe8ywBltz6T9msmChsaKo2hDhIiRI/mg9Q6rH9pJKtVGi4R7CgGxM2" + + "STQ5fwCgub38qGS1W2O4hUsa+3gva5gaNZUEAItegda4/H4t88XdWxW3D8pv" + + "RnFz26/ADdImVaQlBoumD15VmcgYoT1Djizey7X8vfV+pntudESzLbn3GHlI" + + "6C09seH4e8eYP63t7KU/qbUCDomlSswd1OgQ/RxfN86q765K2t3K1i3wDSxe" + + "EgSRyGKee0VNvOBFOFhuWt+patXaBADE1riNkUxg2P4lBNWwu8tEZRmsl/Ys" + + "DBIzXBshoMzZCvS5PnNXMW4G3SAaC9OC9jvKSx9IEWhKjfjs3QcWzXR28mcm" + + "5na0bTxeOMlaPPhBdkTCmFl0IITWlH/pFlR2ah9WYoWYhZEL2tqB82wByzxH" + + "SkSeD9V5oeSCdCcqiqkEmv4DAwLeNsQ2XGJVRmA4lld+CR5vRxpT/+/2xklp" + + "lxVf/nx0+thrHDpro3u/nINIIObk0gh59+zaEEe3APlHqbQVYWFhIGJiYiA8" + + "Y2NjQGRkZC5lZWU+iFoEExECABoFAkAnoewFCwcDAgEDFQIDAxYCAQIeAQIX" + + "gAAKCRA5nBpCS63az85BAKCbPfU8ATrFvkXhzGNGlc1BJo6DWQCgnK125xVK" + + "lWLpt6ZJJ7TXcx3nkm6wAgAAnQFXBEAnoe0QBACsQxPvaeBcv2TkbgU/5Wc/" + + "tO222dPE1mxFbXjGTKfb+6ge96iyD8kTRLrKCkEEeVBa8AZqMSoXUVN6tV8j" + + "/zD8Bc76o5iJ6wgpg3Mmy2GxInVfsfZN6/G3Y2ukmouz+CDNvQdUw8cTguIb" + + "QoV3XhQ03MLbfVmNcHsku9F4CuKNWwADBQP0DSSe8v5PXF9CSCXOIxBDcQ5x" + + "RKjyYOveqoH/4lbOV0YNUbIDZq4RaUdotpADuPREFmWf0zTB6KV/WIiag8XU" + + "WU9zdDvLKR483Bo6Do5pDBcN+NqfQ+ntGY9WJ7BSFnhQ3+07i1K+NsfFTRfv" + + "hf9X3MP75rCf7MxAIWHTabEmUf4DAwLeNsQ2XGJVRmA8DssBUCghogG9n8T3" + + "qfBeKsplGyCcF+JjPeQXkKQaoYGJ0aJz36qFP9d8DuWtT9soQcqIxVf6mTa8" + + "kN1594hGBBgRAgAGBQJAJ6HtAAoJEDmcGkJLrdrPpMkAnRyjQSKugz0YJqOB" + + "yGasMLQLxd2OAKCEIlhtCarlufVQNGZsuWxHVbU8crACAAA="); + + byte[] sig1 = + Base64.decode( + "owGbwMvMwCR4VvnryyOnTJwZ10gncZSkFpfolVSU2Ltz78hIzcnJVyjPL8pJUeTq" + + "sGdmZQCJwpQLMq3ayTA/0Fj3xf4jbwPfK/H3zj55Z9L1n2k/GOapKJrvMZ4tLiCW" + + "GtP/XeDqX4fORDUA"); + + byte[] sig1crc = Base64.decode("OZa/"); + + byte[] testPubWithUserAttr = + Base64.decode( + "mQGiBD2Rqv0RBADqKCkhVEtB/lEEr/9CubuHEy2oN/yU5j+2GXSdcNdVnRI/rwFy" + + "fHEQIk3uU7zHSUKFrC59yDm0sODYyjEdE3BVb0xvEJ5LE/OdndcIMXT1DungZ1vB" + + "zIK/3lr33W/PHixYxv9jduH3WrTehBpiKkgMZp8XloSFj2Cnw9LDyfqB7QCg/8K1" + + "o2k75NkOd9ZjnA9ye7Ri3bEEAKyr61Mo7viPWBK1joWAEsxG0OBWM+iSlG7kwh31" + + "8efgC/7Os6x4Y0jzs8mpcbBjeZtZjS9lRbfp7RinhF269xL0TZ3JxIdtaAV/6yDQ" + + "9NXfZY9dskN++HIR/5GCEEgq/qTJZt6ti5k7aV19ZFfO6wiK3NUy08wOrVsdOkVE" + + "w9IcBADaplhpcel3201uU3OCboogJtw81R5MJMZ4Y9cKL/ca2jGISn0nA7KrAw9v" + + "ShheSixGO4BV9JECkLEbtg7i+W/j/De6S+x2GLNcphuTP3UmgtKbhs0ItRqzW561" + + "s6gLkqi6aWmgaFLd8E1pMJcd9DSY95P13EYB9VJIUxFNUopzo7QcUmFsZiBIYXVz" + + "ZXIgPGhhdXNlckBhY20ub3JnPokAWAQQEQIAGAUCPZGq/QgLAwkIBwIBCgIZAQUb" + + "AwAAAAAKCRAqIBiOh4JvOKg4AJ9j14yygOqqzqiLKeaasIzqT8LCIgCggx14WuLO" + + "wOUTUswTaVKMFnU7tseJAJwEEAECAAYFAj2Rqx8ACgkQ9aWTKMpUDFV+9QP/RiWT" + + "5FAF5Rgb7beaApsgXsME+Pw7HEYFtqGa6VcXEpbcUXO6rjaXsgMgY90klWlWCF1T" + + "HOyKITvj2FdhE+0j8NQn4vaGpiTwORW/zMf/BZ0abdSWQybp10Yjs8gXw30UheO+" + + "F1E524MC+s2AeUi2hwHMiS+AVYd4WhxWHmWuBpTRypP/AAALTgEQAAEBAAAAAQAA" + + "AAABAAAA/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAoHBwgHBgoICAgLCgoLDhgQ" + + "Dg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/" + + "2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7" + + "Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wAARCABqAF0DASIAAhEBAxEB/8QAHwAAAQUB" + + "AQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQID" + + "AAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0" + + "NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKT" + + "lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl" + + "5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL" + + "/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHB" + + "CSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpj" + + "ZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3" + + "uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIR" + + "AxEAPwD2aiiq9xcxWsRllcKqjOT06E/0oAsVm6jrmm6VGXvLuOPGflz8x+grzXxV" + + "8U51u5LXRgBGowZHXknnkc9OQcV51caneXdw9xPOXlckl2AJHY4J6cD1oA9J1z4p" + + "TRkrYQhRyQ0hIY5/2QRx7k9ulczN8SvEEshdZkX0UorDrznI759a5Mksckkknqec" + + "mkoA7WD4oavEoEttbTepYEZ+mCMVv6H8SLTULhbe/gFozAYkD5Unp3Ax/kV5XRQB" + + "9EAhgCDkHkEcgilryTwd4zn0m4WzvpTJZSMBuY5MfbueletKyugZWDKwyCOc/j3o" + + "AduyWLDeWB5Ynj8jSUUUAdFXn/xU15dO0RbGGYC5uWwUB6L1Jx+n413F1cJa2stz" + + "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" + + "7DGrzw=="); + + byte[] aesSecretKey = Base64.decode( + "lQHpBEBSdIYRBADpd7MeIxRk4RsvyMnJNIYe4FiVv6i7I7+LPRvnIjDct0bN" + + "1gCV48QFej7g/PsvXRjYSowV3VIvchWX8OERd/5i10cLbcs7X52EP1vwYaLj" + + "uRfNUBg8Q51RQsKR+/rBmnVsi68rjU4yTH6wpo6FOO4pz4wFV+tWwGOwOitA" + + "K31L4wCgqh59eFFBrOlRFAbDvaL7emoCIR8EAOLxDKiLQJYQrKZfXdZnifeo" + + "dhEP0uuV4O5TG6nrqkhWffzC9cSoFD0BhMl979d8IB2Uft4FNvQc2u8hbJL5" + + "7OCGDCUAidlB9jSdu0/J+kfRaTGhYDjBgw7AA42576BBSMNouJg/aOOQENEN" + + "Nn4n7NxR3viBzIsL/OIeU8HSkBgaA/41PsvcgZ3kwpdltJ/FVRWhmMmv/q/X" + + "qp1YOnF8xPU9bv2ofELrxJfRsbS4GW1etzD+nXs/woW4Vfixs01x+cutR4iF" + + "3hw+eU+yLToMPmmo8D2LUvX1SRODJpx5yBBeRIYv6nz9H3sQRDx3kaLASxDV" + + "jTxKmrLYnZz5w5qyVpvRyv4JAwKyWlhdblPudWBFXNkW5ydKn0AV2f51wEtj" + + "Zy0aLIeutVMSJf1ytLqjFqrnFe6pdJrHO3G00TE8OuFhftWosLGLbEGytDtF" + + "cmljIEguIEVjaGlkbmEgKHRlc3Qga2V5IC0gQUVTMjU2KSA8ZXJpY0Bib3Vu" + + "Y3ljYXN0bGUub3JnPohZBBMRAgAZBQJAUnSGBAsHAwIDFQIDAxYCAQIeAQIX" + + "gAAKCRBYt1NnUiCgeFKaAKCiqtOO+NQES1gJW6XuOGmSkXt8bQCfcuW7SXZH" + + "zxK1FfdcG2HEDs3YEVawAgAA"); + + byte[] aesPublicKey = Base64.decode( + "mQGiBEBSdIYRBADpd7MeIxRk4RsvyMnJNIYe4FiVv6i7I7+LPRvnIjDct0bN" + + "1gCV48QFej7g/PsvXRjYSowV3VIvchWX8OERd/5i10cLbcs7X52EP1vwYaLj" + + "uRfNUBg8Q51RQsKR+/rBmnVsi68rjU4yTH6wpo6FOO4pz4wFV+tWwGOwOitA" + + "K31L4wCgqh59eFFBrOlRFAbDvaL7emoCIR8EAOLxDKiLQJYQrKZfXdZnifeo" + + "dhEP0uuV4O5TG6nrqkhWffzC9cSoFD0BhMl979d8IB2Uft4FNvQc2u8hbJL5" + + "7OCGDCUAidlB9jSdu0/J+kfRaTGhYDjBgw7AA42576BBSMNouJg/aOOQENEN" + + "Nn4n7NxR3viBzIsL/OIeU8HSkBgaA/41PsvcgZ3kwpdltJ/FVRWhmMmv/q/X" + + "qp1YOnF8xPU9bv2ofELrxJfRsbS4GW1etzD+nXs/woW4Vfixs01x+cutR4iF" + + "3hw+eU+yLToMPmmo8D2LUvX1SRODJpx5yBBeRIYv6nz9H3sQRDx3kaLASxDV" + + "jTxKmrLYnZz5w5qyVpvRyrQ7RXJpYyBILiBFY2hpZG5hICh0ZXN0IGtleSAt" + + "IEFFUzI1NikgPGVyaWNAYm91bmN5Y2FzdGxlLm9yZz6IWQQTEQIAGQUCQFJ0" + + "hgQLBwMCAxUCAwMWAgECHgECF4AACgkQWLdTZ1IgoHhSmgCfU83BLBF2nCua" + + "zk2dXB9zO1l6XS8AnA07U4cq5W0GrKM6/kP9HWtPhgOFsAIAAA=="); + + byte[] twofishSecretKey = Base64.decode( + "lQHpBEBSdtIRBACf7WfrqTl8F051+EbaljPf/8/ajFpAfMq/7p3Hri8OCsuc" + + "fJJIufEEOV1/Lt/wkN67MmSyrU0fUCsRbEckRiB4EJ0zGHVFfAnku2lzdgc8" + + "AVounqcHOmqA/gliFDEnhYOx3bOIAOav+yiOqfKVBhWRCpFdOTE+w/XoDM+p" + + "p8bH5wCgmP2FuWpzfSut7GVKp51xNEBRNuED/3t2Q+Mq834FVynmLKEmeXB/" + + "qtIz5reHEQR8eMogsOoJS3bXs6v3Oblj4in1gLyTVfcID5tku6kLP20xMRM2" + + "zx2oRbz7TyOCrs15IpRXyqqJxUWD8ipgJPkPXE7hK8dh4YSTUi4i5a1ug8xG" + + "314twlPzrchpWZiutDvZ+ks1rzOtBACHrEFG2frUu+qVkL43tySE0cV2bnuK" + + "LVhXbpzF3Qdkfxou2nuzsCbl6m87OWocJX8uYcQGlHLKv8Q2cfxZyieLFg6v" + + "06LSFdE9drGBWz7mbrT4OJjxPyvnkffPfLOOqae3PMYIIuscvswuhm4X5aoj" + + "KJs01YT3L6f0iIj03hCeV/4KAwLcGrxT3X0qR2CZyZYSVBdjXeNYKXuGBtOf" + + "ood26WOtwLw4+l9sHVoiXNv0LomkO58ndJRPGCeZWZEDMVrfkS7rcOlktDxF" + + "cmljIEguIEVjaGlkbmEgKHRlc3Qga2V5IC0gdHdvZmlzaCkgPGVyaWNAYm91" + + "bmN5Y2FzdGxlLm9yZz6IWQQTEQIAGQUCQFJ20gQLBwMCAxUCAwMWAgECHgEC" + + "F4AACgkQaCCMaHh9zR2+RQCghcQwlt4B4YmNxp2b3v6rP3E8M0kAn2Gspi4u" + + "A/ynoqnC1O8HNlbjPdlVsAIAAA=="); + + byte[] twofishPublicKey = Base64.decode( + "mQGiBEBSdtIRBACf7WfrqTl8F051+EbaljPf/8/ajFpAfMq/7p3Hri8OCsuc" + + "fJJIufEEOV1/Lt/wkN67MmSyrU0fUCsRbEckRiB4EJ0zGHVFfAnku2lzdgc8" + + "AVounqcHOmqA/gliFDEnhYOx3bOIAOav+yiOqfKVBhWRCpFdOTE+w/XoDM+p" + + "p8bH5wCgmP2FuWpzfSut7GVKp51xNEBRNuED/3t2Q+Mq834FVynmLKEmeXB/" + + "qtIz5reHEQR8eMogsOoJS3bXs6v3Oblj4in1gLyTVfcID5tku6kLP20xMRM2" + + "zx2oRbz7TyOCrs15IpRXyqqJxUWD8ipgJPkPXE7hK8dh4YSTUi4i5a1ug8xG" + + "314twlPzrchpWZiutDvZ+ks1rzOtBACHrEFG2frUu+qVkL43tySE0cV2bnuK" + + "LVhXbpzF3Qdkfxou2nuzsCbl6m87OWocJX8uYcQGlHLKv8Q2cfxZyieLFg6v" + + "06LSFdE9drGBWz7mbrT4OJjxPyvnkffPfLOOqae3PMYIIuscvswuhm4X5aoj" + + "KJs01YT3L6f0iIj03hCeV7Q8RXJpYyBILiBFY2hpZG5hICh0ZXN0IGtleSAt" + + "IHR3b2Zpc2gpIDxlcmljQGJvdW5jeWNhc3RsZS5vcmc+iFkEExECABkFAkBS" + + "dtIECwcDAgMVAgMDFgIBAh4BAheAAAoJEGggjGh4fc0dvkUAn2QGdNk8Wrrd" + + "+DvKECrO5+yoPRx3AJ91DhCMme6uMrQorKSDYxHlgc7iT7ACAAA="); + + char[] pass = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' }; + + /** + * Generated signature test + * + * @param sKey + * @param pgpPrivKey + */ + public void generateTest( + PGPSecretKeyRing sKey, + PGPPublicKey pgpPubKey, + PGPPrivateKey pgpPrivKey) + throws Exception + { + String data = "hello world!"; + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ByteArrayInputStream testIn = new ByteArrayInputStream(data.getBytes()); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1)); + + sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey); + + PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); + + Iterator it = sKey.getSecretKey().getPublicKey().getUserIDs(); + String primaryUserID = (String)it.next(); + + spGen.setSignerUserID(true, primaryUserID); + + sGen.setHashedSubpackets(spGen.generate()); + + PGPCompressedDataGenerator cGen = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + BCPGOutputStream bcOut = new BCPGOutputStream( + cGen.open(new UncloseableOutputStream(bOut))); + + sGen.generateOnePassVersion(false).encode(bcOut); + + PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); + + Date testDate = new Date((System.currentTimeMillis() / 1000) * 1000); + OutputStream lOut = lGen.open( + new UncloseableOutputStream(bcOut), + PGPLiteralData.BINARY, + "_CONSOLE", + data.getBytes().length, + testDate); + + int ch; + while ((ch = testIn.read()) >= 0) + { + lOut.write(ch); + sGen.update((byte)ch); + } + + lGen.close(); + + sGen.generate().encode(bcOut); + + cGen.close(); + + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(bOut.toByteArray()); + PGPCompressedData c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + + PGPOnePassSignatureList p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + PGPOnePassSignature ops = p1.get(0); + + PGPLiteralData p2 = (PGPLiteralData)pgpFact.nextObject(); + if (!p2.getModificationTime().equals(testDate)) + { + fail("Modification time not preserved"); + } + + InputStream dIn = p2.getInputStream(); + + ops.init(new BcPGPContentVerifierBuilderProvider(), pgpPubKey); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + PGPSignatureList p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed generated signature check"); + } + } + + public void performTest() + throws Exception + { + String file = null; + KeyFactory fact = KeyFactory.getInstance("DSA", "SC"); + PGPPublicKey pubKey = null; + PrivateKey privKey = null; + + PGPUtil.setDefaultProvider("SC"); + + // + // Read the public key + // + PGPPublicKeyRing pgpPub = new PGPPublicKeyRing(testPubKey, new BcKeyFingerprintCalculator()); + + pubKey = pgpPub.getPublicKey(); + + // + // Read the private key + // + PGPSecretKeyRing sKey = new PGPSecretKeyRing(testPrivKey, new BcKeyFingerprintCalculator()); + PGPPrivateKey pgpPrivKey = sKey.getSecretKey().extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass)); + + // + // test signature message + // + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(sig1); + + PGPCompressedData c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + PGPOnePassSignatureList p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + + PGPOnePassSignature ops = p1.get(0); + + PGPLiteralData p2 = (PGPLiteralData)pgpFact.nextObject(); + + InputStream dIn = p2.getInputStream(); + int ch; + + ops.init(new BcPGPContentVerifierBuilderProvider(), pubKey); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + PGPSignatureList p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed signature check"); + } + + // + // signature generation + // + generateTest(sKey, pubKey, pgpPrivKey); + + // + // signature generation - canonical text + // + String data = "hello world!"; + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ByteArrayInputStream testIn = new ByteArrayInputStream(data.getBytes()); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(PGPPublicKey.DSA, PGPUtil.SHA1)); + + sGen.init(PGPSignature.CANONICAL_TEXT_DOCUMENT, pgpPrivKey); + + PGPCompressedDataGenerator cGen = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + BCPGOutputStream bcOut = new BCPGOutputStream( + cGen.open(new UncloseableOutputStream(bOut))); + + sGen.generateOnePassVersion(false).encode(bcOut); + + PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); + Date testDate = new Date((System.currentTimeMillis() / 1000) * 1000); + OutputStream lOut = lGen.open( + new UncloseableOutputStream(bcOut), + PGPLiteralData.TEXT, + "_CONSOLE", + data.getBytes().length, + testDate); + + while ((ch = testIn.read()) >= 0) + { + lOut.write(ch); + sGen.update((byte)ch); + } + + lGen.close(); + + sGen.generate().encode(bcOut); + + cGen.close(); + + // + // verify generated signature - canconical text + // + pgpFact = new JcaPGPObjectFactory(bOut.toByteArray()); + + c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + + ops = p1.get(0); + + p2 = (PGPLiteralData)pgpFact.nextObject(); + if (!p2.getModificationTime().equals(testDate)) + { + fail("Modification time not preserved"); + } + + dIn = p2.getInputStream(); + + ops.init(new BcPGPContentVerifierBuilderProvider(), pubKey); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed generated signature check"); + } + + // + // Read the public key with user attributes + // + pgpPub = new PGPPublicKeyRing(testPubWithUserAttr, new BcKeyFingerprintCalculator()); + + pubKey = pgpPub.getPublicKey(); + + Iterator it = pubKey.getUserAttributes(); + int count = 0; + while (it.hasNext()) + { + PGPUserAttributeSubpacketVector attributes = (PGPUserAttributeSubpacketVector)it.next(); + + Iterator sigs = pubKey.getSignaturesForUserAttribute(attributes); + int sigCount = 0; + while (sigs.hasNext()) + { + sigs.next(); + + sigCount++; + } + + if (sigCount != 1) + { + fail("Failed user attributes signature check"); + } + count++; + } + + if (count != 1) + { + fail("Failed user attributes check"); + } + + byte[] pgpPubBytes = pgpPub.getEncoded(); + + pgpPub = new PGPPublicKeyRing(pgpPubBytes, new BcKeyFingerprintCalculator()); + + pubKey = pgpPub.getPublicKey(); + + it = pubKey.getUserAttributes(); + count = 0; + while (it.hasNext()) + { + it.next(); + count++; + } + + if (count != 1) + { + fail("Failed user attributes reread"); + } + + // + // reading test extra data - key with edge condition for DSA key password. + // + char [] passPhrase = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + + sKey = new PGPSecretKeyRing(testPrivKey2, new BcKeyFingerprintCalculator()); + pgpPrivKey = sKey.getSecretKey().extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(passPhrase)); + + byte[] bytes = new JcaPGPKeyConverter().setProvider("SC").getPrivateKey(pgpPrivKey).getEncoded(); + + // + // reading test - aes256 encrypted passphrase. + // + sKey = new PGPSecretKeyRing(aesSecretKey, new BcKeyFingerprintCalculator()); + pgpPrivKey = sKey.getSecretKey().extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass)); + + bytes = new JcaPGPKeyConverter().setProvider("SC").getPrivateKey(pgpPrivKey).getEncoded(); + + // + // reading test - twofish encrypted passphrase. + // + sKey = new PGPSecretKeyRing(twofishSecretKey, new BcKeyFingerprintCalculator()); + pgpPrivKey = sKey.getSecretKey().extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass)); + + bytes = new JcaPGPKeyConverter().setProvider("SC").getPrivateKey(pgpPrivKey).getEncoded(); + + // + // use of PGPKeyPair + // + KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA", "SC"); + + kpg.initialize(512); + + KeyPair kp = kpg.generateKeyPair(); + + PGPKeyPair pgpKp = new JcaPGPKeyPair(PGPPublicKey.DSA, kp, new Date()); + + PGPPublicKey k1 = pgpKp.getPublicKey(); + + PGPPrivateKey k2 = pgpKp.getPrivateKey(); + } + + public String getName() + { + return "BcPGPDSATest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new BcPGPDSATest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/BcPGPKeyRingTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/BcPGPKeyRingTest.java new file mode 100644 index 00000000..30de8bc3 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/BcPGPKeyRingTest.java @@ -0,0 +1,2356 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayInputStream; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Date; +import java.util.Iterator; + +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.jce.spec.ElGamalParameterSpec; +import org.spongycastle.openpgp.PGPEncryptedData; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPKeyPair; +import org.spongycastle.openpgp.PGPKeyRingGenerator; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.bc.BcPGPPublicKeyRingCollection; +import org.spongycastle.openpgp.bc.BcPGPSecretKeyRingCollection; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.openpgp.operator.PGPDigestCalculator; +import org.spongycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder; +import org.spongycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class BcPGPKeyRingTest + extends SimpleTest +{ + byte[] pub1 = Base64.decode( + "mQGiBEA83v0RBADzKVLVCnpWQxX0LCsevw/3OLs0H7MOcLBQ4wMO9sYmzGYn" + + "xpVj+4e4PiCP7QBayWyy4lugL6Lnw7tESvq3A4v3fefcxaCTkJrryiKn4+Cg" + + "y5rIBbrSKNtCEhVi7xjtdnDjP5kFKgHYjVOeIKn4Cz/yzPG3qz75kDknldLf" + + "yHxp2wCgwW1vAE5EnZU4/UmY7l8kTNkMltMEAJP4/uY4zcRwLI9Q2raPqAOJ" + + "TYLd7h+3k/BxI0gIw96niQ3KmUZDlobbWBI+VHM6H99vcttKU3BgevNf8M9G" + + "x/AbtW3SS4De64wNSU3189XDG8vXf0vuyW/K6Pcrb8exJWY0E1zZQ1WXT0gZ" + + "W0kH3g5ro//Tusuil9q2lVLF2ovJA/0W+57bPzi318dWeNs0tTq6Njbc/GTG" + + "FUAVJ8Ss5v2u6h7gyJ1DB334ExF/UdqZGldp0ugkEXaSwBa2R7d3HBgaYcoP" + + "Ck1TrovZzEY8gm7JNVy7GW6mdOZuDOHTxyADEEP2JPxh6eRcZbzhGuJuYIif" + + "IIeLOTI5Dc4XKeV32a+bWrQidGVzdCAoVGVzdCBrZXkpIDx0ZXN0QHViaWNh" + + "bGwuY29tPohkBBMRAgAkBQJAPN79AhsDBQkB4TOABgsJCAcDAgMVAgMDFgIB" + + "Ah4BAheAAAoJEJh8Njfhe8KmGDcAoJWr8xgPr75y/Cp1kKn12oCCOb8zAJ4p" + + "xSvk4K6tB2jYbdeSrmoWBZLdMLACAAC5AQ0EQDzfARAEAJeUAPvUzJJbKcc5" + + "5Iyb13+Gfb8xBWE3HinQzhGr1v6A1aIZbRj47UPAD/tQxwz8VAwJySx82ggN" + + "LxCk4jW9YtTL3uZqfczsJngV25GoIN10f4/j2BVqZAaX3q79a3eMiql1T0oE" + + "AGmD7tO1LkTvWfm3VvA0+t8/6ZeRLEiIqAOHAAQNBACD0mVMlAUgd7REYy/1" + + "mL99Zlu9XU0uKyUex99sJNrcx1aj8rIiZtWaHz6CN1XptdwpDeSYEOFZ0PSu" + + "qH9ByM3OfjU/ya0//xdvhwYXupn6P1Kep85efMBA9jUv/DeBOzRWMFG6sC6y" + + "k8NGG7Swea7EHKeQI40G3jgO/+xANtMyTIhPBBgRAgAPBQJAPN8BAhsMBQkB" + + "4TOAAAoJEJh8Njfhe8KmG7kAn00mTPGJCWqmskmzgdzeky5fWd7rAKCNCp3u" + + "ZJhfg0htdgAfIy8ppm05vLACAAA="); + + byte[] sec1 = Base64.decode( + "lQHhBEA83v0RBADzKVLVCnpWQxX0LCsevw/3OLs0H7MOcLBQ4wMO9sYmzGYn" + + "xpVj+4e4PiCP7QBayWyy4lugL6Lnw7tESvq3A4v3fefcxaCTkJrryiKn4+Cg" + + "y5rIBbrSKNtCEhVi7xjtdnDjP5kFKgHYjVOeIKn4Cz/yzPG3qz75kDknldLf" + + "yHxp2wCgwW1vAE5EnZU4/UmY7l8kTNkMltMEAJP4/uY4zcRwLI9Q2raPqAOJ" + + "TYLd7h+3k/BxI0gIw96niQ3KmUZDlobbWBI+VHM6H99vcttKU3BgevNf8M9G" + + "x/AbtW3SS4De64wNSU3189XDG8vXf0vuyW/K6Pcrb8exJWY0E1zZQ1WXT0gZ" + + "W0kH3g5ro//Tusuil9q2lVLF2ovJA/0W+57bPzi318dWeNs0tTq6Njbc/GTG" + + "FUAVJ8Ss5v2u6h7gyJ1DB334ExF/UdqZGldp0ugkEXaSwBa2R7d3HBgaYcoP" + + "Ck1TrovZzEY8gm7JNVy7GW6mdOZuDOHTxyADEEP2JPxh6eRcZbzhGuJuYIif" + + "IIeLOTI5Dc4XKeV32a+bWv4CAwJ5KgazImo+sGBfMhDiBcBTqyDGhKHNgHic" + + "0Pky9FeRvfXTc2AO+jGmFPjcs8BnTWuDD0/jkQnRZpp1TrQidGVzdCAoVGVz" + + "dCBrZXkpIDx0ZXN0QHViaWNhbGwuY29tPohkBBMRAgAkBQJAPN79AhsDBQkB" + + "4TOABgsJCAcDAgMVAgMDFgIBAh4BAheAAAoJEJh8Njfhe8KmGDcAn3XeXDMg" + + "BZgrZzFWU2IKtA/5LG2TAJ0Vf/jjyq0jZNZfGfoqGTvD2MAl0rACAACdAVgE" + + "QDzfARAEAJeUAPvUzJJbKcc55Iyb13+Gfb8xBWE3HinQzhGr1v6A1aIZbRj4" + + "7UPAD/tQxwz8VAwJySx82ggNLxCk4jW9YtTL3uZqfczsJngV25GoIN10f4/j" + + "2BVqZAaX3q79a3eMiql1T0oEAGmD7tO1LkTvWfm3VvA0+t8/6ZeRLEiIqAOH" + + "AAQNBACD0mVMlAUgd7REYy/1mL99Zlu9XU0uKyUex99sJNrcx1aj8rIiZtWa" + + "Hz6CN1XptdwpDeSYEOFZ0PSuqH9ByM3OfjU/ya0//xdvhwYXupn6P1Kep85e" + + "fMBA9jUv/DeBOzRWMFG6sC6yk8NGG7Swea7EHKeQI40G3jgO/+xANtMyTP4C" + + "AwJ5KgazImo+sGBl2C7CFuI+5KM4ZhbtVie7l+OiTpr5JW2z5VgnV3EX9p04" + + "LcGKfQvD65+ELwli6yh8B2zGcipqTaYk3QoYNIhPBBgRAgAPBQJAPN8BAhsM" + + "BQkB4TOAAAoJEJh8Njfhe8KmG7kAniuRkaFFv1pdCBN8JJXpcorHmyouAJ9L" + + "xxmusffR6OI7WgD3XZ0AL8zUC7ACAAA="); + + char[] pass1 = "qwertzuiop".toCharArray(); + + byte[] pub2 = Base64.decode( + "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"); + + byte[] sec2 = Base64.decode( + "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" + + "Nifs+ljmsAFn"); + + + char[] sec2pass1 = "sandhya".toCharArray(); + char[] sec2pass2 = "psai".toCharArray(); + + byte[] pub3 = Base64.decode( + "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" + + "n3FaE6UZE9GMDmCIAjhI+0X9aH6CsAIAAw=="); + + byte[] sec3 = Base64.decode( + "lQHhBEB9BH0RBACtYQtE7tna6hgGyGLpq+ds3r2cLC0ISn5dNw7tm9vwiNVF" + + "JA2N37RRrifw4PvgelRSvLaX3M3ZBqC9s1Metg3v4FSlIRtSLWCNpHSvNw7i" + + "X8C2Xy9Hdlbh6Y/50o+iscojLRE14upfR1bIkcCZQGSyvGV52V2wBImUUZjV" + + "s2ZngwCg7mu852vK7+euz4WaL7ERVYtq9CMEAJ5swrljerDpz/RQ4Lhp6KER" + + "KyuI0PUttO57xINGshEINgYlZdGaZHRueHe7uKfI19mb0T4N3NJWaZ0wF+Cn" + + "rixsq0VrTUfiwfZeGluNG73aTCeY45fVXMGTTSYXzS8T0LW100Xn/0g9HRyA" + + "xUpuWo8IazxkMqHJis2uwriYKpAfA/9anvj5BS9p5pfPjp9dGM7GTMIYl5f2" + + "fcP57f+AW1TVR6IZiMJAvAdeWuLtwLnJiFpGlnFz273pfl+sAuqm1yNceImR" + + "2SDDP4+vtyycWy8nZhgEuhZx3W3cWMQz5WyNJSY1JJHh9TCQkCoN8E7XpVP4" + + "zEPboB2GzD93mfD8JLHP+/4DAwIvYrn+YqRaaGAu19XUj895g/GROyP8WEaU" + + "Bd/JNqWc4kE/0guetGnPzq7G3bLVwiKfFd4X7BrgHAo3mrQtVGVzdCBLZXkg" + + "KG5vIGNvbW1lbnQpIDx0ZXN0QGJvdW5jeWNhc3RsZS5vcmc+iFkEExECABkF" + + "AkB9BH0ECwcDAgMVAgMDFgIBAh4BAheAAAoJEKnMV8vjZQOpSRQAoKZy6YS1" + + "irF5/Q3JlWiwbkN6dEuLAJ9lldRLOlXsuQ5JW1+SLEc6K9ho4rACAADRwXPB" + + "cQEQAAEBAAAAAAAAAAAAAAAA/9j/4AAQSkZJRgABAQEASABIAAD//gAXQ3Jl" + + "YXRlZCB3aXRoIFRoZSBHSU1Q/9sAQwAIBgYHBgUIBwcHCQkICgwUDQwLCwwZ" + + "EhMPFB0aHx4dGhwcICQuJyAiLCMcHCg3KSwwMTQ0NB8nOT04MjwuMzQy/9sA" + + "QwEJCQkMCwwYDQ0YMiEcITIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy" + + "MjIyMjIyMjIyMjIyMjIyMjIyMjIy/8AAEQgAFAAUAwEiAAIRAQMRAf/EABoA" + + "AQACAwEAAAAAAAAAAAAAAAAEBQIDBgf/xAAoEAABAgUDBAEFAAAAAAAAAAAB" + + "AgMABBEhMQUSQQYTIiNhFFGBkcH/xAAXAQEAAwAAAAAAAAAAAAAAAAAEAgMF" + + "/8QAJBEAAQQAAwkAAAAAAAAAAAAAAQACERIEIfATMTJBUZGx0fH/2gAMAwEA" + + "AhEDEQA/APMuotJlJVxstqaPo22NlAUp+YsNO0qSUtBcMu6n6EtOHcfPAHHF" + + "I16++oajQtTA3DapK02HFR8UpE9pTbQWtKm2WG2rlxVyQTcfGbn7Qm0OIjL7" + + "7Wrs2NNm9lzTmmSxQ0PX4opSprk5tmESF6syggzGwOLG6gXgHFbZhBixk8Xl" + + "IDcOQLRKt+rX+3qC5ZLTQblpQlvwvxn9CMpZturVGkJHapQJphRH8hCLXbzr" + + "qpYsCx1zC5rtpJNuYQhASc0UAQv/2YhcBBMRAgAcBQJAfQV+AhsDBAsHAwID" + + "FQIDAxYCAQIeAQIXgAAKCRCpzFfL42UDqfa2AJ9hjtEeDTbTEAuuSbzhYFxN" + + "/qc0FACgsmzysdbBpuN65yK01tbEaeIMtqCwAgAAnQEUBEB9BH4QAwCqRuWO" + + "rxm5v/8WWBtPEUZnYuu3WYxefRKn6ON5ka5Ymp4AfKpKqKqn982tjlG13GVE" + + "P2ow11L4yQKGNm+VyVEapm7SpMD0SHg9vsJygAWrfMJnBYWSgE19W6o3ckUR" + + "sWsAAwYDAKDCSiSxC3Z5/POaCehw5iHs/vmVk5Wn831LSZEEwkSohNDbIEry" + + "ia/9tFXSt11AP4stJtZ0MH87/6JBbiIRD4JXcx+zfzchL7Teczr/06QMphSn" + + "sAENupbhLupfpR+BbP4DAwIvYrn+YqRaaGBjvFK1fbxCt7ZM4I2W/3BC0lCX" + + "m/NypKNspGflec8u96uUlA0fNCnxm6f9nbB0jpvoKi0g4iqAf+P2iEYEGBEC" + + "AAYFAkB9BH4ACgkQqcxXy+NlA6mtMgCgvccZA/Sg7BXVpxli47SYhxSHoM4A" + + "oNCOMplSnYTuh5ikKeBWtz36gC1psAIAAA=="); + + char[] sec3pass1 = "123456".toCharArray(); + + // + // GPG comment packets. + // + byte[] sec4 = Base64.decode( + "lQG7BD0PbK8RBAC0cW4Y2MZXmAmqYp5Txyw0kSQsFvwZKHNMFRv996IsN57URVF5" + + "BGMVPRBi9dNucWbjiSYpiYN13wE9IuLZsvVaQojV4XWGRDc+Rxz9ElsXnsYQ3mZU" + + "7H1bNQEofstChk4z+dlvPBN4GFahrIzn/CeVUn6Ut7dVdYbiTqviANqNXwCglfVA" + + "2OEePvqFnGxs1jhJyPSOnTED/RwRvsLH/k43mk6UEvOyN1RIpBXN+Ieqs7h1gFrQ" + + "kB+WMgeP5ZUsotTffVDSUS9UMxRQggVUW1Xml0geGwQsNfkr/ztWMs/T4xp1v5j+" + + "QyJx6OqNlkGdqOsoqkzJx0SQ1zBxdinFyyC4H95SDAb/RQOu5LQmxFG7quexztMs" + + "infEA/9cVc9+qCo92yRAaXRqKNVVQIQuPxeUsGMyVeJQvJBD4An8KTMCdjpF10Cp" + + "qA3t+n1S0zKr5WRUtvS6y60MOONO+EJWVWBNkx8HJDaIMNkfoqQoz3Krn7w6FE/v" + + "/5uwMd6jY3N3yJZn5nDZT9Yzv9Nx3j+BrY+henRlSU0c6xDc9QAAnjJYg0Z83VJG" + + "6HrBcgc4+4K6lHulCqH9JiM6RFNBX2ZhY3RvcjoAAK9hV206agp99GI6x5qE9+pU" + + "vs6O+Ich/SYjOkRTQV9mYWN0b3I6AACvYAfGn2FGrpBYbjnpTuFOHJMS/T5xg/0m" + + "IzpEU0FfZmFjdG9yOgAAr0dAQz6XxMwxWIn8xIZR/v2iN2L9C6O0EkZvbyBCYXIg" + + "PGJhekBxdXV4PohXBBMRAgAXBQI9D2yvBQsHCgMEAxUDAgMWAgECF4AACgkQUGLI" + + "YCIktfoGogCfZiXMJUKrScqozv5tMwzTTk2AaT8AniM5iRr0Du/Y08SL/NMhtF6H" + + "hJ89nO4EPQ9ssRADAI6Ggxj6ZBfoavuXd/ye99osW8HsNlbqhXObu5mCMNySX2wa" + + "HoWyRUEaUkI9eQw+MlHzIwzA32E7y2mU3OQBKdgLcBg4jxtcWVEg8ESKF9MpFXxl" + + "pExxWrr4DFBfCRcsTwAFEQL9G3OvwJuEZXgx2JSS41D3pG4/qiHYICVa0u3p/14i" + + "cq0kXajIk5ZJ6frCIAHIzuQ3n7jjzr05yR8s/qCrNbBA+nlkVNa/samk+jCzxxxa" + + "cR/Dbh2wkvTFuDFFETwQYLuZAADcDck4YGQAmHivVT2NNDCf/aTz0+CJWl+xRc2l" + + "Qw7D/SQjOkVMR19mYWN0b3I6AACbBnv9m5/bb/pjYAm2PtDp0CysQ9X9JCM6RUxH" + + "X2ZhY3RvcjoAAJsFyHnSmaWguTFf6lJ/j39LtUNtmf0kIzpFTEdfZmFjdG9yOgAA" + + "mwfwMD3LxmWtuCWBE9BptWMNH07Z/SQjOkVMR19mYWN0b3I6AACbBdhBrbSiM4UN" + + "y7khDW2Sk0e4v9mIRgQYEQIABgUCPQ9ssQAKCRBQYshgIiS1+jCMAJ9txwHnb1Kl" + + "6i/fSoDs8SkdM7w48wCdFvPEV0sSxE73073YhBgPZtMWbBo="); + + // + // PGP freeware version 7 + // + byte[] pub5 = Base64.decode( + "mQENBEBrBE4BCACjXVcNIFDQSofaIyZnALb2CRg+WY9uUqgHEEAOlPe03Cs5STM5" + + "HDlNmrh4TdFceJ46rxk1mQOjULES1YfHay8lCIzrD7FX4oj0r4DC14Fs1vXaSar2" + + "1szIpttOw3obL4A1e0p6N4jjsoG7N/pA0fEL0lSw92SoBrMbAheXRg4qNTZvdjOR" + + "grcuOuwgJRvPLtRXlhyLBoyhkd5mmrIDGv8QHJ/UjpeIcRXY9kn9oGXnEYcRbMaU" + + "VwXB4pLzWqz3ZejFI3lOxRWjm760puPOnGYlzSVBxlt2LgzUgSj1Mn+lIpWmAzsa" + + "xEiU4xUwEomQns72yYRZ6D3euNCibcte4SeXABEBAAG0KXBhbGFzaCBrYXNvZGhh" + + "biA8cGthc29kaGFuQHRpYWEtY3JlZi5vcmc+iQEuBBABAgAYBQJAawROCAsBAwkI" + + "BwIKAhkBBRsDAAAAAAoJEOfelumuiOrYqPEH+wYrdP5Tq5j+E5yN1pyCg1rwbSOt" + + "Dka0y0p7Oq/VIGLk692IWPItLEunnBXQtGBcWqklrvogvlhxtf16FgoyScfLJx1e" + + "1cJa+QQnVuH+VOESN6iS9Gp9lUfVOHv74mEMXw0l2Djfy/lnrkAMBatggyGnF9xF" + + "VXOLk1J2WVFm9KUE23o6qdB7RGkf31pN2eA7SWmkdJSkUH7o/QSFBI+UTRZ/IY5P" + + "ZIJpsdiIOqd9YMG/4RoSZuPqNRR6x7BSs8nQVR9bYs4PPlp4GfdRnOcRonoTeJCZ" + + "83RnsraWJnJTg34gRLBcqumhTuFKc8nuCNK98D6zkQESdcHLLTquCOaF5L+5AQ0E" + + "QGsETwEIAOVwNCTaDZvW4dowPbET1bI5UeYY8rAGLYsWSUfgaFv2srMiApyBVltf" + + "i6OLcPjcUCHDBjCv4pwx/C4qcHWb8av4xQIpqQXOpO9NxYE1eZnel/QB7DtH12ZO" + + "nrDNmHtaXlulcKNGe1i1utlFhgzfFx6rWkRL0ENmkTkaQmPY4gTGymJTUhBbsSRq" + + "2ivWqQA1TPwBuda73UgslIAHRd/SUaxjXoLpMbGOTeqzcKGjr5XMPTs7/YgBpWPP" + + "UxMlEQIiU3ia1bxpEhx05k97ceK6TSH2oCPQA7gumjxOSjKT+jEm+8jACVzymEmc" + + "XRy4D5Ztqkw/Z16pvNcu1DI5m6xHwr8AEQEAAYkBIgQYAQIADAUCQGsETwUbDAAA" + + "AAAKCRDn3pbprojq2EynB/4/cEOtKbI5UisUd3vkTzvWOcqWUqGqi5wjjioNtIM5" + + "pur2nFvhQE7SZ+PbAa87HRJU/4WcWMcoLkHD48JrQwHCHOLHSV5muYowb78X4Yh9" + + "epYtSJ0uUahcn4Gp48p4BkhgsPYXkxEImSYzAOWStv21/7WEMqItMYl89BV6Upm8" + + "HyTJx5MPTDbMR7X51hRg3OeQs6po3WTCWRzFIMyGm1rd/VK1L5ZDFPqO3S6YUJ0z" + + "cxecYruvfK0Wp7q834wE8Zkl/PQ3NhfEPL1ZiLr/L00Ty+77/FZqt8SHRCICzOfP" + + "OawcVGI+xHVXW6lijMpB5VaVIH8i2KdBMHXHtduIkPr9"); + + byte[] sec5 = Base64.decode( + "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"); + + char[] sec5pass1 = "12345678".toCharArray(); + + // + // Werner Koch "odd keys" + // + byte[] pub6 = Base64.decode( + "mQGiBDWiHh4RBAD+l0rg5p9rW4M3sKvmeyzhs2mDxhRKDTVVUnTwpMIR2kIA9pT4" + + "3No/coPajDvhZTaDM/vSz25IZDZWJ7gEu86RpoEdtr/eK8GuDcgsWvFs5+YpCDwW" + + "G2dx39ME7DN+SRvEE1xUm4E9G2Nnd2UNtLgg82wgi/ZK4Ih9CYDyo0a9awCgisn3" + + "RvZ/MREJmQq1+SjJgDx+c2sEAOEnxGYisqIKcOTdPOTTie7o7x+nem2uac7uOW68" + + "N+wRWxhGPIxsOdueMIa7U94Wg/Ydn4f2WngJpBvKNaHYmW8j1Q5zvZXXpIWRXSvy" + + "TR641BceGHNdYiR/PiDBJsGQ3ac7n7pwhV4qex3IViRDJWz5Dzr88x+Oju63KtxY" + + "urUIBACi7d1rUlHr4ok7iBRlWHYXU2hpUIQ8C+UOE1XXT+HB7mZLSRONQnWMyXnq" + + "bAAW+EUUX2xpb54CevAg4eOilt0es8GZMmU6c0wdUsnMWWqOKHBFFlDIvyI27aZ9" + + "quf0yvby63kFCanQKc0QnqGXQKzuXbFqBYW2UQrYgjXji8rd8bQnV2VybmVyIEtv" + + "Y2ggKGdudXBnIHNpZykgPGRkOWpuQGdudS5vcmc+iGUEExECAB0FAjZVoKYFCQht" + + "DIgDCwQDBRUDAgYBAxYCAQIXgAASCRBot6uJV1SNzQdlR1BHAAEBLj4AoId15gcy" + + "YpBX2YLtEQTlXPp3mtEGAJ9UxzJE/t3EHCHK2bAIOkBwIW8ItIkBXwMFEDWiHkMD" + + "bxG4/z6qCxADYzIFHR6I9Si9gzPQNRcFs2znrTp5pV5Mk6f1aqRgZxL3E4qUZ3xe" + + "PQhwAo3fSy3kCwLmFGqvzautSMHn8K5V1u+T5CSHqLFYKqj5FGtuB/xwoKDXH6UO" + + "P0+l5IP8H1RTjme3Fhqahec+zPG3NT57vc2Ru2t6PmuAwry2BMuSFMBs7wzXkyC3" + + "DbI54MV+IKPjHMORivK8uI8jmna9hdNVyBifCk1GcxkHBSCFvU8xJePsA/Q//zCe" + + "lvrnrIiMfY4CQTmKzke9MSzbAZQIRddgrGAsiX1tE8Z3YMd8lDpuujHLVEdWZo6s" + + "54OJuynHrtFFObdapu0uIrT+dEXSASMUbEuNCLL3aCnrEtGJCwxB2TPQvCCvR2BK" + + "zol6MGWxA+nmddeQib2r+GXoKXLdnHcpsAjA7lkXk3IFyJ7MLFK6uDrjGbGJs2FK" + + "SduUjS/Ib4hGBBARAgAGBQI1oic8AAoJEGx+4bhiHMATftYAn1fOaKDUOt+dS38r" + + "B+CJ2Q+iElWJAKDRPpp8q5GylbM8DPlMpClWN3TYqYhGBBARAgAGBQI27U5sAAoJ" + + "EF3iSZZbA1iiarYAn35qU3ZOlVECELE/3V6q98Q30eAaAKCtO+lacH0Qq1E6v4BP" + + "/9y6MoLIhohiBBMRAgAiAhsDBAsHAwIDFQIDAxYCAQIeAQIXgAUCP+mCaQUJDDMj" + + "ywAKCRBot6uJV1SNzaLvAJwLsPV1yfc2D+yT+2W11H/ftNMDvwCbBweORhCb/O/E" + + "Okg2UTXJBR4ekoCIXQQTEQIAHQMLBAMFFQMCBgEDFgIBAheABQI/6YJzBQkMMyPL" + + "AAoJEGi3q4lXVI3NgroAn2Z+4KgVo2nzW72TgCJwkAP0cOc2AJ0ZMilsOWmxmEG6" + + "B4sHMLkB4ir4GIhdBBMRAgAdAwsEAwUVAwIGAQMWAgECF4AFAj/pgnMFCQwzI8sA" + + "CgkQaLeriVdUjc2CugCfRrOIfllp3mSmGpHgIxvg5V8vtMcAn0BvKVehOn+12Yvn" + + "9BCHfg34jUZbiF0EExECAB0DCwQDBRUDAgYBAxYCAQIXgAUCP+mCcwUJDDMjywAK" + + "CRBot6uJV1SNzYK6AJ9x7R+daNIjkieNW6lJeVUIoj1UHgCeLZm025uULML/5DFs" + + "4tUvXs8n9XiZAaIENaIg8xEEALYPe0XNsPjx+inTQ+Izz527ZJnoc6BhWik/4a2b" + + "ZYENSOQXAMKTDQMv2lLeI0i6ceB967MNubhHeVdNeOWYHFSM1UGRfhmZERISho3b" + + "p+wVZvVG8GBVwpw34PJjgYU/0tDwnJaJ8BzX6j0ecTSTjQPnaUEtdJ/u/gmG9j02" + + "18TzAKDihdNoKJEU9IKUiSjdGomSuem/VwQArHfaucSiDmY8+zyZbVLLnK6UJMqt" + + "sIv1LvAg20xwXoUk2bY8H3tXL4UZ8YcoSXYozwALq3cIo5UZJ0q9Of71mI8WLK2i" + + "FSYVplpTX0WMClAdkGt3HgVb7xtOhGt1mEKeRQjNZ2LteUQrRDD9MTQ+XxcvEN0I" + + "pAj4kBJe9bR6HzAD/iecCmGwSlHUZZrgqWzv78o79XxDdcuLdl4i2fL7kwEOf9js" + + "De7hGs27yrdJEmAG9QF9TOF9LJFmE1CqkgW+EpKxsY01Wjm0BFJB1R7iPUaUtFRZ" + + "xYqfgXarmPjql2iBi+cVjLzGu+4BSojVAPgP/hhcnIowf4M4edPiICMP1GVjtCFX" + + "ZXJuZXIgS29jaCA8d2VybmVyLmtvY2hAZ3V1Zy5kZT6IYwQTEQIAGwUCNs8JNwUJ" + + "CCCxRAMLCgMDFQMCAxYCAQIXgAASCRBsfuG4YhzAEwdlR1BHAAEBaSAAn3YkpT5h" + + "xgehGFfnX7izd+c8jI0SAJ9qJZ6jJvXnGB07p60aIPYxgJbLmYkAdQMFEDWjdxQd" + + "GfTBDJhXpQEBPfMC/0cxo+4xYVAplFO0nIYyjQgP7D8O0ufzPsIwF3kvb7b5FNNj" + + "fp+DAhN6G0HOIgkL3GsWtCfH5UHali+mtNFIKDpTtr+F/lPpZP3OPzzsLZS4hYTq" + + "mMs1O/ACq8axKgAilYkBXwMFEDWiJw4DbxG4/z6qCxADB9wFH0i6mmn6rWYKFepJ" + + "hXyhE4wWqRPJAnvfoiWUntDp4aIQys6lORigVXIWo4k4SK/FH59YnzF7578qrTZW" + + "/RcA0bIqJqzqaqsOdTYEFa49cCjvLnBW4OebJlLTUs/nnmU0FWKW8OwwL+pCu8d7" + + "fLSSnggBsrUQwbepuw0cJoctFPAz5T1nQJieQKVsHaCNwL2du0XefOgF5ujB1jK1" + + "q3p4UysF9hEcBR9ltE3THr+iv4jtZXmC1P4at9W5LFWsYuwr0U3yJcaKSKp0v/wG" + + "EWe2J/gFQZ0hB1+35RrCZPgiWsEv87CHaG6XtQ+3HhirBCJsYhmOikVKoEan6PhU" + + "VR1qlXEytpAt389TBnvyceAX8hcHOE3diuGvILEgYes3gw3s5ZmM7bUX3jm2BrX8" + + "WchexUFUQIuKW2cL379MFXR8TbxpVxrsRYE/4jHZBYhGBBARAgAGBQI27U4LAAoJ" + + "EF3iSZZbA1iifJoAoLEsGy16hV/CfmDku6D1CBUIxXvpAJ9GBApdC/3OXig7sBrV" + + "CWOb3MQzcLkBjQQ2zwcIEAYA9zWEKm5eZpMMBRsipL0IUeSKEyeKUjABX4vYNurl" + + "44+2h6Y8rHn7rG1l/PNj39UJXBkLFj1jk8Q32v+3BQDjvwv8U5e/kTgGlf7hH3WS" + + "W38RkZw18OXYCvnoWkYneIuDj6/HH2bVNXmTac05RkBUPUv4yhqlaFpkVcswKGuE" + + "NRxujv/UWvVF+/2P8uSQgkmGp/cbwfMTkC8JBVLLBRrJhl1uap2JjZuSVklUUBez" + + "Vf3NJMagVzx47HPqLVl4yr4bAAMGBf9PujlH5I5OUnvZpz+DXbV/WQVfV1tGRCra" + + "kIj3mpN6GnUDF1LAbe6vayUUJ+LxkM1SqQVcmuy/maHXJ+qrvNLlPqUZPmU5cINl" + + "sA7bCo1ljVUp54J1y8PZUx6HxfEl/LzLVkr+ITWnyqeiRikDecUf4kix2teTlx6I" + + "3ecqT5oNqZSRXWwnN4SbkXtAd7rSgEptUYhQXgSEarp1pXJ4J4rgqFa49jKISDJq" + + "rn/ElltHe5Fx1bpfkCIYlYk45Cga9bOIVAQYEQIADAUCNs8HCAUJBvPJAAASCRBs" + + "fuG4YhzAEwdlR1BHAAEBeRUAoIGpCDmMy195TatlloHAJEjZu5KaAJwOvW989hOb" + + "8cg924YIFVA1+4/Ia7kBjQQ1oiE8FAYAkQmAlOXixb8wra83rE1i7LCENLzlvBZW" + + "KBXN4ONelZAnnkOm7IqRjMhtKRJN75zqVyKUaUwDKjpf9J5K2t75mSxBtnbNRqL3" + + "XodjHK93OcAUkz3ci7iuC/b24JI2q4XeQG/v4YR1VodM0zEQ1IC0JCq4Pl39QZyX" + + "JdZCrUFvMcXq5ruNSldztBqTFFUiFbkw1Fug/ZyXJve2FVcbsRXFrB7EEuy+iiU/" + + "kZ/NViKk0L4T6KRHVsEiriNlCiibW19fAAMFBf9Tbv67KFMDrLqQan/0oSSodjDQ" + + "KDGqtoh7KQYIKPXqfqT8ced9yd5MLFwPKf3t7AWG1ucW2x118ANYkPSU122UTndP" + + "sax0cY4XkaHxaNwpNFCotGQ0URShxKNpcqbdfvy+1d8ppEavgOyxnV1JOkLjZJLw" + + "K8bgxFdbPWcsJJnjuuH3Pwz87CzTgOSYQxMPnIwQcx5buZIV5NeELJtcbbd3RVua" + + "K/GQht8QJpuXSji8Nl1FihYDjACR8TaRlAh50GmIRgQoEQIABgUCOCv7gwAKCRBs" + + "fuG4YhzAE9hTAJ9cRHu+7q2hkxpFfnok4mRisofCTgCgzoPjNIuYiiV6+wLB5o11" + + "7MNWPZCIVAQYEQIADAUCNaIhPAUJB4TOAAASCRBsfuG4YhzAEwdlR1BHAAEBDfUA" + + "oLstR8cg5QtHwSQ3nFCOKEREUFIwAKDID3K3hM+b6jW1o+tNX9dnjb+YMZkAbQIw" + + "bYOUAAABAwC7ltmO5vdKssohwzXEZeYvDW2ll3CYD2I+ruiNq0ybxkfFBopq9cxt" + + "a0OvVML4LK/TH+60f/Fqx9wg2yk9APXyaomdLrXfWyfZ91YtNCfj3ElC4XB4qqm0" + + "HRn0wQyYV6UABRG0IVdlcm5lciBLb2NoIDx3ZXJuZXIua29jaEBndXVnLmRlPokA" + + "lQMFEDRfoOmOB31Gi6BmjQEBzwgD/2fHcdDXuRRY+SHvIVESweijstB+2/sVRp+F" + + "CDjR74Kg576sJHfTJCxtSSmzpaVpelb5z4URGJ/Byi5L9AU7hC75S1ZnJ+MjBT6V" + + "ePyk/r0uBrMkU/lMG7lk/y2By3Hll+edjzJsdwn6aoNPiyen4Ch4UGTEguxYsLq0" + + "HES/UvojiQEVAwUTNECE2gnp+QqKck5FAQH+1Af/QMlYPlLG+5E19qP6AilKQUzN" + + "kd1TWMenXTS66hGIVwkLVQDi6RCimhnLMq/F7ENA8bSbyyMuncaBz5dH4kjfiDp1" + + "o64LULcTmN1LW9ctpTAIeLLJZnwxoJLkUbLUYKADKqIBXHMt2B0zRmhFOqEjRN+P" + + "hI7XCcHeHWHiDeUB58QKMyeoJ/QG/7zLwnNgDN2PVqq2E72C3ye5FOkYLcHfWKyB" + + "Rrn6BdUphAB0LxZujSGk8ohZFbia+zxpWdE8xSBhZbjVGlwLurmS2UTjjxByBNih" + + "eUD6IC3u5P6psld0OfqnpriZofP0CBP2oTk65r529f/1lsy2kfWrVPYIFJXEnIkA" + + "lQMFEDQyneGkWMS9SnJfMQEBMBMD/1ADuhhuY9kyN7Oj6DPrDt5SpPQDGS0Jtw3y" + + "uIPoed+xyzlrEuL2HeaOj1O9urpn8XLN7V21ajkzlqsxnGkOuifbE9UT67o2b2vC" + + "ldCcY4nV5n+U1snMDwNv+RkcEgNa8ANiWkm03UItd7/FpHDQP0FIgbPEPwRoBN87" + + "I4gaebfRiQCVAwUQNDUSwxRNm5Suj3z1AQGMTAP/UaXXMhPzcjjLxBW0AccTdHUt" + + "Li+K+rS5PNxxef2nnasEhCdK4GkM9nwJgsP0EZxCG3ZSAIlWIgQ3MK3ZAV1Au5pL" + + "KolRjFyEZF420wAtiE7V+4lw3FCqNoXDJEFC3BW431kx1wAhDk9VaIHHadYcof4d" + + "dmMLQOW2cJ7LDEEBW/WJAJUDBRA0M/VQImbGhU33abUBARcoA/9eerDBZGPCuGyE" + + "mQBcr24KPJHWv/EZIKl5DM/Ynz1YZZbzLcvEFww34mvY0jCfoVcCKIeFFBMKiSKr" + + "OMtoVC6cQMKpmhE9hYRStw4E0bcf0BD/stepdVtpwRnG8SDP2ZbmtgyjYT/7T4Yt" + + "6/0f6N/0NC7E9qfq4ZlpU3uCGGu/44kAlQMFEDQz8kp2sPVxuCQEdQEBc5YD/Rix" + + "vFcLTO1HznbblrO0WMzQc+R4qQ50CmCpWcFMwvVeQHo/bxoxGggNMmuVT0bqf7Mo" + + "lZDSJNS96IAN32uf25tYHgERnQaMhmi1aSHvRDh4jxFu8gGVgL6lWit/vBDW/BiF" + + "BCH6sZJJrGSuSdpecTtaWC8OJGDoKTO9PqAA/HQRiQB1AwUQNDJSx011eFs7VOAZ" + + "AQGdKQL/ea3qD2OP3wVTzXvfjQL1CosX4wyKusBBhdt9u2vOT+KWkiRk1o35nIOG" + + "uZLHtSFQDY8CVDOkqg6g4sVbOcTl8QUwHA+A4AVDInwTm1m4Bk4oeCIwk4Bp6mDd" + + "W11g28k/iQEVAgUSNDIWPm/Y4wPDeaMxAQGvBQgAqGhzA/21K7oL/L5S5Xz//eO7" + + "J8hgvqqGXWd13drNy3bHbKPn7TxilkA3ca24st+6YPZDdSUHLMCqg16YOMyQF8gE" + + "kX7ZHWPacVoUpCmSz1uQ3p6W3+u5UCkRpgQN8wBbJx5ZpBBqeq5q/31okaoNjzA2" + + "ghEWyR5Ll+U0C87MY7pc7PlNHGCr0ZNOhhtf1jU+H9ag5UyT6exIYim3QqWYruiC" + + "LSUcim0l3wK7LMW1w/7Q6cWfAFQvl3rGjt3rg6OWg9J4H2h5ukf5JNiRybkupmat" + + "UM+OVMRkf93jzU62kbyZpJBHiQZuxxJaLkhpv2RgWib9pbkftwEy/ZnmjkxlIIkA" + + "lQMFEDQvWjh4313xYR8/NQEB37QEAIi9vR9h9ennz8Vi7RNU413h1ZoZjxfEbOpk" + + "QAjE/LrZ/L5WiWdoStSiyqCLPoyPpQafiU8nTOr1KmY4RgceJNgxIW4OiSMoSvrh" + + "c2kqP+skb8A2B4+47Aqjr5fSAVfVfrDMqDGireOguhQ/hf9BOYsM0gs+ROdtyLWP" + + "tMjRnFlviD8DBRAz8qQSj6lRT5YOKXIRAntSAJ9StSEMBoFvk8iRWpXb6+LDNLUW" + + "zACfT8iY3IxwvMF6jjCHrbuxQkL7chSJARUDBRA0MMO7569NIyeqD3EBATIAB/4t" + + "CPZ1sLWO07g2ZCpiP1HlYpf5PENaXtaasFvhWch7eUe3DksuMEPzB5GnauoQZAku" + + "hEGkoEfrfL3AXtXH+WMm2t7dIcTBD4p3XkeZ+PgJpKiASXDyul9rumXXvMxSL4KV" + + "7ar+F1ZJ0ycCx2r2au0prPao70hDAzLTy16hrWgvdHSK7+wwaYO5TPCL5JDmcB+d" + + "HKW72qNUOD0pxbe0uCkkb+gDxeVX28pZEkIIOMMV/eAs5bs/smV+eJqWT/EyfVBD" + + "o7heF2aeyJj5ecxNOODr88xKF7qEpqazCQ4xhvFY+Yn6+vNCcYfkoZbOn0XQAvqf" + + "a2Vab9woVIVSaDji/mlPiQB1AwUQNDC233FfeD4HYGBJAQFh6QL/XCgm5O3q9kWp" + + "gts1MHKoHoh7vxSSQGSP2k7flNP1UB2nv4sKvyGM8eJKApuROIodcTkccM4qXaBu" + + "XunMr5kJlvDJPm+NLzKyhtQP2fWI7xGYwiCiB29gm1GFMjdur4amiQEVAwUQNDBR" + + "9fjDdqGixRdJAQE+mAf+JyqJZEVFwNwZ2hSIMewekC1r7N97p924nqfZKnzn6weF" + + "pE80KIJSWtEVzI0XvHlVCOnS+WRxn7zxwrOTbrcEOy0goVbNgUsP5ypZa2/EM546" + + "uyyJTvgD0nwA45Q4bP5sGhjh0G63r9Vwov7itFe4RDBGM8ibGnZTr9hHo469jpom" + + "HSNeavcaUYyEqcr4GbpQmdpJTnn/H0A+fMl7ZHRoaclNx9ZksxihuCRrkQvUOb3u" + + "RD9lFIhCvNwEardN62dKOKJXmn1TOtyanZvnmWigU5AmGuk6FpsClm3p5vvlid64" + + "i49fZt9vW5krs2XfUevR4oL0IyUl+qW2HN0DIlDiAYkAlQMFEDQvbv2wcgJwUPMh" + + "JQEBVBID/iOtS8CQfMxtG0EmrfaeVUU8R/pegBmVWDBULAp8CLTtdfxjVzs/6DXw" + + "0RogXMRRl2aFfu1Yp0xhBYjII6Kque/FzAFXY9VNF1peqnPt7ADdeptYMppZa8sG" + + "n9BBRu9Fsw69z6JkyqvMiVxGcKy3XEpVGr0JHx8Xt6BYdrULiKr2iQB1AwUQNC68" + + "n6jZR/ntlUftAQFaYgL+NUYEj/sX9M5xq1ORX0SsVPMpNamHO3JBSmZSIzjiox5M" + + "AqoFOCigAkonuzk5aBy/bRHy1cmDBOxf4mNhzrH8N6IkGvPE70cimDnbFvr+hoZS" + + "jIqxtELNZsLuLVavLPAXiQCVAwUQNC6vWocCuHlnLQXBAQHb1gQAugp62aVzDCuz" + + "4ntfXsmlGbLY7o5oZXYIKdPP4riOj4imcJh6cSgYFL6OMzeIp9VW/PHo2mk8kkdk" + + "z5uif5LqOkEuIxgra7p1Yq/LL4YVhWGQeD8hwpmu+ulYoPOw40dVYS36PwrHIH9a" + + "fNhl8Or5O2VIHIWnoQ++9r6gwngFQOyJAJUDBRAzHnkh1sNKtX1rroUBAWphBACd" + + "huqm7GHoiXptQ/Y5F6BivCjxr9ch+gPSjaLMhq0kBHVO+TbXyVefVVGVgCYvFPjo" + + "zM8PEVykQAtY//eJ475aGXjF+BOAhl2z0IMkQKCJMExoEDHbcj0jIIMZ2/+ptgtb" + + "FSyJ2DQ3vvCdbw/1kyPHTPfP+L2u40GWMIYVBbyouokAlQMFEDMe7+UZsymln7HG" + + "2QEBzMED/3L0DyPK/u6PyAd1AdpjUODTkWTZjZ6XA2ubc6IXXsZWpmCgB/24v8js" + + "J3DIsvUD3Ke55kTr6xV+au+mAkwOQqWUTUWfQCkSrSDlbUJ1VPBzhyTpuzjBopte" + + "7o3R6XXfcLiC5jY6eCX0QtLGhKpLjTr5uRhf1fYODGsAGXmCByDviQB1AgUQMy6U" + + "MB0Z9MEMmFelAQHV4AMAjdFUIyFtpTr5jkyZSd3y//0JGO0z9U9hLVxeBBCwvdEQ" + + "xsrpeTtVdqpeKZxHN1GhPCYvgLFZAQlcPh/Gc8u9uO7wVSgJc3zYKFThKpQevdF/" + + "rzjTCHfgigf5Iui0qiqBiQCVAwUQMx22bAtzgG/ED06dAQFi0gQAkosqTMWy+1eU" + + "Xbi2azFK3RX5ERf9wlN7mqh7TvwcPXvVWzUARnwRv+4kk3uOWI18q5UPis7KH3KY" + + "OVeRrPd8bbp6SjhBh82ourTEQUXLBDQiI1V1cZZmwwEdlnAnhFnkXgMBNM2q7oBe" + + "fRHADfYDfGo90wXyrVVL+GihDNpzUwOJAJUDBRAzHUFnOWvfULwOR3EBAbOYA/90" + + "JIrKmxhwP6quaheFOjjPoxDGEZpGJEOwejEByYj+AgONCRmQS3BydtubA+nm/32D" + + "FeG8pe/dnFvGc+QgNW560hK21C2KJj72mhjRlg/na7jz4/MmBAv5k61Q7roWi0rw" + + "x+R9NSHxpshC8A92zmvo8w/XzVSogC8pJ04jcnY6YokAlQMFEDMdPtta9LwlvuSC" + + "3QEBvPMD/3TJGroHhHYjHhiEpDZZVszeRQ0cvVI/uLLi5yq3W4F6Jy47DF8VckA7" + + "mw0bXrOMNACN7Je7uyaU85qvJC2wgoQpFGdFlkjmkAwDAjR+koEysiE8FomiOHhv" + + "EpEY/SjSS4jj4IPmgV8Vq66XjPw+i7Z0RsPLOIf67yZHxypNiBiYiQCVAwUQMxxw" + + "pKrq6G7/78D5AQHo2QQAjnp6KxOl6Vvv5rLQ/4rj3OemvF7IUUq34xb25i/BSvGB" + + "UpDQVUmhv/qIfWvDqWGZedyM+AlNSfUWPWnP41S8OH+lcERH2g2dGKGl7kH1F2Bx" + + "ByZlqREHm2q624wPPA35RLXtXIx06yYjLtJ7b+FCAX6PUgZktZYk5gwjdoAGrC2J" + + "AJUDBRAzGvcCKC6c7f53PGUBAUozA/9l/qKmcqbi8RtLsKQSh3vHds9d22zcbkuJ" + + "PBSoOv2D7i2VLshaQFjq+62uYZGE6nU1WP5sZcBDuWjoX4t4NrffnOG/1R9D0t1t" + + "9F47D77HJzjvo+J52SN520YHcbT8VoHdPRoEOXPN4tzhvn2GapVVdaAlWM0MLloh" + + "NH3I9jap9okAdQMFEDMZlUAnyXglSykrxQEBnuwC/jXbFL+jzs2HQCuo4gyVrPlU" + + "ksQCLYZjNnZtw1ca697GV3NhBhSXR9WHLQH+ZWnpTzg2iL3WYSdi9tbPs78iY1FS" + + "d4EG8H9V700oQG8dlICF5W2VjzR7fByNosKM70WSXYkBFQMFEDMWBsGCy1t9eckW" + + "HQEBHzMH/jmrsHwSPrA5R055VCTuDzdS0AJ+tuWkqIyqQQpqbost89Hxper3MmjL" + + "Jas/VJv8EheuU3vQ9a8sG2SnlWKLtzFqpk7TCkyq/H3blub0agREbNnYhHHTGQFC" + + "YJb4lWjWvMjfP+N5jvlLcnDqQPloXfAOgy7W90POoqFrsvhxdpnXgoLrzyNNja1O" + + "1NRj+Cdv/GmJYNi6sQe43zmXWeA7syLKMw6058joDqEJFKndgSp3Zy/yXmObOZ/H" + + "C2OJwA3gzEaAu8Pqd1svwGIGznqtTNCn9k1+rMvJPaxglg7PXIJS282hmBl9AcJl" + + "wmh2GUCswl9/sj+REWTb8SgJUbkFcp6JAJUDBRAwdboVMPfsgxioXMEBAQ/LA/9B" + + "FTZ9T95P/TtsxeC7lm9imk2mpNQCBEvXk286FQnGFtDodGfBfcH5SeKHaUNxFaXr" + + "39rDGUtoTE98iAX3qgCElf4V2rzgoHLpuQzCg3U35dfs1rIxlpcSDk5ivaHpPV3S" + + "v+mlqWL049y+3bGaZeAnwM6kvGMP2uccS9U6cbhpw4hGBBARAgAGBQI3GtRfAAoJ" + + "EF3iSZZbA1iikWUAoIpSuXzuN/CI63dZtT7RL7c/KtWUAJ929SAtTr9SlpSgxMC8" + + "Vk1T1i5/SYkBFQMFEzccnFnSJilEzmrGwQEBJxwH/2oauG+JlUC3zBUsoWhRQwqo" + + "7DdqaPl7sH5oCGDKS4x4CRA23U15NicDI7ox6EizkwCjk0dRr1EeRK+RqL1b/2T4" + + "2B6nynOLhRG2A0BPHRRJLcoL4nKfoPSo/6dIC+3iVliGEl90KZZD5bnONrVJQkRj" + + "ZL8Ao+9IpmoYh8XjS5xMLEF9oAQqAkA93nVBm56lKmaL1kl+M3dJFtNKtVB8de1Z" + + "XifDs8HykD42qYVtcseCKxZXhC3UTG5YLNhPvgZKH8WBCr3zcR13hFDxuecUmu0M" + + "VhvEzoKyBYYt0rrqnyWrxwbv4gSTUWH5ZbgsTjc1SYKZxz6hrPQnfYWzNkznlFWJ" + + "ARUDBRM0xL43CdxwOTnzf10BATOCB/0Q6WrpzwPMofjHj54MiGLKVP++Yfwzdvns" + + "HxVpTZLZ5Ux8ErDsnLmvUGphnLVELZwEkEGRjln7a19h9oL8UYZaV+IcR6tQ06Fb" + + "1ldR+q+3nXtBYzGhleXdgJQSKLJkzPF72tvY0DHUB//GUV9IBLQMvfG8If/AFsih" + + "4iXi96DOtUAbeuIhnMlWwLJFeGjLLsX1u6HSX33xy4bGX6v/UcHbTSSYaxzb92GR" + + "/xpP2Xt332hOFRkDZL52g27HS0UrEJWdAVZbh25KbZEl7C6zX/82OZ5nTEziHo20" + + "eOS6Nrt2+gLSeA9X5h/+qUx30kTPz2LUPBQyIqLCJkHM8+0q5j9ciQCiAwUTNMS+" + + "HZFeTizbCJMJAQFrGgRlEAkG1FYU4ufTxsaxhFZy7xv18527Yxpls6mSCi1HL55n" + + "Joce6TI+Z34MrLOaiZljeQP3EUgzA+cs1sFRago4qz2wS8McmQ9w0FNQQMz4vVg9" + + "CVi1JUVd4EWYvJpA8swDd5b9+AodYFEsfxt9Z3aP+AcWFb10RlVVsNw9EhObc6IM" + + "nwAOHCEI9vp5FzzFiQCVAwUQNxyr6UyjTSyISdw9AQHf+wP+K+q6hIQ09tkgaYaD" + + "LlWKLbuxePXqM4oO72qi70Gkg0PV5nU4l368R6W5xgR8ZkxlQlg85sJ0bL6wW/Sj" + + "Mz7pP9hkhNwk0x3IFkGMTYG8i6Gt8Nm7x70dzJoiC+A496PryYC0rvGVf+Om8j5u" + + "TexBBjb/jpJhAQ/SGqeDeCHheOC0Lldlcm5lciBLb2NoIChtZWluIGFsdGVyIGtl" + + "eSkgPHdrQGNvbXB1dGVyLm9yZz6JAHUDBRM2G2MyHRn0wQyYV6UBASKKAv4wzmK7" + + "a9Z+g0KH+6W8ffIhzrQo8wDAU9X1WJKzJjS205tx4mmdnAt58yReBc/+5HXTI8IK" + + "R8IgF+LVXKWAGv5P5AqGhnPMeQSCs1JYdf9MPvbe34jD8wA1LTWFXn9e/cWIRgQQ" + + "EQIABgUCNxrUaQAKCRBd4kmWWwNYovRiAJ9dJBVfjx9lGARoFXmAieYrMGDrmwCZ" + + "AQyO4Wo0ntQ+iq4do9M3/FTFjiCZAaIENu1I6REEAJRGEqcYgXJch5frUYBj2EkD" + + "kWAbhRqVXnmiF3PjCEGAPMMYsTddiU7wcKfiCAqKWWXow7BjTJl6Do8RT1jdKpPO" + + "lBJXqqPYzsyBxLzE6mLps0K7SLJlSKTQqSVRcx0jx78JWYGlAlP0Kh9sPV2w/rPh" + + "0LrPeOKXT7lZt/DrIhfPAKDL/sVqCrmY3QfvrT8kSKJcgtLWfQP/cfbqVNrGjW8a" + + "m631N3UVA3tWfpgM/T9OjmKmw44NE5XfPJTAXlCV5j7zNMUkDeoPkrFF8DvbpYQs" + + "4XWYHozDjhR2Q+eI6gZ0wfmhLHqqc2eVVkEG7dT57Wp9DAtCMe7RZfhnarTQMqlY" + + "tOEa/suiHk0qLo59NsyF8eh68IDNCeYD/Apzonwaq2EQ1OEpfFlp6LcSnS34+UGZ" + + "tTO4BgJdmEjr/QrIPp6bJDstgho+/2oR8yQwuHGJwbS/8ADA4IFEpLduSpzrABho" + + "7RuNQcm96bceRY+7Hza3zf7pg/JGdWOb+bC3S4TIpK+3sx3YNWs7eURwpGREeJi5" + + "/Seic+GXlGzltBpXZXJuZXIgS29jaCA8d2tAZ251cGcub3JnPohjBBMRAgAbBQI3" + + "Gs+QBQkMyXyAAwsKAwMVAwIDFgIBAheAABIJEF3iSZZbA1iiB2VHUEcAAQFdwgCe" + + "O/s43kCLDMIsHCb2H3LC59clC5UAn1EyrqWk+qcOXLpQIrP6Qa3QSmXIiEYEEBEC" + + "AAYFAjca0T0ACgkQbH7huGIcwBOF9ACeNwO8G2G0ei03z0g/n3QZIpjbzvEAnRaE" + + "qX2PuBbClWoIP6h9yrRlAEbUiQB1AwUQNxrRYx0Z9MEMmFelAQHRrgL/QDNKPV5J" + + "gWziyzbHvEKfTIw/Ewv6El2MadVvQI8kbPN4qkPr2mZWwPzuc9rneCPQ1eL8AOdC" + + "8+ZyxWzx2vsrk/FcU5donMObva2ct4kqJN6xl8xjsxDTJhBSFRaiBJjxiEYEEBEC" + + "AAYFAjca0aMACgkQaLeriVdUjc0t+ACghK37H2vTYeXXieNJ8aZkiPJSte4An0WH" + + "FOotQdTW4NmZJK+Uqk5wbWlgiEYEEBECAAYFAjdPH10ACgkQ9u7fIBhLxNktvgCe" + + "LnQ5eOxAJz+Cvkb7FnL/Ko6qc5YAnjhWWW5c1o3onvKEH2Je2wQa8T6iiEYEEBEC" + + "AAYFAjenJv4ACgkQmDRl2yFDlCJ+yQCfSy1zLftEfLuIHZsUHis9U0MlqLMAn2EI" + + "f7TI1M5OKysQcuFLRC58CfcfiEUEEBECAAYFAjfhQTMACgkQNmdg8X0u14h55wCf" + + "d5OZCV3L8Ahi4QW/JoXUU+ZB0M0AmPe2uw7WYDLOzv48H76tm6cy956IRgQQEQIA" + + "BgUCOCpiDwAKCRDj8lhUEo8OeRsdAJ9FHupRibBPG2t/4XDqF+xiMLL/8ACfV5F2" + + "SR0ITE4k/C+scS1nJ1KZUDW0C1dlcm5lciBLb2NoiGMEExECABsFAjbtSOoFCQzJ" + + "fIADCwoDAxUDAgMWAgECF4AAEgkQXeJJllsDWKIHZUdQRwABAbXWAJ9SCW0ieOpL" + + "7AY6vF+OIaMmw2ZW1gCgkto0eWfgpjAuVg6jXqR1wHt2pQOJAh4EEBQDAAYFAjcv" + + "WdQACgkQbEwxpbHVFWcNxQf/bg14WGJ0GWMNSuuOOR0WYzUaNtzYpiLSVyLrreXt" + + "o8LBNwzbgzj2ramW7Ri+tYJAHLhtua8ZgSeibmgBuZasF8db1m5NN1ZcHBXGTysA" + + "jp+KnicTZ9Orj75D9o3oSmMyRcisEhr+gkj0tVhGfOAOC6eKbufVuyYFDVIyOyUB" + + "GlW7ApemzAzYemfs3DdjHn87lkjHMVESO4fM5rtLuSc7cBfL/e6ljaWQc5W8S0gI" + + "Dv0VtL39pMW4BlpKa25r14oJywuUpvWCZusvDm7ZJnqZ/WmgOHQUsyYudTROpGIb" + + "lsNg8iqC6huWpGSBRdu3oRQRhkqpfVdszz6BB/nAx01q2wf/Q+U9XId1jyzxUL1S" + + "GgaYMf6QdyjHQ1oxuFLNxzM6C/M069twbNgXJ71RsDDXVxFZfSTjSiH100AP9+9h" + + "b5mycaXLUOXYDvOSFzHBd/LsjFNVrrFbDs5Xw+cLGVHOIgR5IWAfgu5d1PAZU9uQ" + + "VgdGnQfmZg383RSPxvR3fnZz1rHNUGmS6w7x6FVbxa1QU2t38gNacIwHATAPcBpy" + + "JLfXoznbpg3ADbgCGyDjBwnuPQEQkYwRakbczRrge8IaPZbt2HYPoUsduXMZyJI8" + + "z5tvu7pUDws51nV1EX15BcN3++aY5pUyA1ItaaDymQVmoFbQC0BNMzMO53dMnFko" + + "4i42kohGBBARAgAGBQI3OvmjAAoJEHUPZJXInZM+hosAnRntCkj/70shGTPxgpUF" + + "74zA+EbzAKCcMkyHXIz2W0Isw3gDt27Z9ggsE4hGBBARAgAGBQI3NyPFAAoJEPbu" + + "3yAYS8TZh2UAoJVmzw85yHJzsXQ1vpO2IAPfv59NAJ9WY0oiYqb3q1MSxBRwG0gV" + + "iNCJ7YkBFQMFEDdD3tNSgFdEdlNAHQEByHEH/2JMfg71GgiyGJTKxCAymdyf2j2y" + + "fH6wI782JK4BWV4c0E/V38q+jpIYslihV9t8s8w1XK5niMaLwlCOyBWOkDP3ech6" + + "+GPPtfB3cmlL2hS896PWZ1adQHgCeQpB837n56yj0aTs4L1xarbSVT22lUwMiU6P" + + "wYdH2Rh8nh8FvN0IZsbln2nOj73qANQzNflmseUKF1Xh4ck8yLrRd4r6amhxAVAf" + + "cYFRJN4zdLL3cmhgkt0ADZlzAwXnEjwdHHy7SvAJk1ecNOA9pFsOJbvnzufd1afs" + + "/CbG78I+0JDhg75Z2Nwq8eKjsKqiO0zz/vG5yWSndZvWkTWz3D3b1xr1Id2IRgQQ" + + "EQIABgUCOCpiHgAKCRDj8lhUEo8OeQ+QAKCbOTscyUnWHSrDo4fIy0MThEjhOgCe" + + "L4Kb7TWkd/OHQScVBO8sTUz0+2g="); + + byte[] pub6check = Base64.decode("62O9"); + + // + // revoked sub key + // + byte[] pub7 = Base64.decode( + "mQGiBFKQDEMRBACtcEzu15gGDrZKLuO2zgDJ9qFkweOxKyeO45LKIfUGBful" + + "lheoFHbsJIeNGjWbSOfWWtphTaSu9//BJt4xxg2pqVLYqzR+hEPpDy9kXxnZ" + + "LwwxjAP2TcOvuZKWe+JzoYQxDunOH4Zu9CPJhZhF3RNPw+tbv0jHfTV/chtb" + + "23Dj5wCg7eoM8bL9NYXacsAfkS//m+AB1MkD/jEZJqJSQHW8WVP7wKRrAZse" + + "N4l9b8+yY4RwLIodhD8wGsMYjkCF4yb/SQ5QlmLlvrHDLBofRzG+8oxldX4o" + + "GLZWvqPmW+BlS4QNSr+ZBu+OwnpClXG2pR+ExumXNoeArREyylrmOgD+0cUa" + + "8K2UbOxbJ8EioyOKxa7wjUVxmHmhBACAGQGLT/lpHA5zcU0g8AlSk8fsd+bB" + + "nwa/+9xdLqVsCTZdOWULtPOw9hbAdjjAy0L4M/MDAJYYtCEl9rB7aOc9PVdT" + + "h7CT9Ma6ltiSMKDlqWbDmogNEGx9Gz3GjiSGxAy/SN6JR1On4c60TAiTv6eE" + + "uEHszE6CH4qceK5W8HLLB7QncmV2b2tlIChSZXZva2UgVGVzdCkgPHJldm9r" + + "ZUB0ZXN0LnRlc3Q+iGIEExECACIFAlKQDEMCGwMGCwkIBwMCBhUIAgkKCwQW" + + "AgMBAh4BAheAAAoJEBCIvJhXZzdIrDQAn2S5/G+eitU6/pr5Yz4j9s0/6aMt" + + "AKC08q7BPJ5lTaRJ5zV8llSywMvWEbACAAO5AQ0EUpAMQxAEAKu4nnga6FRp" + + "eCobO78ewKuAZACfzo9lbWo8JfbwT2xrISZU6DNIMD85PlzTk/Q9UuEw0SC5" + + "KdQYLbj0yll88r/0tUoxcBNkvMQHqUVfVgl1+utv0qtDmR0OE5wVebUYgYHA" + + "vONSZdhFU8f5OxPhAW8Ol8gA1Bl8orhRXkEnMlXnAAMFA/97Dvl3LXHnwpak" + + "+p94fU5WWf9SLp4QPLIhKJzXjv4Uh9UO4u1ajEwUTRk+Djv6sRCuFYL3qLNp" + + "Io9b3vLluRbPk8YIwKGctyD7cz3XH9AIbM2HNUyJWljlWEEMU/7uKI5ophGI" + + "3/Huhqx/bjzY3LzWiLKQ5lSbwUJRCdGYnMiVuIhJBBgRAgAJBQJSkAxDAhsM" + + "AAoJEBCIvJhXZzdIvTgAn1Vx4PUO1wQNpY8PMU+Cl7dl+JeJAJ97lrNiXbom" + + "kdIm80plEuLQjweyELACAAM="); + + byte[] pub7revoke = Base64.decode("iEkEIBECAAkFAlKQDQ4CHQIACgkQEIi8mFdnN0hfzACfSpQ/+OoC48Rf2DZcKvmM" + + "3dEq8qMAoOnHg0/s/X/Is3bJwUiDEpnWmUoI"); + + byte[] pub8 = Base64.decode( + "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" + + "9Uqz3fUvGoewAWA="); + + byte[] sec8 = Base64.decode( + "lQHpBEEcraYRBADFYj+uFOhHz5SdECvJ3Z03P47gzmWLQ5HH8fPYC9rrv7AgqFFX" + + "aWlJJVMLua9e6xoCiDWJs/n4BbZ/weL/11ELg6XqUnzFhYyz0H2KFsPgQ/b9lWLY" + + "MtcPMFy5jE33hv/ixHgYLFqoNaAIbg0lzYEW/otQ9IhRl16fO1Q/CQZZrQCg/9M2" + + "V2BTmm9RYog86CXJtjawRBcD/RIqU0zulxZ2Zt4javKVxrGIwW3iBU935ebmJEIK" + + "Y5EVkGKBOCvsApZ+RGzpYeR2uMsTnQi8RJgiAnjaoVPCdsVJE7uQ0h8XuJ5n5mJ2" + + "kLCFlF2hj5ViicZzse+crC12CGtgRe8z23ubLRcd6IUGhVutK8/b5knZ22vE14JD" + + "ykKdA/96ObzJQdiuuPsEWN799nUUCaYWPAoLAmiXuICSP4GEnxLbYHWo8zhMrVMT" + + "9Q5x3h8cszUz7Acu2BXjP1m96msUNoxPOZtt88NlaFz1Q/JSbQTsVOMd9b/IRN6S" + + "A/uU0BiKEMHXuT8HUHVPK49oCKhZrGFP3RT8HZxDKLmR/qrgZ/4JAwLXyWhb4pf4" + + "nmCmD0lDwoYvatLiR7UQVM2MamxClIiT0lCPN9C2AYIFgRWAJNS215Tjx7P/dh7e" + + "8sYfh5XEHErT3dMbsAGHtCFKaWEgWWl5dSA8eXlqaWFAbm93bWVkaWF0ZWNoLmNv" + + "bT6wAwP//4kAXQQQEQIAHQUCQRytpgcLCQgHAwIKAhkBBRsDAAAABR4BAAAAAAoJ" + + "EPT+Vvgr/2IUmWEAoJEyJ9B7CJfmjwVTT30UbdCctVRmAJ9akw6we6UYd82vF0FK" + + "QTlSuqHXKbABZ50CawRBHK2mEAgA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlL" + + "OCDaAadWoxTpj0BV89AHxstDqZSt90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N" + + "286Z4VeSWc39uK50T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq01uejaClcjrUGvC/" + + "RgBYK+X0iP1YTknbzSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2O" + + "u1WMuF040zT9fBdXQ6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqV" + + "DNmWn6vQClCbAkbTCD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwACAgf/crbApFLO" + + "QikN9lHbn62dDxuu/dNigNmjf/A3cX+vo8aPHTXnRDyDwQALRuqbitdbM6p1LFjG" + + "8g84Aabk/jL7zzjJLqPe8pxeK1Pu+P44NzalXAYMsOOsxGuixIrz3Jw8IrpH/mkP" + + "tG/iX0NaLZ+Au9eokdLb+6NR/a51r2qL3E0ycFciJ61HzZKKHi6d0VQ7CHozCz+j" + + "d5530Mh1qq/ZjYDDjfP+snpyNIZXcLtGR/3HzkBqNgDcvClLx3322AWKDa7pX8DX" + + "qiLr8znWhPRpH9kCTnSpRzhYGT25FRcvdj4/q/oUIET/Tp+BWW3BxAc7WgpgqEfn" + + "fa0Mv72Zbn91gf4JAwITijME9IlFBGAwH6YmBtWIlnDiRbsq/Pxozuhbnes831il" + + "KmdpUKXkiIfHY0MqrEWl3Dfn6PMJGTnhgqXMrDxx3uHrq0Jl2swRnAWIIO8gID7j" + + "uPetUqEviPiwAYeJAEwEGBECAAwFAkEcraYFGwwAAAAACgkQ9P5W+Cv/YhShrgCg" + + "+JW8m5nF3R/oZGuG87bXQBszkjMAoLhGPncuGKowJXMRVc70/8qwXQJLsAFn"); + + char[] sec8pass = "qwertyui".toCharArray(); + + byte[] sec9 = Base64.decode( + "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" + + "6neEEX/i1Q=="); + + public char[] sec9pass = "foo".toCharArray(); + + // version 4 keys with expiry dates + byte[] pub10 = Base64.decode( + "mQGiBEKqia0RBACc3hkufmscRSC4UvPZqMDsHm4+d/GXIr+3iNMSSEySJu8yk+k0" + + "Xs11C/K+n+v1rnn2jGGknv+1lDY6w75TIcTE6o6HGKeIDxsAm8P3MhoGU1GNPamA" + + "eTDeNybtrN/g6C65fCY9uI11hsUboYgQZ8ND22PB0VtvdOgq9D85qNUzxwCg1BbJ" + + "ycAKd4VqEvQ2Zglp3dCSrFMD/Ambq1kZqYa69sp3b9BPKuAgUgUPoytOArEej3Bk" + + "easAgAxNhWJy4GxigES3vk50rVi7w8XBuqbD1mQCzldF0HX0/A7PxLBv6od5uqqF" + + "HFxIyxg/KBZLd9ZOrsSaoUWH58jZq98X/sFtJtRi5VuJagMxCIJD4mLgtMv7Unlb" + + "/GrsA/9DEnObA/fNTgK70T+ZmPIS5tSt+bio30Aw4YGpPCGqpnm1u73b5kqX3U3B" + + "P+vGDvFuqZYpqQA8byAueH0MbaDHI4CFugvShXvgysJxN7ov7/8qsZZUMfK1t2Nr" + + "SAsPuKRbcY4gNKXIElKeXbyaET7vX7uAEKuxEwdYGFp/lNTkHLQgdGVzdCBrZXkg" + + "KHRlc3QpIDx0ZXN0QHRlc3QudGVzdD6IZAQTEQIAJAUCQqqJrQIbAwUJACTqAAYL" + + "CQgHAwIDFQIDAxYCAQIeAQIXgAAKCRDjDROQZRqIzDzLAJ42AeCRIBBjv8r8qw9y" + + "laNj2GZ1sACgiWYHVXMA6B1H9I1kS3YsCd3Oq7qwAgAAuM0EQqqJrhADAKWkix8l" + + "pJN7MMTXob4xFF1TvGll0UD1bDGOMMbes6aeXSbT9QXee/fH3GnijLY7wB+qTPv9" + + "ohubrSpnv3yen3CEBW6Q2YK+NlCskma42Py8YMV2idmYjtJi1ckvHFWt5wADBQL/" + + "fkB5Q5xSGgspMaTZmtmX3zG7ZDeZ0avP8e8mRL8UszCTpqs6vMZrXwyQLZPbtMYv" + + "PQpuRGEeKj0ysimwYRA5rrLQjnRER3nyuuEUUgc4j+aeRxPf9WVsJ/a1FCHtaAP1" + + "iE8EGBECAA8FAkKqia4CGwwFCQAk6gAACgkQ4w0TkGUaiMzdqgCfd66H7DL7kFGd" + + "IoS+NIp8JO+noxAAn25si4QAF7og8+4T5YQUuhIhx/NesAIAAA=="); + + byte[] sec10 = Base64.decode( + "lQHhBEKqia0RBACc3hkufmscRSC4UvPZqMDsHm4+d/GXIr+3iNMSSEySJu8yk+k0" + + "Xs11C/K+n+v1rnn2jGGknv+1lDY6w75TIcTE6o6HGKeIDxsAm8P3MhoGU1GNPamA" + + "eTDeNybtrN/g6C65fCY9uI11hsUboYgQZ8ND22PB0VtvdOgq9D85qNUzxwCg1BbJ" + + "ycAKd4VqEvQ2Zglp3dCSrFMD/Ambq1kZqYa69sp3b9BPKuAgUgUPoytOArEej3Bk" + + "easAgAxNhWJy4GxigES3vk50rVi7w8XBuqbD1mQCzldF0HX0/A7PxLBv6od5uqqF" + + "HFxIyxg/KBZLd9ZOrsSaoUWH58jZq98X/sFtJtRi5VuJagMxCIJD4mLgtMv7Unlb" + + "/GrsA/9DEnObA/fNTgK70T+ZmPIS5tSt+bio30Aw4YGpPCGqpnm1u73b5kqX3U3B" + + "P+vGDvFuqZYpqQA8byAueH0MbaDHI4CFugvShXvgysJxN7ov7/8qsZZUMfK1t2Nr" + + "SAsPuKRbcY4gNKXIElKeXbyaET7vX7uAEKuxEwdYGFp/lNTkHP4DAwLssmOjVC+d" + + "mWB783Lpzjb9evKzsxisTdx8/jHpUSS+r//6/Guyx3aA/zUw5bbftItW57mhuNNb" + + "JTu7WrQgdGVzdCBrZXkgKHRlc3QpIDx0ZXN0QHRlc3QudGVzdD6IZAQTEQIAJAUC" + + "QqqJrQIbAwUJACTqAAYLCQgHAwIDFQIDAxYCAQIeAQIXgAAKCRDjDROQZRqIzDzL" + + "AJ0cYPwKeoSReY14LqJtAjnkX7URHACgsRZWfpbalrSyDnq3TtZeGPUqGX+wAgAA" + + "nQEUBEKqia4QAwClpIsfJaSTezDE16G+MRRdU7xpZdFA9WwxjjDG3rOmnl0m0/UF" + + "3nv3x9xp4oy2O8Afqkz7/aIbm60qZ798np9whAVukNmCvjZQrJJmuNj8vGDFdonZ" + + "mI7SYtXJLxxVrecAAwUC/35AeUOcUhoLKTGk2ZrZl98xu2Q3mdGrz/HvJkS/FLMw" + + "k6arOrzGa18MkC2T27TGLz0KbkRhHio9MrIpsGEQOa6y0I50REd58rrhFFIHOI/m" + + "nkcT3/VlbCf2tRQh7WgD9f4DAwLssmOjVC+dmWDXVLRopzxbBGOvodp/LZoSDb56" + + "gNJjDMJ1aXqWW9qTAg1CFjBq73J3oFpVzInXZ8+Q8inxv7bnWiHbiE8EGBECAA8F" + + "AkKqia4CGwwFCQAk6gAACgkQ4w0TkGUaiMzdqgCgl2jw5hfk/JsyjulQqe1Nps1q" + + "Lx0AoMdnFMZmTMLHn8scUW2j9XO312tmsAIAAA=="); + + public char[] sec10pass = "test".toCharArray(); + + public byte[] subKeyBindingKey = Base64.decode( + "mQGiBDWagYwRBAD7UcH4TAIp7tmUoHBNxVxCVz2ZrNo79M6fV63riOiH2uDxfIpr" + + "IrL0cM4ehEKoqlhngjDhX60eJrOw1nC5BpYZRnDnyDYT4wTWRguxObzGq9pqA1dM" + + "oPTJhkFZVIBgFY99/ULRqaUYIhFGgBtnwS70J8/L/PGVc3DmWRLMkTDjSQCg/5Nh" + + "MCjMK++MdYMcMl/ziaKRT6EEAOtw6PnU9afdohbpx9CK4UvCCEagfbnUtkSCQKSk" + + "6cUp6VsqyzY0pai/BwJ3h4apFMMMpVrtBAtchVgqo4xTr0Sve2j0k+ase6FSImiB" + + "g+AR7hvTUTcBjwtIExBc8TuCTqmn4GG8F7UMdl5Z0AZYj/FfAQYaRVZYP/pRVFNx" + + "Lw65BAC/Fi3qgiGCJFvXnHIckTfcAmZnKSEXWY9NJ4YQb4+/nH7Vsw0wR/ZObUHR" + + "bWgTc9Vw1uZIMe0XVj6Yk1dhGRehUnrm3mE7UJxu7pgkBCbFECFSlSSqP4MEJwZV" + + "09YP/msu50kjoxyoTpt+16uX/8B4at24GF1aTHBxwDLd8X0QWrQsTWVycmlsbCBM" + + "eW5jaCBDTEVBUiBzeXN0ZW0gREggPGNsZWFyQG1sLmNvbT6JAEsEEBECAAsFAjWa" + + "gYwECwMBAgAKCRDyAGjiP47/XanfAKCs6BPURWVQlGh635VgL+pdkUVNUwCdFcNa" + + "1isw+eAcopXPMj6ACOapepu5Ag0ENZqBlBAIAPZCV7cIfwgXcqK61qlC8wXo+VMR" + + "OU+28W65Szgg2gGnVqMU6Y9AVfPQB8bLQ6mUrfdMZIZJ+AyDvWXpF9Sh01D49Vlf" + + "3HZSTz09jdvOmeFXklnN/biudE/F/Ha8g8VHMGHOfMlm/xX5u/2RXscBqtNbno2g" + + "pXI61Brwv0YAWCvl9Ij9WE5J280gtJ3kkQc2azNsOA1FHQ98iLMcfFstjvbzySPA" + + "Q/ClWxiNjrtVjLhdONM0/XwXV0OjHRhs3jMhLLUq/zzhsSlAGBGNfISnCnLWhsQD" + + "GcgHKXrKlQzZlp+r0ApQmwJG0wg9ZqRdQZ+cfL2JSyIZJrqrol7DVekyCzsAAgIH" + + "/RYtVo+HROZ6jrNjrATEwQm1fUQrk6n5+2dniN881lF0CNkB4NkHw1Xxz4Ejnu/0" + + "iLg8fkOAsmanOsKpOkRtqUnVpsVL5mLJpFEyCY5jbcfj+KY9/25bs0ga7kLHNZia" + + "zbCxJdF+W179z3nudQxRaXG/0XISIH7ziZbSVni69sKc1osk1+OoOMbSuZ86z535" + + "Pln4fXclkFE927HxfbWoO+60hkOLKh7x+8fC82b3x9vCETujEaxrscO2xS7/MYXP" + + "8t1ffriTDmhuIuQS2q4fLgeWdqrODrMhrD8Dq7e558gzp30ZCqpiS7EmKGczL7B8" + + "gXxbBCVSTxYMJheXt2xMXsuJAD8DBRg1moGU8gBo4j+O/10RAgWdAKCPhaFIXuC8" + + "/cdiNMxTDw9ug3De5QCfYXmDzRSFUu/nrCi8yz/l09wsnxo="); + + public byte[] subKeyBindingCheckSum = Base64.decode("3HU+"); + + // + // PGP8 with SHA1 checksum. + // + public byte[] rewrapKey = Base64.decode( + "lQOWBEUPOQgBCADdjPTtl8oOwqJFA5WU8p7oDK5KRWfmXeXUZr+ZJipemY5RSvAM" + + "rxqsM47LKYbmXOJznXCQ8+PPa+VxXAsI1CXFHIFqrXSwvB/DUmb4Ec9EuvNd18Zl" + + "hJAybzmV2KMkaUp9oG/DUvxZJqkpUddNfwqZu0KKKZWF5gwW5Oy05VCpaJxQVXFS" + + "whdbRfwEENJiNx4RB3OlWhIjY2p+TgZfgQjiGB9i15R+37sV7TqzBUZF4WWcnIRQ" + + "DnpUfxHgxQ0wO/h/aooyRHSpIx5i4oNpMYq9FNIyakEx/Bomdbs5hW9dFxhrE8Es" + + "UViAYITgTsyROxmgGatGG09dcmVDJVYF4i7JAAYpAAf/VnVyUDs8HrxYTOIt4rYY" + + "jIHToBsV0IiLpA8fEA7k078L1MwSwERVVe6oHVTjeR4A9OxE52Vroh2eOLnF3ftf" + + "6QThVVZr+gr5qeG3yvQ36N7PXNEVOlkyBzGmFQNe4oCA+NR2iqnAIspnekVmwJV6" + + "xVvPCjWw/A7ZArDARpfthspwNcJAp4SWfoa2eKzvUTznTyqFu2PSS5fwQZUgOB0P" + + "Y2FNaKeqV8vEZu4SUWwLOqXBQIZXiaLvdKNgwFvUe3kSHdCNsrVzW7SYxFwaEog2" + + "o6YLKPVPqjlGX1cMOponGp+7n9nDYkQjtEsGSSMQkQRDAcBdSVJmLO07kFOQSOhL" + + "WQQA49BcgTZyhyH6TnDBMBHsGCYj43FnBigypGT9FrQHoWybfX47yZaZFROAaaMa" + + "U6man50YcYZPwzDzXHrK2MoGALY+DzB3mGeXVB45D/KYtlMHPLgntV9T5b14Scbc" + + "w1ES2OUtsSIUs0zelkoXqjLuKnSIYK3mMb67Au7AEp6LXM8EAPj2NypvC86VEnn+" + + "FH0QHvUwBpmDw0EZe25xQs0brvAG00uIbiZnTH66qsIfRhXV/gbKK9J5DTGIqQ15" + + "DuPpz7lcxg/n2+SmjQLNfXCnG8hmtBjhTe+udXAUrmIcfafXyu68SAtebgm1ga56" + + "zUfqsgN3FFuMUffLl3myjyGsg5DnA/oCFWL4WCNClOgL6A5VkNIUait8QtSdCACT" + + "Y7jdSOguSNXfln0QT5lTv+q1AjU7zjRl/LsFNmIJ5g2qdDyK937FOXM44FEEjZty" + + "/4P2dzYpThUI4QUohIj8Qi9f2pZQueC5ztH6rpqANv9geZKcciAeAbZ8Md0K2TEU" + + "RD3Lh+RSBzILtBtUZXN0IEtleSA8dGVzdEBleGFtcGxlLmNvbT6JATYEEwECACAF" + + "AkUPOQgCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRDYpknHeQaskD9NB/9W" + + "EbFuLaqZAl3yjLU5+vb75BdvcfL1lUs44LZVwobNp3/0XbZdY76xVPNZURtU4u3L" + + "sJfGlaF+EqZDE0Mqc+vs5SIb0OnCzNJ00KaUFraUtkByRV32T5ECHK0gMBjCs5RT" + + "I0vVv+Qmzl4+X1Y2bJ2mlpBejHIrOzrBD5NTJimTAzyfnNfipmbqL8p/cxXKKzS+" + + "OM++ZFNACj6lRM1W9GioXnivBRC88gFSQ4/GXc8yjcrMlKA27JxV+SZ9kRWwKH2f" + + "6o6mojUQxnHr+ZFKUpo6ocvTgBDlC57d8IpwJeZ2TvqD6EdA8rZ0YriVjxGMDrX1" + + "8esfw+iLchfEwXtBIRwS"); + + char[] rewrapPass = "voltage123".toCharArray(); + + byte[] pubWithX509 = Base64.decode( + "mQENBERabjABCACtmfyo6Nph9MQjv4nmCWjZrRYnhXbivomAdIwYkLZUj1bjqE+j"+ + "uaLzjZV8xSI59odZvrmOiqlzOc4txitQ1OX7nRgbOJ7qku0dvwjtIn46+HQ+cAFn"+ + "2mTi81RyXEpO2uiZXfsNTxUtMi+ZuFLufiMc2kdk27GZYWEuasdAPOaPJnA+wW6i"+ + "ZHlt0NfXIGNz864gRwhD07fmBIr1dMFfATWxCbgMd/rH7Z/j4rvceHD2n9yrhPze"+ + "YN7W4Nuhsr2w/Ft5Cm9xO7vXT/cpto45uxn8f7jERep6bnUwNOhH8G+6xLQgTLD0"+ + "qFBGVSIneK3lobs6+xn6VaGN8W0tH3UOaxA1ABEBAAG0D0NOPXFhLWRlZXBzaWdo"+ + "dIkFDgQQZAIFAQUCRFpuMAUDCWdU0gMF/3gCGwPELGQBAQQwggTkMIIDzKADAgEC"+ + "AhBVUMV/M6rIiE+IzmnPheQWMA0GCSqGSIb3DQEBBQUAMG4xEzARBgoJkiaJk/Is"+ + "ZAEZFgNjb20xEjAQBgoJkiaJk/IsZAEZFgJxYTEVMBMGCgmSJomT8ixkARkWBXRt"+ + "czAxMRUwEwYKCZImiZPyLGQBGRYFV2ViZmUxFTATBgNVBAMTDHFhLWRlZXBzaWdo"+ + "dDAeFw0wNjA1MDQyMTEyMTZaFw0xMTA1MDQyMTIwMDJaMG4xEzARBgoJkiaJk/Is"+ + "ZAEZFgNjb20xEjAQBgoJkiaJk/IsZAEZFgJxYTEVMBMGCgmSJomT8ixkARkWBXRt"+ + "czAxMRUwEwYKCZImiZPyLGQBGRYFV2ViZmUxFTATBgNVBAMTDHFhLWRlZXBzaWdo"+ + "dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK2Z/Kjo2mH0xCO/ieYJ"+ + "aNmtFieFduK+iYB0jBiQtlSPVuOoT6O5ovONlXzFIjn2h1m+uY6KqXM5zi3GK1DU"+ + "5fudGBs4nuqS7R2/CO0ifjr4dD5wAWfaZOLzVHJcSk7a6Jld+w1PFS0yL5m4Uu5+"+ + "IxzaR2TbsZlhYS5qx0A85o8mcD7BbqJkeW3Q19cgY3PzriBHCEPTt+YEivV0wV8B"+ + "NbEJuAx3+sftn+Piu9x4cPaf3KuE/N5g3tbg26GyvbD8W3kKb3E7u9dP9ym2jjm7"+ + "Gfx/uMRF6npudTA06Efwb7rEtCBMsPSoUEZVIid4reWhuzr7GfpVoY3xbS0fdQ5r"+ + "EDUCAwEAAaOCAXwwggF4MAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0G"+ + "A1UdDgQWBBSmFTRv5y65DHtTYae48zl0ExNWZzCCASUGA1UdHwSCARwwggEYMIIB"+ + "FKCCARCgggEMhoHFbGRhcDovLy9DTj1xYS1kZWVwc2lnaHQsQ049cWEtd3VtYW4x"+ + "LWRjLENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNl"+ + "cyxDTj1Db25maWd1cmF0aW9uLERDPVdlYmZlLERDPXRtczAxLERDPXFhLERDPWNv"+ + "bT9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JM"+ + "RGlzdHJpYnV0aW9uUG9pbnSGQmh0dHA6Ly9xYS13dW1hbjEtZGMud2ViZmUudG1z"+ + "MDEucWEuY29tL0NlcnRFbnJvbGwvcWEtZGVlcHNpZ2h0LmNybDAQBgkrBgEEAYI3"+ + "FQEEAwIBADANBgkqhkiG9w0BAQUFAAOCAQEAfuZCW3XlB7Eok35zQbvYt9rhAndT"+ + "DNw3wPNI4ZzD1nXoYWnwhNNvWRpsOt4ExOSNdaHErfgDXAMyyg66Sro0TkAx8eAj"+ + "fPQsyRAh0nm0glzFmJN6TdOZbj7hqGZjc4opQ6nZo8h/ULnaEwMIUW4gcSkZt0ww"+ + "CuErl5NUrN3DpkREeCG/fVvQZ8ays3ibQ5ZCZnYBkLYq/i0r3NLW34WfYhjDY48J"+ + "oQWtvFSAxvRfz2NGmqnrCHPQZxqlfdta97kDa4VQ0zSeBaC70gZkLmD1GJMxWoXW"+ + "6tmEcgPY5SghInUf+L2u52V55MjyAFzVp7kTK2KY+p7qw35vzckrWkwu8AAAAAAA"+ + "AQE="); + + private static byte[] secWithPersonalCertificate = Base64.decode( + "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" + + "cGdwbWltZQULBwgJAgIZAQUbAQAAAAUeAQAAAAIVAgAKCRDlTa3BE84gWVKW" + + "BACcoCFKvph9r9QiHT1Z3N4wZH36Uxqu/059EFALnBkEdVudX/p6S9mynGRk" + + "EfhmWFC1O6dMpnt+ZBEed/4XyFWVSLPwirML+6dxfXogdUsdFF1NCRHc3QGc" + + "txnNUT/zcZ9IRIQjUhp6RkIvJPHcyfTXKSbLviI+PxzHU2Padq8pV7ABZ7kA" + + "jQRIfg8tAQQAutJR/aRnfZYwlVv+KlUDYjG8YQUfHpTxpnmVu7W6N0tNg/Xr" + + "5dg50wq3I4HOamRxUwHpdPkXyNF1szpDSRZmlM+VmiIvJDBnyH5YVlxT6+zO" + + "8LUJ2VTbfPxoLFp539SQ0oJOm7IGMAGO7c0n/QV0N3hKUfWgCyJ+sENDa0Ft" + + "JycAEQEAAbABj4kEzQQYAQIENwUCSMYtnAUJAeEzgMLFFAAAAAAAFwNleDUw" + + "OWNlcnRpZmljYXRlQHBncC5jb20wggNhMIICyqADAgECAgkA1AoCoRKJCgsw" + + "DQYJKoZIhvcNAQEFBQAwgakxCzAJBgNVBAYTAkNaMRcwFQYDVQQIEw5DemVj" + + "aCBSZXB1YmxpYzESMBAGA1UEChQJQSYmTCBzb2Z0MSAwHgYDVQQLExdJbnRl" + + "cm5hbCBEZXZlbG9wbWVudCBDQTEqMCgGA1UEAxQhQSYmTCBzb2Z0IEludGVy" + + "bmFsIERldmVsb3BtZW50IENBMR8wHQYJKoZIhvcNAQkBFhBrYWRsZWNAYWxz" + + "b2Z0LmN6MB4XDTA4MDcxNjE1MDkzM1oXDTA5MDcxNjE1MDkzM1owaTELMAkG" + + "A1UEBhMCQ1oxFzAVBgNVBAgTDkN6ZWNoIFJlcHVibGljMRIwEAYDVQQKFAlB" + + "JiZMIHNvZnQxFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5IeW5l" + + "ay1JbnRyYW5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAutJR/aRn" + + "fZYwlVv+KlUDYjG8YQUfHpTxpnmVu7W6N0tNg/Xr5dg50wq3I4HOamRxUwHp" + + "dPkXyNF1szpDSRZmlM+VmiIvJDBnyH5YVlxT6+zO8LUJ2VTbfPxoLFp539SQ" + + "0oJOm7IGMAGO7c0n/QV0N3hKUfWgCyJ+sENDa0FtJycCAwEAAaOBzzCBzDAJ" + + "BgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBD" + + "ZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUNaw7A6r10PtYZzAvr9CrSKeRYJgwHwYD" + + "VR0jBBgwFoAUmqSRM8rN3+T1+tkGiqef8S5suYgwGgYDVR0RBBMwEYEPaHlu" + + "ZWtAYWxzb2Z0LmN6MCgGA1UdHwQhMB8wHaAboBmGF2h0dHA6Ly9wZXRyazIv" + + "Y2EvY2EuY3JsMAsGA1UdDwQEAwIF4DANBgkqhkiG9w0BAQUFAAOBgQCUdOWd" + + "7mBLWj1/GSiYgfwgdTrgk/VZOJvMKBiiFyy1iFEzldz6Xx+mAexnFJKfZXZb" + + "EMEGWHfWPmgJzAtuTT0Jz6tUwDmeLH3MP4m8uOZtmyUJ2aq41kciV3rGxF0G" + + "BVlZ/bWTaOzHdm6cjylt6xxLt6MJzpPBA/9ZfybSBh1DaAUbDgAAAJ0gBBkB" + + "AgAGBQJIxi2bAAoJEAdYkEWLb2R2fJED/RK+JErZ98uGo3Z81cHkdP3rk8is" + + "DUL/PR3odBPFH2SIA5wrzklteLK/ZXmBUzcvxqHEgI1F7goXbsBgeTuGgZdx" + + "pINErxkNpcMl9FTldWKGiapKrhkZ+G8knDizF/Y7Lg6uGd2nKVxzutLXdHJZ" + + "pU89Q5nzq6aJFAZo5TBIcchQAAoJEOVNrcETziBZXvQD/1mvFqBfWqwXxoj3" + + "8fHUuFrE2pcp32y3ciO2i+uNVEkNDoaVVNw5eHQaXXWpllI/Pe6LnBl4vkyc" + + "n3pjONa4PKrePkEsCUhRbIySqXIHuNwZumDOlKzZHDpCUw72LaC6S6zwuoEf" + + "ucOcxTeGIUViANWXyTIKkHfo7HfigixJIL8nsAFn"); + + private static final byte[] umlautKeySig = Base64.decode( + "mI0ETdvOgQEEALoI2a39TRk1HReEB6DP9Bu3ShZUce+/Oeg9RIL9aUFuCsNdhu02" + + "REEHjO29Jz8daPgrnJDfFepNLD6iKKru2m9P30qnhsHMIAshO2Ozfh6wKwuHRqR3" + + "L4gBDu7cCB6SLwPoD8AYG0yQSM+Do10Td87RlStxCgxpMK6R3TsRkxcFABEBAAG0" + + "OlVNTEFVVFNUQVJUOsOEw6TDlsO2w5zDvMOfOlVNTEFURU5ERSA8YXNkbGFrc2Rs" + + "QGFrc2RqLmNvbT6IuAQTAQIAIgUCTdvOgQIbAwYLCQgHAwIGFQgCCQoLBBYCAwEC" + + "HgECF4AACgkQP8kDwm8AOFiArAP/ZXrlZJB1jFEjyBb04ckpE6F/aJuSYIXf0Yx5" + + "T2eS+lA69vYuqKRC1qNROBrAn/WGNOQBFNEgGoy3F3gV5NgpIphnyIEZdZWGY2rv" + + "yjunKWlioZjWc/xbSbvpvJ3Q8RyfDXBOkDEB6uF1ksimw2eJSOUTkF9AQfS5f4rT" + + "5gs013G4jQRN286BAQQApVbjd8UhsQLB4TpeKn9+dDXAfikGgxDOb19XisjRiWxA" + + "+bKFxu5tRt6fxXl6BGSGT7DhoVbNkcJGVQFYcbR31UGKCVYcWSL3yfz+PiVuf1UB" + + "Rp44cXxxqxrLqKp1rk3dGvV4Ayy8lkk3ncDGPez6lIKvj3832yVtAzUOX1QOg9EA" + + "EQEAAYifBBgBAgAJBQJN286BAhsMAAoJED/JA8JvADhYQ80D/R3TX0FBMHs/xqEh" + + "tiS86XP/8pW6eMm2eaAYINxoDY3jmDMv2HFQ+YgrYXgqGr6eVGqDMNPj4W8VBoOt" + + "iYW7+SWY76AAl+gmWIMm2jbN8bZXFk4jmIxpycHCrtoXX8rUk/0+se8NvbmAdMGK" + + "POOoD7oxdRmJSU5hSspOCHrCwCa3"); + + public void test1() + throws Exception + { + BcPGPPublicKeyRingCollection pubRings = new BcPGPPublicKeyRingCollection(pub1); + + int count = 0; + + Iterator rIt = pubRings.getKeyRings(); + + while (rIt.hasNext()) + { + PGPPublicKeyRing pgpPub = (PGPPublicKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpPub.getEncoded(); + + pgpPub = new PGPPublicKeyRing(bytes, new BcKeyFingerprintCalculator()); + + Iterator it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPPublicKey pubKey = (PGPPublicKey)it.next(); + + Iterator sIt = pubKey.getSignatures(); + while (sIt.hasNext()) + { + ((PGPSignature)sIt.next()).getSignatureType(); + } + } + + if (keyCount != 2) + { + fail("wrong number of public keys"); + } + } + + if (count != 1) + { + fail("wrong number of public keyrings"); + } + + // + // exact match + // + rIt = pubRings.getKeyRings("test (Test key) <test@ubicall.com>"); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 1) + { + fail("wrong number of public keyrings on exact match"); + } + + // + // partial match 1 expected + // + rIt = pubRings.getKeyRings("test", true); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 1) + { + fail("wrong number of public keyrings on partial match 1"); + } + + // + // partial match 0 expected + // + rIt = pubRings.getKeyRings("XXX", true); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 0) + { + fail("wrong number of public keyrings on partial match 0"); + } + + // + // case-insensitive partial match + // + rIt = pubRings.getKeyRings("TEST@ubicall.com", true, true); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 1) + { + fail("wrong number of public keyrings on case-insensitive partial match"); + } + + BcPGPSecretKeyRingCollection secretRings = new BcPGPSecretKeyRingCollection(sec1); + + rIt = secretRings.getKeyRings(); + count = 0; + + while (rIt.hasNext()) + { + PGPSecretKeyRing pgpSec = (PGPSecretKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpSec.getEncoded(); + + pgpSec = new PGPSecretKeyRing(bytes, new BcKeyFingerprintCalculator()); + + Iterator it = pgpSec.getSecretKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPSecretKey k = (PGPSecretKey)it.next(); + PGPPublicKey pk = k.getPublicKey(); + + pk.getSignatures(); + + byte[] pkBytes = pk.getEncoded(); + + PGPPublicKeyRing pkR = new PGPPublicKeyRing(pkBytes, new BcKeyFingerprintCalculator()); + } + + if (keyCount != 2) + { + fail("wrong number of secret keys"); + } + } + + if (count != 1) + { + fail("wrong number of secret keyrings"); + } + + // + // exact match + // + rIt = secretRings.getKeyRings("test (Test key) <test@ubicall.com>"); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 1) + { + fail("wrong number of secret keyrings on exact match"); + } + + // + // partial match 1 expected + // + rIt = secretRings.getKeyRings("test", true); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 1) + { + fail("wrong number of secret keyrings on partial match 1"); + } + + // + // exact match 0 expected + // + rIt = secretRings.getKeyRings("test", false); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 0) + { + fail("wrong number of secret keyrings on partial match 0"); + } + + // + // case-insensitive partial match + // + rIt = secretRings.getKeyRings("TEST@ubicall.com", true, true); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 1) + { + fail("wrong number of secret keyrings on case-insensitive partial match"); + } + } + + public void test2() + throws Exception + { + BcPGPPublicKeyRingCollection pubRings = new BcPGPPublicKeyRingCollection(pub2); + + int count = 0; + + byte[] encRing = pubRings.getEncoded(); + + pubRings = new BcPGPPublicKeyRingCollection(encRing); + + Iterator rIt = pubRings.getKeyRings(); + + while (rIt.hasNext()) + { + PGPPublicKeyRing pgpPub = (PGPPublicKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpPub.getEncoded(); + + pgpPub = new PGPPublicKeyRing(bytes, new BcKeyFingerprintCalculator()); + + Iterator it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + PGPPublicKey pk = (PGPPublicKey)it.next(); + + byte[] pkBytes = pk.getEncoded(); + + PGPPublicKeyRing pkR = new PGPPublicKeyRing(pkBytes, new BcKeyFingerprintCalculator()); + + keyCount++; + } + + if (keyCount != 2) + { + fail("wrong number of public keys"); + } + } + + if (count != 2) + { + fail("wrong number of public keyrings"); + } + + BcPGPSecretKeyRingCollection secretRings = new BcPGPSecretKeyRingCollection(sec2); + + rIt = secretRings.getKeyRings(); + count = 0; + + encRing = secretRings.getEncoded(); + + secretRings = new BcPGPSecretKeyRingCollection(encRing); + + while (rIt.hasNext()) + { + PGPSecretKeyRing pgpSec = (PGPSecretKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpSec.getEncoded(); + + pgpSec = new PGPSecretKeyRing(bytes, new BcKeyFingerprintCalculator()); + + Iterator it = pgpSec.getSecretKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPSecretKey k = (PGPSecretKey)it.next(); + PGPPublicKey pk = k.getPublicKey(); + + if (pk.getKeyID() == -1413891222336124627L) + { + int sCount = 0; + Iterator sIt = pk.getSignaturesOfType(PGPSignature.SUBKEY_BINDING); + while (sIt.hasNext()) + { + int type = ((PGPSignature)sIt.next()).getSignatureType(); + if (type != PGPSignature.SUBKEY_BINDING) + { + fail("failed to return correct signature type"); + } + sCount++; + } + + if (sCount != 1) + { + fail("failed to find binding signature"); + } + } + + pk.getSignatures(); + + if (k.getKeyID() == -4049084404703773049L + || k.getKeyID() == -1413891222336124627L) + { + k.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(sec2pass1)); + } + else if (k.getKeyID() == -6498553574938125416L + || k.getKeyID() == 59034765524361024L) + { + k.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(sec2pass2)); + } + } + + if (keyCount != 2) + { + fail("wrong number of secret keys"); + } + } + + if (count != 2) + { + fail("wrong number of secret keyrings"); + } + } + + public void test3() + throws Exception + { + BcPGPPublicKeyRingCollection pubRings = new BcPGPPublicKeyRingCollection(pub3); + + int count = 0; + + byte[] encRing = pubRings.getEncoded(); + + pubRings = new BcPGPPublicKeyRingCollection(encRing); + + Iterator rIt = pubRings.getKeyRings(); + + while (rIt.hasNext()) + { + PGPPublicKeyRing pgpPub = (PGPPublicKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpPub.getEncoded(); + + pgpPub = new PGPPublicKeyRing(bytes, new BcKeyFingerprintCalculator()); + + Iterator it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPPublicKey pubK = (PGPPublicKey)it.next(); + + pubK.getSignatures(); + } + + if (keyCount != 2) + { + fail("wrong number of public keys"); + } + } + + if (count != 1) + { + fail("wrong number of public keyrings"); + } + + BcPGPSecretKeyRingCollection secretRings = new BcPGPSecretKeyRingCollection(sec3); + + rIt = secretRings.getKeyRings(); + count = 0; + + encRing = secretRings.getEncoded(); + + secretRings = new BcPGPSecretKeyRingCollection(encRing); + + while (rIt.hasNext()) + { + PGPSecretKeyRing pgpSec = (PGPSecretKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpSec.getEncoded(); + + pgpSec = new PGPSecretKeyRing(bytes, new BcKeyFingerprintCalculator()); + + Iterator it = pgpSec.getSecretKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPSecretKey k = (PGPSecretKey)it.next(); + + k.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(sec3pass1)); + } + + if (keyCount != 2) + { + fail("wrong number of secret keys"); + } + } + + if (count != 1) + { + fail("wrong number of secret keyrings"); + } + } + + public void test4() + throws Exception + { + BcPGPSecretKeyRingCollection secretRings = new BcPGPSecretKeyRingCollection(sec4); + + Iterator rIt = secretRings.getKeyRings(); + int count = 0; + + byte[] encRing = secretRings.getEncoded(); + + secretRings = new BcPGPSecretKeyRingCollection(encRing); + + while (rIt.hasNext()) + { + PGPSecretKeyRing pgpSec = (PGPSecretKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpSec.getEncoded(); + + pgpSec = new PGPSecretKeyRing(bytes, new BcKeyFingerprintCalculator()); + + Iterator it = pgpSec.getSecretKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPSecretKey k = (PGPSecretKey)it.next(); + + k.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(sec3pass1)); + } + + if (keyCount != 2) + { + fail("wrong number of secret keys"); + } + } + + if (count != 1) + { + fail("wrong number of secret keyrings"); + } + } + + public void test5() + throws Exception + { + BcPGPPublicKeyRingCollection pubRings = new BcPGPPublicKeyRingCollection(pub5); + + int count = 0; + + byte[] encRing = pubRings.getEncoded(); + + pubRings = new BcPGPPublicKeyRingCollection(encRing); + + Iterator rIt = pubRings.getKeyRings(); + + while (rIt.hasNext()) + { + PGPPublicKeyRing pgpPub = (PGPPublicKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpPub.getEncoded(); + + pgpPub = new PGPPublicKeyRing(bytes, new BcKeyFingerprintCalculator()); + + Iterator it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + keyCount++; + + it.next(); + } + + if (keyCount != 2) + { + fail("wrong number of public keys"); + } + } + + if (count != 1) + { + fail("wrong number of public keyrings"); + } + + if (noIDEA()) + { + return; + } + + BcPGPSecretKeyRingCollection secretRings = new BcPGPSecretKeyRingCollection(sec5); + + rIt = secretRings.getKeyRings(); + count = 0; + + encRing = secretRings.getEncoded(); + + secretRings = new BcPGPSecretKeyRingCollection(encRing); + + while (rIt.hasNext()) + { + PGPSecretKeyRing pgpSec = (PGPSecretKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpSec.getEncoded(); + + pgpSec = new PGPSecretKeyRing(bytes, new BcKeyFingerprintCalculator()); + + Iterator it = pgpSec.getSecretKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPSecretKey k = (PGPSecretKey)it.next(); + + k.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(sec5pass1)); + } + + if (keyCount != 2) + { + fail("wrong number of secret keys"); + } + } + + if (count != 1) + { + fail("wrong number of secret keyrings"); + } + } + + private boolean noIDEA() + { + return true; + } + + public void test6() + throws Exception + { + BcPGPPublicKeyRingCollection pubRings = new BcPGPPublicKeyRingCollection(pub6); + Iterator rIt = pubRings.getKeyRings(); + + while (rIt.hasNext()) + { + PGPPublicKeyRing pgpPub = (PGPPublicKeyRing)rIt.next(); + Iterator it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + PGPPublicKey k = (PGPPublicKey)it.next(); + + if (k.getKeyID() == 0x5ce086b5b5a18ff4L) + { + int count = 0; + Iterator sIt = k.getSignaturesOfType(PGPSignature.SUBKEY_REVOCATION); + while (sIt.hasNext()) + { + PGPSignature sig = (PGPSignature)sIt.next(); + count++; + } + + if (count != 1) + { + fail("wrong number of revocations in test6."); + } + } + } + } + + byte[] encRing = pubRings.getEncoded(); + } + + public void revocationTest() + throws Exception + { + PGPPublicKeyRing pgpPub = new PGPPublicKeyRing(pub7, new BcKeyFingerprintCalculator()); + Iterator it = pgpPub.getPublicKeys(); + PGPPublicKey masterKey = null; + + while (it.hasNext()) + { + PGPPublicKey k = (PGPPublicKey)it.next(); + + if (k.isMasterKey()) + { + masterKey = k; + continue; + } + } + + PGPSignature sig =((PGPSignatureList)new JcaPGPObjectFactory(pub7revoke).nextObject()).get(0); + + sig.init(new BcPGPContentVerifierBuilderProvider(), masterKey); + + if (!sig.verifyCertification(masterKey)) + { + fail("failed to verify revocation certification"); + } + } + + public void test8() + throws Exception + { + BcPGPPublicKeyRingCollection pubRings = new BcPGPPublicKeyRingCollection(pub8); + + int count = 0; + + byte[] encRing = pubRings.getEncoded(); + + pubRings = new BcPGPPublicKeyRingCollection(encRing); + + Iterator rIt = pubRings.getKeyRings(); + + while (rIt.hasNext()) + { + PGPPublicKeyRing pgpPub = (PGPPublicKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpPub.getEncoded(); + + pgpPub = new PGPPublicKeyRing(bytes, new BcKeyFingerprintCalculator()); + + Iterator it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + keyCount++; + + it.next(); + } + + if (keyCount != 2) + { + fail("wrong number of public keys"); + } + } + + if (count != 2) + { + fail("wrong number of public keyrings"); + } + + BcPGPSecretKeyRingCollection secretRings = new BcPGPSecretKeyRingCollection(sec8); + + rIt = secretRings.getKeyRings(); + count = 0; + + encRing = secretRings.getEncoded(); + + secretRings = new BcPGPSecretKeyRingCollection(encRing); + + while (rIt.hasNext()) + { + PGPSecretKeyRing pgpSec = (PGPSecretKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpSec.getEncoded(); + + pgpSec = new PGPSecretKeyRing(bytes, new BcKeyFingerprintCalculator()); + + Iterator it = pgpSec.getSecretKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPSecretKey k = (PGPSecretKey)it.next(); + + k.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(sec8pass)); + } + + if (keyCount != 2) + { + fail("wrong number of secret keys"); + } + } + + if (count != 1) + { + fail("wrong number of secret keyrings"); + } + } + + public void test9() + throws Exception + { + BcPGPSecretKeyRingCollection secretRings = new BcPGPSecretKeyRingCollection(sec9); + + Iterator rIt = secretRings.getKeyRings(); + int count = 0; + + byte[] encRing = secretRings.getEncoded(); + + secretRings = new BcPGPSecretKeyRingCollection(encRing); + + while (rIt.hasNext()) + { + PGPSecretKeyRing pgpSec = (PGPSecretKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpSec.getEncoded(); + + pgpSec = new PGPSecretKeyRing(bytes, new BcKeyFingerprintCalculator()); + + Iterator it = pgpSec.getSecretKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPSecretKey k = (PGPSecretKey)it.next(); + + PGPPrivateKey pKey = k.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(sec9pass)); + if (keyCount == 1 && pKey != null) + { + fail("primary secret key found, null expected"); + } + } + + if (keyCount != 3) + { + fail("wrong number of secret keys"); + } + } + + if (count != 1) + { + fail("wrong number of secret keyrings"); + } + } + + public void test10() + throws Exception + { + PGPSecretKeyRing secretRing = new PGPSecretKeyRing(sec10, new BcKeyFingerprintCalculator()); + Iterator secretKeys = secretRing.getSecretKeys(); + + while (secretKeys.hasNext()) + { + PGPPublicKey pubKey = ((PGPSecretKey)secretKeys.next()).getPublicKey(); + + if (pubKey.getValidDays() != 28) + { + fail("days wrong on secret key ring"); + } + + if (pubKey.getValidSeconds() != 28 * 24 * 60 * 60) + { + fail("seconds wrong on secret key ring"); + } + } + + PGPPublicKeyRing publicRing = new PGPPublicKeyRing(pub10, new BcKeyFingerprintCalculator()); + Iterator publicKeys = publicRing.getPublicKeys(); + + while (publicKeys.hasNext()) + { + PGPPublicKey pubKey = (PGPPublicKey)publicKeys.next(); + + if (pubKey.getValidDays() != 28) + { + fail("days wrong on public key ring"); + } + + if (pubKey.getValidSeconds() != 28 * 24 * 60 * 60) + { + fail("seconds wrong on public key ring"); + } + } + } + + public void generateTest() + throws Exception + { + char[] passPhrase = "hello".toCharArray(); + KeyPairGenerator dsaKpg = KeyPairGenerator.getInstance("DSA", "SC"); + + dsaKpg.initialize(512); + + // + // this takes a while as the key generator has to generate some DSA params + // before it generates the key. + // + KeyPair dsaKp = dsaKpg.generateKeyPair(); + + KeyPairGenerator elgKpg = KeyPairGenerator.getInstance("ELGAMAL", "SC"); + BigInteger g = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + BigInteger p = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g); + + elgKpg.initialize(elParams); + + // + // this is quicker because we are using pregenerated parameters. + // + KeyPair elgKp = elgKpg.generateKeyPair(); + PGPKeyPair dsaKeyPair = new JcaPGPKeyPair(PGPPublicKey.DSA, dsaKp, new Date()); + PGPKeyPair elgKeyPair = new JcaPGPKeyPair(PGPPublicKey.ELGAMAL_ENCRYPT, elgKp, new Date()); + + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, dsaKeyPair, + "test", sha1Calc, null, null, new JcaPGPContentSignerBuilder(PGPPublicKey.DSA, HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256).setProvider("SC").build(passPhrase)); + + keyRingGen.addSubKey(elgKeyPair); + + PGPSecretKeyRing keyRing = keyRingGen.generateSecretKeyRing(); + + keyRing.getSecretKey().extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(passPhrase)); + + PGPPublicKeyRing pubRing = keyRingGen.generatePublicKeyRing(); + + PGPPublicKey vKey = null; + PGPPublicKey sKey = null; + + Iterator it = pubRing.getPublicKeys(); + while (it.hasNext()) + { + PGPPublicKey pk = (PGPPublicKey)it.next(); + if (pk.isMasterKey()) + { + vKey = pk; + } + else + { + sKey = pk; + } + } + + Iterator sIt = sKey.getSignatures(); + while (sIt.hasNext()) + { + PGPSignature sig = (PGPSignature)sIt.next(); + + if (sig.getKeyID() == vKey.getKeyID() + && sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) + { + sig.init(new BcPGPContentVerifierBuilderProvider(), vKey); + + if (!sig.verifyCertification(vKey, sKey)) + { + fail("failed to verify sub-key signature."); + } + } + } + } + + private void insertMasterTest() + throws Exception + { + char[] passPhrase = "hello".toCharArray(); + KeyPairGenerator rsaKpg = KeyPairGenerator.getInstance("RSA", "SC"); + + rsaKpg.initialize(512); + + // + // this is quicker because we are using pregenerated parameters. + // + KeyPair rsaKp = rsaKpg.generateKeyPair(); + PGPKeyPair rsaKeyPair1 = new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, rsaKp, new Date()); + rsaKp = rsaKpg.generateKeyPair(); + PGPKeyPair rsaKeyPair2 = new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, rsaKp, new Date()); + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, rsaKeyPair1, + "test", sha1Calc, null, null, new JcaPGPContentSignerBuilder(PGPPublicKey.RSA_SIGN, HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256).setProvider("SC").build(passPhrase)); + PGPSecretKeyRing secRing1 = keyRingGen.generateSecretKeyRing(); + PGPPublicKeyRing pubRing1 = keyRingGen.generatePublicKeyRing(); + keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, rsaKeyPair2, + "test", sha1Calc, null, null, new JcaPGPContentSignerBuilder(PGPPublicKey.RSA_SIGN, HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256).setProvider("SC").build(passPhrase)); + PGPSecretKeyRing secRing2 = keyRingGen.generateSecretKeyRing(); + PGPPublicKeyRing pubRing2 = keyRingGen.generatePublicKeyRing(); + + try + { + PGPPublicKeyRing.insertPublicKey(pubRing1, pubRing2.getPublicKey()); + fail("adding second master key (public) should throw an IllegalArgumentException"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("cannot add a master key to a ring that already has one")) + { + fail("wrong message in public test"); + } + } + + try + { + PGPSecretKeyRing.insertSecretKey(secRing1, secRing2.getSecretKey()); + fail("adding second master key (secret) should throw an IllegalArgumentException"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("cannot add a master key to a ring that already has one")) + { + fail("wrong message in secret test"); + } + } + } + + public void generateSha1Test() + throws Exception + { + char[] passPhrase = "hello".toCharArray(); + KeyPairGenerator dsaKpg = KeyPairGenerator.getInstance("DSA", "SC"); + + dsaKpg.initialize(512); + + // + // this takes a while as the key generator has to generate some DSA params + // before it generates the key. + // + KeyPair dsaKp = dsaKpg.generateKeyPair(); + + KeyPairGenerator elgKpg = KeyPairGenerator.getInstance("ELGAMAL", "SC"); + BigInteger g = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + BigInteger p = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g); + + elgKpg.initialize(elParams); + + // + // this is quicker because we are using pregenerated parameters. + // + KeyPair elgKp = elgKpg.generateKeyPair(); + PGPKeyPair dsaKeyPair = new JcaPGPKeyPair(PGPPublicKey.DSA, dsaKp, new Date()); + PGPKeyPair elgKeyPair = new JcaPGPKeyPair(PGPPublicKey.ELGAMAL_ENCRYPT, elgKp, new Date()); + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, dsaKeyPair, + "test", sha1Calc, null, null, new JcaPGPContentSignerBuilder(PGPPublicKey.DSA, HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256).setProvider("SC").build(passPhrase)); + + + keyRingGen.addSubKey(elgKeyPair); + + PGPSecretKeyRing keyRing = keyRingGen.generateSecretKeyRing(); + + keyRing.getSecretKey().extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(passPhrase)); + + PGPPublicKeyRing pubRing = keyRingGen.generatePublicKeyRing(); + + PGPPublicKey vKey = null; + PGPPublicKey sKey = null; + + Iterator it = pubRing.getPublicKeys(); + while (it.hasNext()) + { + PGPPublicKey pk = (PGPPublicKey)it.next(); + if (pk.isMasterKey()) + { + vKey = pk; + } + else + { + sKey = pk; + } + } + + Iterator sIt = sKey.getSignatures(); + while (sIt.hasNext()) + { + PGPSignature sig = (PGPSignature)sIt.next(); + + if (sig.getKeyID() == vKey.getKeyID() + && sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) + { + sig.init(new BcPGPContentVerifierBuilderProvider(), vKey); + + if (!sig.verifyCertification(vKey, sKey)) + { + fail("failed to verify sub-key signature."); + } + } + } + } + + private void test11() + throws Exception + { + PGPPublicKeyRing pubRing = new PGPPublicKeyRing(subKeyBindingKey, new BcKeyFingerprintCalculator()); + Iterator it = pubRing.getPublicKeys(); + + while (it.hasNext()) + { + PGPPublicKey key = (PGPPublicKey)it.next(); + + if (key.getValidSeconds() != 0) + { + fail("expiration time non-zero"); + } + } + } + + private void rewrapTest() + throws Exception + { + SecureRandom rand = new SecureRandom(); + + // Read the secret key rings + BcPGPSecretKeyRingCollection privRings = new BcPGPSecretKeyRingCollection( + new ByteArrayInputStream(rewrapKey)); + + Iterator rIt = privRings.getKeyRings(); + + if (rIt.hasNext()) + { + PGPSecretKeyRing pgpPriv = (PGPSecretKeyRing)rIt.next(); + + Iterator it = pgpPriv.getSecretKeys(); + + while (it.hasNext()) + { + PGPSecretKey pgpKey = (PGPSecretKey)it.next(); + + // re-encrypt the key with an empty password + pgpPriv = PGPSecretKeyRing.removeSecretKey(pgpPriv, pgpKey); + pgpKey = PGPSecretKey.copyWithNewPassword( + pgpKey, + new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(rewrapPass), + null); + pgpPriv = PGPSecretKeyRing.insertSecretKey(pgpPriv, pgpKey); + + // this should succeed + PGPPrivateKey privTmp = pgpKey.extractPrivateKey(null); + } + } + } + + private void testPublicKeyRingWithX509() + throws Exception + { + checkPublicKeyRingWithX509(pubWithX509); + + PGPPublicKeyRing pubRing = new PGPPublicKeyRing(pubWithX509, new BcKeyFingerprintCalculator()); + + checkPublicKeyRingWithX509(pubRing.getEncoded()); + } + + private void testSecretKeyRingWithPersonalCertificate() + throws Exception + { + checkSecretKeyRingWithPersonalCertificate(secWithPersonalCertificate); + BcPGPSecretKeyRingCollection secRing = new BcPGPSecretKeyRingCollection(secWithPersonalCertificate); + checkSecretKeyRingWithPersonalCertificate(secRing.getEncoded()); + } + + private void testUmlaut() + throws Exception + { + PGPPublicKeyRing pubRing = new PGPPublicKeyRing(umlautKeySig, new BcKeyFingerprintCalculator()); + + PGPPublicKey pub = pubRing.getPublicKey(); + String userID = (String)pub.getUserIDs().next(); + + for (Iterator it = pub.getSignatures(); it.hasNext();) + { + PGPSignature sig = (PGPSignature)it.next(); + + if (sig.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION) + { + sig.init(new BcPGPContentVerifierBuilderProvider(), pub); + + if (!sig.verifyCertification(userID, pub)) + { + fail("failed UTF8 userID test"); + } + } + } + + // + // this is quicker because we are using pregenerated parameters. + // + KeyPairGenerator rsaKpg = KeyPairGenerator.getInstance("RSA", "SC"); + KeyPair rsaKp = rsaKpg.generateKeyPair(); + PGPKeyPair rsaKeyPair1 = new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, rsaKp, new Date()); + rsaKp = rsaKpg.generateKeyPair(); + PGPKeyPair rsaKeyPair2 = new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, rsaKp, new Date()); + char[] passPhrase = "passwd".toCharArray(); + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, rsaKeyPair1, + userID, sha1Calc, null, null, new JcaPGPContentSignerBuilder(PGPPublicKey.RSA_SIGN, HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256).setProvider("SC").build(passPhrase)); + + PGPPublicKeyRing pubRing1 = keyRingGen.generatePublicKeyRing(); + + pub = pubRing1.getPublicKey(); + + for (Iterator it = pub.getSignatures(); it.hasNext();) + { + PGPSignature sig = (PGPSignature)it.next(); + + if (sig.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION) + { + sig.init(new BcPGPContentVerifierBuilderProvider(), pub); + + if (!sig.verifyCertification(userID, pub)) + { + fail("failed UTF8 userID creation test"); + } + } + } + } + + private void checkSecretKeyRingWithPersonalCertificate(byte[] keyRing) + throws Exception + { + BcPGPSecretKeyRingCollection secCol = new BcPGPSecretKeyRingCollection(keyRing); + + + int count = 0; + + for (Iterator rIt = secCol.getKeyRings(); rIt.hasNext();) + { + PGPSecretKeyRing ring = (PGPSecretKeyRing)rIt.next(); + + for (Iterator it = ring.getExtraPublicKeys(); it.hasNext();) + { + it.next(); + count++; + } + } + + if (count != 1) + { + fail("personal certificate data subkey not found - count = " + count); + } + } + + private void checkPublicKeyRingWithX509(byte[] keyRing) + throws Exception + { + PGPPublicKeyRing pubRing = new PGPPublicKeyRing(keyRing, new BcKeyFingerprintCalculator()); + Iterator it = pubRing.getPublicKeys(); + + if (it.hasNext()) + { + PGPPublicKey key = (PGPPublicKey)it.next(); + + Iterator sIt = key.getSignatures(); + + if (sIt.hasNext()) + { + PGPSignature sig = (PGPSignature)sIt.next(); + if (sig.getKeyAlgorithm() != 100) + { + fail("experimental signature not found"); + } + if (!areEqual(sig.getSignature(), Hex.decode("000101"))) + { + fail("experimental encoding check failed"); + } + } + else + { + fail("no signature found"); + } + } + else + { + fail("no key found"); + } + } + + public void performTest() + throws Exception + { + try + { + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + revocationTest(); + test8(); + test9(); + test10(); + test11(); + generateTest(); + generateSha1Test(); + rewrapTest(); + testPublicKeyRingWithX509(); + testSecretKeyRingWithPersonalCertificate(); + insertMasterTest(); + testUmlaut(); + } + catch (PGPException e) + { + if (e.getUnderlyingException() != null) + { + Exception ex = e.getUnderlyingException(); + fail("exception: " + ex, ex); + } + else + { + fail("exception: " + e, e); + } + } + } + + public String getName() + { + return "BcPGPKeyRingTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new BcPGPKeyRingTest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/BcPGPPBETest.java b/pg/src/test/java/org/spongycastle/openpgp/test/BcPGPPBETest.java new file mode 100644 index 00000000..9a394d30 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/BcPGPPBETest.java @@ -0,0 +1,500 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Date; + +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPCompressedData; +import org.spongycastle.openpgp.PGPCompressedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedData; +import org.spongycastle.openpgp.PGPEncryptedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedDataList; +import org.spongycastle.openpgp.PGPLiteralData; +import org.spongycastle.openpgp.PGPLiteralDataGenerator; +import org.spongycastle.openpgp.PGPPBEEncryptedData; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.openpgp.operator.bc.BcPBEDataDecryptorFactory; +import org.spongycastle.openpgp.operator.bc.BcPBEKeyEncryptionMethodGenerator; +import org.spongycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder; +import org.spongycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; +import org.spongycastle.util.test.UncloseableOutputStream; + +public class BcPGPPBETest + extends SimpleTest +{ + private static final Date TEST_DATE = new Date(1062200111000L); + + byte[] enc1 = Base64.decode( + "jA0EAwMC5M5wWBP2HBZgySvUwWFAmMRLn7dWiZN6AkQMvpE3b6qwN3SSun7zInw2" + + "hxxdgFzVGfbjuB8w"); + + byte[] enc1crc = Base64.decode("H66L"); + + char[] pass = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' }; + + /** + * Message with both PBE and symmetric + */ + byte[] testPBEAsym = Base64.decode( + "hQIOA/ZlQEFWB5vuEAf/covEUaBve7NlWWdiO5NZubdtTHGElEXzG9hyBycp9At8" + + "nZGi27xOZtEGFQo7pfz4JySRc3O0s6w7PpjJSonFJyNSxuze2LuqRwFWBYYcbS8/" + + "7YcjB6PqutrT939OWsozfNqivI9/QyZCjBvFU89pp7dtUngiZ6MVv81ds2I+vcvk" + + "GlIFcxcE1XoCIB3EvbqWNaoOotgEPT60unnB2BeDV1KD3lDRouMIYHfZ3SzBwOOI" + + "6aK39sWnY5sAK7JjFvnDAMBdueOiI0Fy+gxbFD/zFDt4cWAVSAGTC4w371iqppmT" + + "25TM7zAtCgpiq5IsELPlUZZnXKmnYQ7OCeysF0eeVwf+OFB9fyvCEv/zVQocJCg8" + + "fWxfCBlIVFNeNQpeGygn/ZmRaILvB7IXDWP0oOw7/F2Ym66IdYYIp2HeEZv+jFwa" + + "l41w5W4BH/gtbwGjFQ6CvF/m+lfUv6ZZdzsMIeEOwhP5g7rXBxrbcnGBaU+PXbho" + + "gjDqaYzAWGlrmAd6aPSj51AGeYXkb2T1T/yoJ++M3GvhH4C4hvitamDkksh/qRnM" + + "M/s8Nku6z1+RXO3M6p5QC1nlAVqieU8esT43945eSoC77K8WyujDNbysDyUCUTzt" + + "p/aoQwe/HgkeOTJNelKR9y2W3xinZLFzep0SqpNI/e468yB/2/LGsykIyQa7JX6r" + + "BYwuBAIDAkOKfv5rK8v0YDfnN+eFqwhTcrfBj5rDH7hER6nW3lNWcMataUiHEaMg" + + "o6Q0OO1vptIGxW8jClTD4N1sCNwNu9vKny8dKYDDHbCjE06DNTv7XYVW3+JqTL5E" + + "BnidvGgOmA=="); + + /** + * decrypt the passed in message stream + */ + private byte[] decryptMessage( + byte[] message, + Date date) + throws Exception + { + JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(message); + PGPEncryptedDataList enc = (PGPEncryptedDataList)pgpF.nextObject(); + PGPPBEEncryptedData pbe = (PGPPBEEncryptedData)enc.get(0); + + InputStream clear = pbe.getDataStream(new BcPBEDataDecryptorFactory(pass, new BcPGPDigestCalculatorProvider())); + + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(clear); + PGPCompressedData cData = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(cData.getDataStream()); + + PGPLiteralData ld = (PGPLiteralData)pgpFact.nextObject(); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + if (!ld.getFileName().equals("test.txt") + && !ld.getFileName().equals("_CONSOLE")) + { + fail("wrong filename in packet"); + } + if (!ld.getModificationTime().equals(date)) + { + fail("wrong modification time in packet: " + ld.getModificationTime().getTime() + " " + date.getTime()); + } + + InputStream unc = ld.getInputStream(); + int ch; + + while ((ch = unc.read()) >= 0) + { + bOut.write(ch); + } + + if (pbe.isIntegrityProtected() && !pbe.verify()) + { + fail("integrity check failed"); + } + + return bOut.toByteArray(); + } + + /** + * decrypt the passed in message stream, verifying the algorithm used. + */ + private byte[] decryptMessageCheck( + int algorithm, + byte[] message, + Date date) + throws Exception + { + JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(message); + PGPEncryptedDataList enc = (PGPEncryptedDataList)pgpF.nextObject(); + PGPPBEEncryptedData pbe = (PGPPBEEncryptedData)enc.get(0); + + if (algorithm != pbe.getSymmetricAlgorithm(new BcPBEDataDecryptorFactory(pass, new BcPGPDigestCalculatorProvider()))) + { + fail("algorithm mismatch"); + } + + InputStream clear = pbe.getDataStream(new BcPBEDataDecryptorFactory(pass, new BcPGPDigestCalculatorProvider())); + + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(clear); + PGPCompressedData cData = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(cData.getDataStream()); + + PGPLiteralData ld = (PGPLiteralData)pgpFact.nextObject(); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + if (!ld.getFileName().equals("test.txt") + && !ld.getFileName().equals("_CONSOLE")) + { + fail("wrong filename in packet"); + } + if (!ld.getModificationTime().equals(date)) + { + fail("wrong modification time in packet: " + ld.getModificationTime().getTime() + " " + date.getTime()); + } + + InputStream unc = ld.getInputStream(); + int ch; + + while ((ch = unc.read()) >= 0) + { + bOut.write(ch); + } + + if (pbe.isIntegrityProtected() && !pbe.verify()) + { + fail("integrity check failed"); + } + + return bOut.toByteArray(); + } + + private byte[] decryptMessageBuffered( + byte[] message, + Date date) + throws Exception + { + JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(message); + PGPEncryptedDataList enc = (PGPEncryptedDataList)pgpF.nextObject(); + PGPPBEEncryptedData pbe = (PGPPBEEncryptedData)enc.get(0); + + InputStream clear = pbe.getDataStream(new BcPBEDataDecryptorFactory(pass, new BcPGPDigestCalculatorProvider())); + + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(clear); + PGPCompressedData cData = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(cData.getDataStream()); + + PGPLiteralData ld = (PGPLiteralData)pgpFact.nextObject(); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + if (!ld.getFileName().equals("test.txt") + && !ld.getFileName().equals("_CONSOLE")) + { + fail("wrong filename in packet"); + } + if (!ld.getModificationTime().equals(date)) + { + fail("wrong modification time in packet: " + ld.getModificationTime().getTime() + " " + date.getTime()); + } + + InputStream unc = ld.getInputStream(); + byte[] buf = new byte[1024]; + int len; + + while ((len = unc.read(buf)) >= 0) + { + bOut.write(buf, 0, len); + } + + if (pbe.isIntegrityProtected() && !pbe.verify()) + { + fail("integrity check failed"); + } + + return bOut.toByteArray(); + } + + public void performTest() + throws Exception + { + byte[] out = decryptMessage(enc1, TEST_DATE); + + if (out[0] != 'h' || out[1] != 'e' || out[2] != 'l') + { + fail("wrong plain text in packet"); + } + + // + // create a PBE encrypted message and read it back. + // + byte[] text = { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)' ', (byte)'w', (byte)'o', (byte)'r', (byte)'l', (byte)'d', (byte)'!', (byte)'\n' }; + + // + // encryption step - convert to literal data, compress, encode. + // + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + Date cDate = new Date((System.currentTimeMillis() / 1000) * 1000); + PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator(); + OutputStream comOut = comData.open(new UncloseableOutputStream(bOut)); + OutputStream ldOut = lData.open( + new UncloseableOutputStream(comOut), + PGPLiteralData.BINARY, + PGPLiteralData.CONSOLE, + text.length, + cDate); + + ldOut.write(text); + + ldOut.close(); + + comOut.close(); + + // + // encrypt - with stream close + // + ByteArrayOutputStream cbOut = new ByteArrayOutputStream(); + PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setSecureRandom(new SecureRandom())); + + cPk.addMethod(new BcPBEKeyEncryptionMethodGenerator(pass)); + + OutputStream cOut = cPk.open(new UncloseableOutputStream(cbOut), bOut.toByteArray().length); + + cOut.write(bOut.toByteArray()); + + cOut.close(); + + out = decryptMessage(cbOut.toByteArray(), cDate); + + if (!areEqual(out, text)) + { + fail("wrong plain text in generated packet"); + } + + // + // encrypt - with generator close + // + cbOut = new ByteArrayOutputStream(); + cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setSecureRandom(new SecureRandom())); + + cPk.addMethod(new BcPBEKeyEncryptionMethodGenerator(pass)); + + cOut = cPk.open(new UncloseableOutputStream(cbOut), bOut.toByteArray().length); + + cOut.write(bOut.toByteArray()); + + cPk.close(); + + out = decryptMessage(cbOut.toByteArray(), cDate); + + if (!areEqual(out, text)) + { + fail("wrong plain text in generated packet"); + } + + // + // encrypt - partial packet style. + // + SecureRandom rand = new SecureRandom(); + byte[] test = new byte[1233]; + + rand.nextBytes(test); + + bOut = new ByteArrayOutputStream(); + + comData = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + comOut = comData.open(bOut); + lData = new PGPLiteralDataGenerator(); + + ldOut = lData.open(new UncloseableOutputStream(comOut), + PGPLiteralData.BINARY, PGPLiteralData.CONSOLE, TEST_DATE, + new byte[16]); + + + ldOut.write(test); + + ldOut.close(); + + comOut.close(); + + cbOut = new ByteArrayOutputStream(); + cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setSecureRandom(rand)); + + cPk.addMethod(new BcPBEKeyEncryptionMethodGenerator(pass)); + + cOut = cPk.open(new UncloseableOutputStream(cbOut), new byte[16]); + + cOut.write(bOut.toByteArray()); + + cOut.close(); + + out = decryptMessage(cbOut.toByteArray(), TEST_DATE); + if (!areEqual(out, test)) + { + fail("wrong plain text in generated packet"); + } + + // + // with integrity packet + // + cbOut = new ByteArrayOutputStream(); + cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(true).setSecureRandom(rand)); + + cPk.addMethod(new BcPBEKeyEncryptionMethodGenerator(pass)); + + cOut = cPk.open(new UncloseableOutputStream(cbOut), new byte[16]); + + cOut.write(bOut.toByteArray()); + + cOut.close(); + + out = decryptMessage(cbOut.toByteArray(), TEST_DATE); + if (!areEqual(out, test)) + { + fail("wrong plain text in generated packet"); + } + + // + // decrypt with buffering + // + out = decryptMessageBuffered(cbOut.toByteArray(), TEST_DATE); + if (!areEqual(out, test)) + { + fail("wrong plain text in buffer generated packet"); + } + + // + // sample message + // + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(testPBEAsym); + + PGPEncryptedDataList enc = (PGPEncryptedDataList)pgpFact.nextObject(); + + PGPPBEEncryptedData pbe = (PGPPBEEncryptedData)enc.get(1); + + InputStream clear = pbe.getDataStream(new BcPBEDataDecryptorFactory("password".toCharArray(), new BcPGPDigestCalculatorProvider())); + + pgpFact = new JcaPGPObjectFactory(clear); + + PGPLiteralData ld = (PGPLiteralData)pgpFact.nextObject(); + + bOut = new ByteArrayOutputStream(); + InputStream unc = ld.getInputStream(); + int ch; + + while ((ch = unc.read()) >= 0) + { + bOut.write(ch); + } + + if (!areEqual(bOut.toByteArray(), Hex.decode("5361742031302e30322e30370d0a"))) + { + fail("data mismatch on combined PBE"); + } + + // + // with integrity packet - one byte message + // + byte[] msg = new byte[1]; + bOut = new ByteArrayOutputStream(); + + comData = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + lData = new PGPLiteralDataGenerator(); + comOut = comData.open(new UncloseableOutputStream(bOut)); + ldOut = lData.open( + new UncloseableOutputStream(comOut), + PGPLiteralData.BINARY, + PGPLiteralData.CONSOLE, + msg.length, + cDate); + + ldOut.write(msg); + + ldOut.close(); + + comOut.close(); + + cbOut = new ByteArrayOutputStream(); + cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(true).setSecureRandom(rand)); + + cPk.addMethod(new BcPBEKeyEncryptionMethodGenerator(pass)); + + cOut = cPk.open(new UncloseableOutputStream(cbOut), new byte[16]); + + cOut.write(bOut.toByteArray()); + + cOut.close(); + + out = decryptMessage(cbOut.toByteArray(), cDate); + if (!areEqual(out, msg)) + { + fail("wrong plain text in generated packet"); + } + + // + // decrypt with buffering + // + out = decryptMessageBuffered(cbOut.toByteArray(), cDate); + if (!areEqual(out, msg)) + { + fail("wrong plain text in buffer generated packet"); + } + + tryAlgorithm(PGPEncryptedData.AES_128, text); + //tryAlgorithm(PGPEncryptedData.CAMELLIA_128, text); + } + + private void tryAlgorithm(int algorithm, byte[] text) + throws Exception + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + Date cDate = new Date((System.currentTimeMillis() / 1000) * 1000); + PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator(); + OutputStream comOut = comData.open(new UncloseableOutputStream(bOut)); + OutputStream ldOut = lData.open( + new UncloseableOutputStream(comOut), + PGPLiteralData.BINARY, + PGPLiteralData.CONSOLE, + text.length, + cDate); + + ldOut.write(text); + + ldOut.close(); + + comOut.close(); + + ByteArrayOutputStream cbOut = new ByteArrayOutputStream(); + PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(algorithm).setSecureRandom(new SecureRandom())); + + cPk.addMethod(new BcPBEKeyEncryptionMethodGenerator(pass)); + + OutputStream cOut = cPk.open(new UncloseableOutputStream(cbOut), bOut.toByteArray().length); + + cOut.write(bOut.toByteArray()); + + cOut.close(); + + byte[] out = decryptMessageCheck(algorithm, cbOut.toByteArray(), cDate); + + if (!areEqual(out, text)) + { + fail("wrong plain text in generated packet"); + } + } + + public String getName() + { + return "BcPGPPBETest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new BcPGPPBETest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/BcPGPRSATest.java b/pg/src/test/java/org/spongycastle/openpgp/test/BcPGPRSATest.java new file mode 100644 index 00000000..86ce820d --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/BcPGPRSATest.java @@ -0,0 +1,1377 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Date; +import java.util.Iterator; + +import javax.crypto.Cipher; + +import org.spongycastle.bcpg.BCPGOutputStream; +import org.spongycastle.bcpg.CompressionAlgorithmTags; +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.bcpg.PublicKeyAlgorithmTags; +import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.spongycastle.bcpg.attr.ImageAttribute; +import org.spongycastle.bcpg.sig.Features; +import org.spongycastle.bcpg.sig.KeyFlags; +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.generators.RSAKeyPairGenerator; +import org.spongycastle.crypto.params.RSAKeyGenerationParameters; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPCompressedData; +import org.spongycastle.openpgp.PGPCompressedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedData; +import org.spongycastle.openpgp.PGPEncryptedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedDataList; +import org.spongycastle.openpgp.PGPKeyPair; +import org.spongycastle.openpgp.PGPKeyRingGenerator; +import org.spongycastle.openpgp.PGPLiteralData; +import org.spongycastle.openpgp.PGPLiteralDataGenerator; +import org.spongycastle.openpgp.PGPObjectFactory; +import org.spongycastle.openpgp.PGPOnePassSignature; +import org.spongycastle.openpgp.PGPOnePassSignatureList; +import org.spongycastle.openpgp.PGPPBEEncryptedData; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVectorGenerator; +import org.spongycastle.openpgp.PGPUtil; +import org.spongycastle.openpgp.PGPV3SignatureGenerator; +import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory; +import org.spongycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.bc.BcPBEDataDecryptorFactory; +import org.spongycastle.openpgp.operator.bc.BcPBEKeyEncryptionMethodGenerator; +import org.spongycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder; +import org.spongycastle.openpgp.operator.bc.BcPBESecretKeyEncryptorBuilder; +import org.spongycastle.openpgp.operator.bc.BcPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder; +import org.spongycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; +import org.spongycastle.openpgp.operator.bc.BcPGPKeyPair; +import org.spongycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory; +import org.spongycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyConverter; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; +import org.spongycastle.util.test.UncloseableOutputStream; + +public class BcPGPRSATest + extends SimpleTest +{ + byte[] testPubKey = Base64.decode( + "mIsEPz2nJAEEAOTVqWMvqYE693qTgzKv/TJpIj3hI8LlYPC6m1dk0z3bDLwVVk9F" + + "FAB+CWS8RdFOWt/FG3tEv2nzcoNdRvjv9WALyIGNawtae4Ml6oAT06/511yUzXHO" + + "k+9xK3wkXN5jdzUhf4cA2oGpLSV/pZlocsIDL+jCUQtumUPwFodmSHhzAAYptC9F" + + "cmljIEVjaGlkbmEgKHRlc3Qga2V5KSA8ZXJpY0Bib3VuY3ljYXN0bGUub3JnPoi4" + + "BBMBAgAiBQI/PackAhsDBQkAg9YABAsHAwIDFQIDAxYCAQIeAQIXgAAKCRA1WGFG" + + "/fPzc8WMA/9BbjuB8E48QAlxoiVf9U8SfNelrz/ONJA/bMvWr/JnOGA9PPmFD5Uc" + + "+kV/q+i94dEMjsC5CQ1moUHWSP2xlQhbOzBP2+oPXw3z2fBs9XJgnTH6QWMAAvLs" + + "3ug9po0loNHLobT/D/XdXvcrb3wvwvPT2FptZqrtonH/OdzT9JdfrA=="); + + byte[] testPrivKey = Base64.decode( + "lQH8BD89pyQBBADk1aljL6mBOvd6k4Myr/0yaSI94SPC5WDwuptXZNM92wy8FVZP" + + "RRQAfglkvEXRTlrfxRt7RL9p83KDXUb47/VgC8iBjWsLWnuDJeqAE9Ov+ddclM1x" + + "zpPvcSt8JFzeY3c1IX+HANqBqS0lf6WZaHLCAy/owlELbplD8BaHZkh4cwAGKf4D" + + "AwKbLeIOVYTEdWD5v/YgW8ERs0pDsSIfBTvsJp2qA798KeFuED6jGsHUzdi1M990" + + "6PRtplQgnoYmYQrzEc6DXAiAtBR4Kuxi4XHx0ZR2wpVlVxm2Ypgz7pbBNWcWqzvw" + + "33inl7tR4IDsRdJOY8cFlN+1tSCf16sDidtKXUVjRjZNYJytH18VfSPlGXMeYgtw" + + "3cSGNTERwKaq5E/SozT2MKTiORO0g0Mtyz+9MEB6XVXFavMun/mXURqbZN/k9BFb" + + "z+TadpkihrLD1xw3Hp+tpe4CwPQ2GdWKI9KNo5gEnbkJgLrSMGgWalPhknlNHRyY" + + "bSq6lbIMJEE3LoOwvYWwweR1+GrV9farJESdunl1mDr5/d6rKru+FFDwZM3na1IF" + + "4Ei4FpqhivZ4zG6pN5XqLy+AK85EiW4XH0yAKX1O4YlbmDU4BjxhiwTdwuVMCjLO" + + "5++jkz5BBQWdFX8CCMA4FJl36G70IbGzuFfOj07ly7QvRXJpYyBFY2hpZG5hICh0" + + "ZXN0IGtleSkgPGVyaWNAYm91bmN5Y2FzdGxlLm9yZz6IuAQTAQIAIgUCPz2nJAIb" + + "AwUJAIPWAAQLBwMCAxUCAwMWAgECHgECF4AACgkQNVhhRv3z83PFjAP/QW47gfBO" + + "PEAJcaIlX/VPEnzXpa8/zjSQP2zL1q/yZzhgPTz5hQ+VHPpFf6voveHRDI7AuQkN" + + "ZqFB1kj9sZUIWzswT9vqD18N89nwbPVyYJ0x+kFjAALy7N7oPaaNJaDRy6G0/w/1" + + "3V73K298L8Lz09habWaq7aJx/znc0/SXX6w="); + + byte[] testPubKeyV3 = Base64.decode( + "mQCNAz+zvlEAAAEEAMS22jgXbOZ/D3xWgM2kauSdzrwlU7Ms5hDW05ObqQyO" + + "FfQoKKMhfupyoa7J3x04VVBKu6Eomvr1es+VImH0esoeWFFahNOYq/I+jRRB" + + "woOhAGZ5UB2/hRd7rFmxqp6sCXi8wmLO2tAorlTzAiNNvl7xF4cQZpc0z56F" + + "wdi2fBUJAAURtApGSVhDSVRZX1FBiQCVAwUQP7O+UZ6Fwdi2fBUJAQFMwwQA" + + "qRnFsdg4xQnB8Y5d4cOpXkIn9AZgYS3cxtuSJB84vG2CgC39nfv4c+nlLkWP" + + "4puG+mZuJNgVoE84cuAF4I//1anKjlU7q1M6rFQnt5S4uxPyG3dFXmgyU1b4" + + "PBOnA0tIxjPzlIhJAMsPCGGA5+5M2JP0ad6RnzqzE3EENMX+GqY="); + + byte[] testPrivKeyV3 = Base64.decode( + "lQHfAz+zvlEAAAEEAMS22jgXbOZ/D3xWgM2kauSdzrwlU7Ms5hDW05ObqQyO" + + "FfQoKKMhfupyoa7J3x04VVBKu6Eomvr1es+VImH0esoeWFFahNOYq/I+jRRB" + + "woOhAGZ5UB2/hRd7rFmxqp6sCXi8wmLO2tAorlTzAiNNvl7xF4cQZpc0z56F" + + "wdi2fBUJAAURAXWwRBZQHNikA/f0ScLLjrXi4s0hgQecg+dkpDow94eu5+AR" + + "0DzZnfurpgfUJCNiDi5W/5c3Zj/xyrfMAgkbCgJ1m6FZqAQh7Mq73l7Kfu4/" + + "XIkyDF3tDgRuZNezB+JuElX10tV03xumHepp6M6CfhXqNJ15F33F99TA5hXY" + + "CPYD7SiSOpIhQkCOAgDAA63imxbpuKE2W7Y4I1BUHB7WQi8ZdkZd04njNTv+" + + "rFUuOPapQVfbWG0Vq8ld3YmJB4QWsa2mmqn+qToXbwufAgBpXkjvqK5yPiHF" + + "Px2QbFc1VqoCJB6PO5JRIqEiUZBFGdDlLxt3VSyqz7IZ/zEnxZq+tPCGGGSm" + + "/sAGiMvENcHVAfy0kTXU42TxEAYJyyNyqjXOobDJpEV1mKhFskRXt7tbMfOS" + + "Yf91oX8f6xw6O2Nal+hU8dS0Bmfmk5/enHmvRLHQocO0CkZJWENJVFlfUUE="); + + byte[] sig1 = Base64.decode( + "owGbwMvMwMRoGpHo9vfz52LGNTJJnBmpOTn5eiUVJfb23JvAHIXy/KKcFEWuToap" + + "zKwMIGG4Bqav0SwMy3yParsEKi2LMGI9xhh65sBxb05n5++ZLcWNJ/eLFKdWbm95" + + "tHbDV7GMwj/tUctUpFUXWPYFCLdNsDiVNuXbQvZtdXV/5xzY+9w1nCnijH9JoNiJ" + + "22n2jo0zo30/TZLo+jDl2vTzIvPeLEsPM3ZUE/1Ytqs4SG2TxIQbH7xf3uzcYXq2" + + "5Fw9AA=="); + + byte[] sig1crc = Base64.decode("+3i0"); + + byte[] subKey = Base64.decode( + "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" + + "CphiUYWnsC0mQ+J15B4="); + + byte[] enc1 = Base64.decode( + "hIwDKwfQexPJboABA/4/7prhYYMORTiQ5avQKx0XYpCLujzGefYjnyuWZnx3Iev8" + + "Pmsguumm+OLLvtXhhkXQmkJRXbIg6Otj2ubPYWflRPgpJSgOrNOreOl5jeABOrtw" + + "bV6TJb9OTtZuB7cTQSCq2gmYiSZkluIiDjNs3R3mEanILbYzOQ3zKSggKpzlv9JQ" + + "AZUqTyDyJ6/OUbJF5fI5uiv76DCsw1zyMWotUIu5/X01q+AVP5Ly3STzI7xkWg/J" + + "APz4zUHism7kSYz2viAQaJx9/bNnH3AM6qm1Fuyikl4="); + + byte[] enc1crc = Base64.decode("lv4o"); + + byte[] enc2 = Base64.decode( + "hIwDKwfQexPJboABBAC62jcJH8xKnKb1neDVmiovYON04+7VQ2v4BmeHwJrdag1g" + + "Ya++6PeBlQ2Q9lSGBwLobVuJmQ7cOnPUJP727JeSGWlMyFtMbBSHekOaTenT5lj7" + + "Zk7oRHxMp/hByzlMacIDzOn8LPSh515RHM57eDLCOwqnAxGQwk67GRl8f5dFH9JQ" + + "Aa7xx8rjCqPbiIQW6t5LqCNvPZOiSCmftll6+se1XJhFEuq8WS4nXtPfTiJ3vib4" + + "3soJdHzGB6AOs+BQ6aKmmNTVAxa5owhtSt1Z/6dfSSk="); + + byte[] subPubKey = Base64.decode( + "mIsEPz2nJAEEAOTVqWMvqYE693qTgzKv/TJpIj3hI8LlYPC6m1dk0z3bDLwVVk9F" + + "FAB+CWS8RdFOWt/FG3tEv2nzcoNdRvjv9WALyIGNawtae4Ml6oAT06/511yUzXHO" + + "k+9xK3wkXN5jdzUhf4cA2oGpLSV/pZlocsIDL+jCUQtumUPwFodmSHhzAAYptC9F" + + "cmljIEVjaGlkbmEgKHRlc3Qga2V5KSA8ZXJpY0Bib3VuY3ljYXN0bGUub3JnPoi4" + + "BBMBAgAiBQI/PackAhsDBQkAg9YABAsHAwIDFQIDAxYCAQIeAQIXgAAKCRA1WGFG" + + "/fPzc8WMA/9BbjuB8E48QAlxoiVf9U8SfNelrz/ONJA/bMvWr/JnOGA9PPmFD5Uc" + + "+kV/q+i94dEMjsC5CQ1moUHWSP2xlQhbOzBP2+oPXw3z2fBs9XJgnTH6QWMAAvLs" + + "3ug9po0loNHLobT/D/XdXvcrb3wvwvPT2FptZqrtonH/OdzT9JdfrIhMBBARAgAM" + + "BQI/RxooBYMAemL8AAoJEM0j9enEyjRDiBgAn3RcLK+gq90PvnQFTw2DNqdq7KA0" + + "AKCS0EEIXCzbV1tfTdCUJ3hVh3btF7QkRXJpYyBFY2hpZG5hIDxlcmljQGJvdW5j" + + "eWNhc3RsZS5vcmc+iLgEEwECACIFAj9HFA0CGwMFCQCD1gAECwcDAgMVAgMDFgIB" + + "Ah4BAheAAAoJEDVYYUb98/Nzc7oD/j21cUKKI/y+Dvs5e+eZufM8EDUbqMJFk0/X" + + "Ihe6w6OkerIs3kr2HDqWr+jik2IK6KrfaiyoZFfeW/+cN24lTWSfY7D4jZVyL6iM" + + "xd0IZ0So/Bl+/juMcvBGshQnbY46haw5G2C9J5FR3gjODyOu5oUzu5+vmGuMSXVy" + + "4tbUevwuiEwEEBECAAwFAj9HGigFgwB6YvwACgkQzSP16cTKNEPwBQCdHm0Amwza" + + "NmVmDHm3rmqI7rp2oQ0An2YbiP/H/kmBNnmTeH55kd253QOhuIsEP0ccUAEEANCd" + + "gSHam/CbQxio72Ma47tLqyVVc8iNQpwowKewrS6B0CVEFOz2o51eCXddrpH3KCuz" + + "Ea2mMnUBI8YdjKj6bkICUt3YEFa8Tj2qw0GARa2TXdrWcTo2GpIRK71JkaOslhWs" + + "QocKjIJfF1roATYNQ72vv2HKBkPpcviYOEVmaB/PAAYpiJ8EGAECAAkFAj9HHFAC" + + "GwwACgkQNVhhRv3z83M5hQP8DIOR4TeTZKpo5x1BX3lzV3R85npMsN/EZ7gjCpn3" + + "ONwIg7PhbSetoKUOjxLGReKPUuX8XI1ZN1UoNNFzA7UP9AbCgXORsYSU6uxvv0qH" + + "jON91htfbqEtPuS3/99cDaE56b+p6TmmKXE0Oy/Swp88ABeB9ISTxOm4ZltgjHLB" + + "PyGZAaIEP0cHNREEALOTFEJUYmDn4t30NThemd3gsIqAyrtg5jsaLQSAr3aBtprr" + + "7NChAWrPW23dBSanPdhWSb/MsRIEG0LUAIhcaCBR0UxSvkjzv7UJvq/N58C0a3w3" + + "lVXUX8xe/WAnPgG7ofLEv+dx97vWOw2Fq/SLjICN/Z61YWPnfMrpH46ODkfrAKCk" + + "v3+1dV8Y/xKoW/Ks3/jfsyUVJQQAg3dXqP8xSWXKtmCWu2vb5FYjBGsb8AKasXqF" + + "O6A6XhxDFoNg1ye1duGVOUmz0zGNMffHHPKXKKsLKrsfMYnFnNK3oVN6HUMVjOEn" + + "tC5hHXGtJ0DpjSZS/SLEPkDic8eO6lDlAKocZ5F8UP+gfMPjOoGcmn8Encu9Drps" + + "REmYqXkD/i6PcehXGlvS+/IQ19GooyYYEhLJxjgygfm5Z9vbcV9+xP2v0ovqcniz" + + "IvNpFHSC9xtyORz1nd6kjuCveNOtvh3xY/GwNtP9bW2/1sb8QdrCiYtyKG25RTrx" + + "R6Pr/Bmi3Vcmq7adCWS7nv4z9XZfXLbpUqyKmiU9+Nri7IE47K9stDNFcmljIEVj" + + "aGlkbmEgKERTQSBUZXN0IEtleSkgPGVyaWNAYm91bmN5Y2FzdGxlLm9yZz6IWQQT" + + "EQIAGQUCP0cHNQQLBwMCAxUCAwMWAgECHgECF4AACgkQzSP16cTKNEMCXACfauui" + + "bSwyG59Yrm8hHCDuCPmqwsQAni+dPl08FVuWh+wb6kOgJV4lcYae"); + + byte[] subPubCrc = Base64.decode("rikt"); + + byte[] pgp8Key = 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[] pgp8Pass = "2002 Buffalo Sabres".toCharArray(); + + char[] pass = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' }; + + byte[] fingerprintKey = Base64.decode( + "mQEPA0CiJdUAAAEIAMI+znDlPd2kQoEcnxqxLcRz56Z7ttFKHpnYp0UkljZdquVc" + + "By1jMfXGVV64xN1IvMcyenLXUE0IUeUBCQs6tHunFRAPSeCxJ3FdFe1B5MpqQG8A" + + "BnEpAds/hAUfRDZD5y/lolk1hjvFMrRh6WXckaA/QQ2t00NmTrJ1pYUpkw9tnVQb" + + "LUjWJhfZDBBcN0ADtATzgkugxMtcDxR6I5x8Ndn+IilqIm23kxGIcmMd/BHOec4c" + + "jRwJXXDb7u8tl+2knAf9cwhPHp3+Zy4uGSQPdzQnXOhBlA+4WDa0RROOevWgq8uq" + + "8/9Xp/OlTVL+OoIzjsI6mJP1Joa4qmqAnaHAmXcAEQEAAbQoQk9BM1JTS1kgPEJP" + + "QSBNb25pdG9yaW5nIEAgODg4LTI2OS01MjY2PokBFQMFEECiJdWqaoCdocCZdwEB" + + "0RsH/3HPxoUZ3G3K7T3jgOnJUckTSHWU3XspHzMVgqOxjTrcexi5IsAM5M+BulfW" + + "T2aO+Kqf5w8cKTKgW02DNpHUiPjHx0nzDE+Do95zbIErGeK+Twkc4O/aVsvU9GGO" + + "81VFI6WMvDQ4CUAUnAdk03MRrzI2nAuhn4NJ5LQS+uJrnqUJ4HmFAz6CQZQKd/kS" + + "Xgq+A6i7aI1LG80YxWa9ooQgaCrb9dwY/kPQ+yC22zQ3FExtv+Fv3VtAKTilO3vn" + + "BA4Y9uTHuObHfI+1yxUS2PrlRUX0m48ZjpIX+cEN3QblGBJudI/A1QSd6P0LZeBr" + + "7F1Z1aF7ZDo0KzgiAIBvgXkeTpw="); + + byte[] fingerprintCheck = Base64.decode("CTv2"); + + byte[] expiry60and30daysSig13Key = Base64.decode( + "mQGiBENZt/URBAC5JccXiwe4g6MuviEC8NI/x0NaVkGFAOY04d5E4jeIycBP" + + "SrpOPrjETuigqhrj8oqed2+2yUqfnK4nhTsTAjyeJ3PpWC1pGAKzJgYmJk+K" + + "9aTLq0BQWiXDdv5RG6fDmeq1umvOfcXBqGFAguLPZC+U872bSLnfe3lqGNA8" + + "jvmY7wCgjhzVQVm10NN5ST8nemPEcSjnBrED/R494gHL6+r5OgUgXnNCDejA" + + "4InoDImQCF+g7epp5E1MB6CMYSg2WSY2jHFuHpwnUb7AiOO0ZZ3UBqM9rYnK" + + "kDvxkFCxba7Ms+aFj9blRNmy3vG4FewDcTdxzCtjUk6dRfu6UoARpqlTE/q7" + + "Xo6EQP1ncwJ+UTlcHkTBvg/usI/yBACGjBqX8glb5VfNaZgNHMeS/UIiUiuV" + + "SVFojiSDOHcnCe/6y4M2gVm38zz1W9qhoLfLpiAOFeL0yj6wzXvsjjXQiKQ8" + + "nBE4Mf+oeH2qiQ/LfzQrGpI5eNcMXrzK9nigmz2htYO2GjQfupEnu1RHBTH8" + + "NjofD2AShL9IO73plRuExrQgVGVzdCBLZXkgPHRlc3RAYm91bmN5Y2FzdGxl" + + "Lm9yZz6IZAQTEQIAJAIbAwYLCQgHAwIDFQIDAxYCAQIeAQIXgAUCQ1m4DgUJ" + + "AE8aGQAKCRD8QP1QuU7Kqw+eAJ0dZ3ZAqr73X61VmCkbyPoszLQMAQCfdFs2" + + "YMDeUvX34Q/8Ba0KgO5f3RSwAgADuM0EQ1m39hADAIHpVGcLqS9UkmQaWBvH" + + "WP6TnN7Y1Ha0TJOuxpbFjBW+CmVh/FjcsnavFXDXpo2zc742WT+vrHBSa/0D" + + "1QEBsnCaX5SRRVp7Mqs8q+aDhjcHMIP8Sdxf7GozXDORkrRaJwADBQL9HLYm" + + "7Rr5iYWDcvs+Pi6O1zUyb1tjkxEGaV/rcozl2MMmr2mzJ6x/Bz8SuhZEJS0m" + + "bB2CvAA39aQi9jHlV7q0SV73NOkd2L/Vt2UZhzlUdvrJ37PgYDv+Wd9Ufz6g" + + "MzLSiE8EGBECAA8FAkNZt/YCGwwFCQAnjQAACgkQ/ED9ULlOyqsTqQCcDnAZ" + + "7YymCfhm1yJiuFQg3qiX6Z4An19OSEgeSKugVcH49g1sxUB0zNdIsAIAAw=="); + + byte[] jpegImage = Base64.decode( + "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"); + + byte[] embeddedJPEGKey = Base64.decode( + "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" + + "Qvmtc8X7lqK/zLRVkSSBItik2IIhsAIAAw=="); + + + private void fingerPrintTest() + throws Exception + { + // + // version 3 + // + PGPPublicKeyRing pgpPub = new PGPPublicKeyRing(fingerprintKey, new BcKeyFingerprintCalculator()); + + PGPPublicKey pubKey = pgpPub.getPublicKey(); + + if (!areEqual(pubKey.getFingerprint(), Hex.decode("4FFB9F0884266C715D1CEAC804A3BBFA"))) + { + fail("version 3 fingerprint test failed"); + } + + // + // version 4 + // + pgpPub = new PGPPublicKeyRing(testPubKey, new BcKeyFingerprintCalculator()); + + pubKey = pgpPub.getPublicKey(); + + if (!areEqual(pubKey.getFingerprint(), Hex.decode("3062363c1046a01a751946bb35586146fdf3f373"))) + { + fail("version 4 fingerprint test failed"); + } + } + + private void mixedTest(PGPPrivateKey pgpPrivKey, PGPPublicKey pgpPubKey) + throws Exception + { + byte[] text = { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)' ', (byte)'w', (byte)'o', (byte)'r', (byte)'l', (byte)'d', (byte)'!', (byte)'\n' }; + + // + // literal data + // + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); + OutputStream lOut = lGen.open(bOut, PGPLiteralData.BINARY, PGPLiteralData.CONSOLE, text.length, new Date()); + + lOut.write(text); + + lGen.close(); + + byte[] bytes = bOut.toByteArray(); + + PGPObjectFactory f = new PGPObjectFactory(bytes, new BcKeyFingerprintCalculator()); + checkLiteralData((PGPLiteralData)f.nextObject(), text); + + ByteArrayOutputStream bcOut = new ByteArrayOutputStream(); + + PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_128).setWithIntegrityPacket(true).setSecureRandom(new SecureRandom())); + + encGen.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(pgpPubKey)); + + encGen.addMethod(new BcPBEKeyEncryptionMethodGenerator("password".toCharArray())); + + OutputStream cOut = encGen.open(bcOut, bytes.length); + + cOut.write(bytes); + + cOut.close(); + + byte[] encData = bcOut.toByteArray(); + + // + // asymmetric + // + PGPObjectFactory pgpF = new PGPObjectFactory(encData, new BcKeyFingerprintCalculator()); + + PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpF.nextObject(); + + PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0); + + InputStream clear = encP.getDataStream(new BcPublicKeyDataDecryptorFactory(pgpPrivKey)); + + PGPObjectFactory pgpFact = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator()); + + checkLiteralData((PGPLiteralData)pgpFact.nextObject(), text); + + // + // PBE + // + pgpF = new PGPObjectFactory(encData, new BcKeyFingerprintCalculator()); + + encList = (PGPEncryptedDataList)pgpF.nextObject(); + + PGPPBEEncryptedData encPbe = (PGPPBEEncryptedData)encList.get(1); + + clear = encPbe.getDataStream(new BcPBEDataDecryptorFactory("password".toCharArray(), new BcPGPDigestCalculatorProvider())); + + pgpF = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator()); + + checkLiteralData((PGPLiteralData)pgpF.nextObject(), text); + } + + private void checkLiteralData(PGPLiteralData ld, byte[] data) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + if (!ld.getFileName().equals(PGPLiteralData.CONSOLE)) + { + throw new RuntimeException("wrong filename in packet"); + } + + InputStream inLd = ld.getDataStream(); + int ch; + + while ((ch = inLd.read()) >= 0) + { + bOut.write(ch); + } + + if (!areEqual(bOut.toByteArray(), data)) + { + fail("wrong plain text in decrypted packet"); + } + } + + private void existingEmbeddedJpegTest() + throws Exception + { + PGPPublicKeyRing pgpPub = new PGPPublicKeyRing(embeddedJPEGKey, new BcKeyFingerprintCalculator()); + + PGPPublicKey pubKey = pgpPub.getPublicKey(); + + Iterator it = pubKey.getUserAttributes(); + int count = 0; + while (it.hasNext()) + { + PGPUserAttributeSubpacketVector attributes = (PGPUserAttributeSubpacketVector)it.next(); + + Iterator sigs = pubKey.getSignaturesForUserAttribute(attributes); + int sigCount = 0; + while (sigs.hasNext()) + { + PGPSignature sig = (PGPSignature)sigs.next(); + + sig.init(new BcPGPContentVerifierBuilderProvider(), pubKey); + + if (!sig.verifyCertification(attributes, pubKey)) + { + fail("signature failed verification"); + } + + sigCount++; + } + + if (sigCount != 1) + { + fail("Failed user attributes signature check"); + } + count++; + } + + if (count != 1) + { + fail("didn't find user attributes"); + } + } + + private void embeddedJpegTest() + throws Exception + { + PGPPublicKeyRing pgpPub = new PGPPublicKeyRing(testPubKey, new BcKeyFingerprintCalculator()); + PGPSecretKeyRing pgpSec = new PGPSecretKeyRing(testPrivKey, new BcKeyFingerprintCalculator()); + + PGPPublicKey pubKey = pgpPub.getPublicKey(); + + PGPUserAttributeSubpacketVectorGenerator vGen = new PGPUserAttributeSubpacketVectorGenerator(); + + vGen.setImageAttribute(ImageAttribute.JPEG, jpegImage); + + PGPUserAttributeSubpacketVector uVec = vGen.generate(); + + PGPSignatureGenerator sGen = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1)); + + sGen.init(PGPSignature.POSITIVE_CERTIFICATION, pgpSec.getSecretKey().extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass))); + + PGPSignature sig = sGen.generateCertification(uVec, pubKey); + + PGPPublicKey nKey = PGPPublicKey.addCertification(pubKey, uVec, sig); + + Iterator it = nKey.getUserAttributes(); + int count = 0; + while (it.hasNext()) + { + PGPUserAttributeSubpacketVector attributes = (PGPUserAttributeSubpacketVector)it.next(); + + Iterator sigs = nKey.getSignaturesForUserAttribute(attributes); + int sigCount = 0; + while (sigs.hasNext()) + { + PGPSignature s = (PGPSignature)sigs.next(); + + s.init(new BcPGPContentVerifierBuilderProvider(), pubKey); + + if (!s.verifyCertification(attributes, pubKey)) + { + fail("added signature failed verification"); + } + + sigCount++; + } + + if (sigCount != 1) + { + fail("Failed added user attributes signature check"); + } + count++; + } + + if (count != 1) + { + fail("didn't find added user attributes"); + } + + nKey = PGPPublicKey.removeCertification(nKey, uVec); + count = 0; + for (it = nKey.getUserAttributes(); it.hasNext();) + { + count++; + } + if (count != 0) + { + fail("found attributes where none expected"); + } + } + + private void sigsubpacketTest() + throws Exception + { + char[] passPhrase = "test".toCharArray(); + String identity = "TEST <test@test.org>"; + Date date = new Date(); + + RSAKeyPairGenerator kpg = new RSAKeyPairGenerator(); + kpg.init(new RSAKeyGenerationParameters(BigInteger.valueOf(0x11), new SecureRandom(), 2048, 25)); + AsymmetricCipherKeyPair kpSgn = kpg.generateKeyPair(); + AsymmetricCipherKeyPair kpEnc = kpg.generateKeyPair(); + + PGPKeyPair sgnKeyPair = new BcPGPKeyPair(PGPPublicKey.RSA_SIGN, kpSgn, date); + PGPKeyPair encKeyPair = new BcPGPKeyPair(PGPPublicKey.RSA_GENERAL, kpEnc, date); + + PGPSignatureSubpacketVector unhashedPcks = null; + PGPSignatureSubpacketGenerator svg = new PGPSignatureSubpacketGenerator(); + svg.setKeyExpirationTime(true, 86400L * 366 * 2); + svg.setPrimaryUserID(true, true); + int[] encAlgs = {SymmetricKeyAlgorithmTags.AES_256, + SymmetricKeyAlgorithmTags.AES_192, + SymmetricKeyAlgorithmTags.TRIPLE_DES}; + svg.setPreferredSymmetricAlgorithms(true, encAlgs); + int[] hashAlgs = {HashAlgorithmTags.SHA1, + HashAlgorithmTags.SHA512, + HashAlgorithmTags.SHA384, + HashAlgorithmTags.SHA256, + HashAlgorithmTags.RIPEMD160}; + svg.setPreferredHashAlgorithms(true, hashAlgs); + int[] comprAlgs = {CompressionAlgorithmTags.ZLIB, + CompressionAlgorithmTags.BZIP2, + CompressionAlgorithmTags.ZIP}; + svg.setPreferredCompressionAlgorithms(true, comprAlgs); + svg.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION); + svg.setKeyFlags(true, KeyFlags.CERTIFY_OTHER + KeyFlags.SIGN_DATA); + PGPSignatureSubpacketVector hashedPcks = svg.generate(); + + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, + sgnKeyPair, identity, new BcPGPDigestCalculatorProvider().get(HashAlgorithmTags.SHA1), + hashedPcks, unhashedPcks, new BcPGPContentSignerBuilder(PGPPublicKey.RSA_GENERAL, HashAlgorithmTags.SHA1), new BcPBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256).build(passPhrase)); + + svg = new PGPSignatureSubpacketGenerator(); + svg.setKeyExpirationTime(true, 86400L * 366 * 2); + svg.setKeyFlags(true, KeyFlags.ENCRYPT_COMMS + KeyFlags.ENCRYPT_STORAGE); + svg.setPrimaryUserID(true, false); + svg.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION); + hashedPcks = svg.generate(); + + keyRingGen.addSubKey(encKeyPair, hashedPcks, unhashedPcks); + + byte[] encodedKeyRing = keyRingGen.generatePublicKeyRing().getEncoded(); + + PGPPublicKeyRing keyRing = new PGPPublicKeyRing(encodedKeyRing, new BcKeyFingerprintCalculator()); + + for (Iterator it = keyRing.getPublicKeys(); it.hasNext();) + { + PGPPublicKey pKey = (PGPPublicKey)it.next(); + + if (pKey.isEncryptionKey()) + { + for (Iterator sit = pKey.getSignatures(); sit.hasNext();) + { + PGPSignature sig = (PGPSignature)sit.next(); + PGPSignatureSubpacketVector v = sig.getHashedSubPackets(); + + if (v.getKeyExpirationTime() != 86400L * 366 * 2) + { + fail("key expiration time wrong"); + } + if (!v.getFeatures().supportsFeature(Features.FEATURE_MODIFICATION_DETECTION)) + { + fail("features wrong"); + } + if (v.isPrimaryUserID()) + { + fail("primary userID flag wrong"); + } + if (v.getKeyFlags() != KeyFlags.ENCRYPT_COMMS + KeyFlags.ENCRYPT_STORAGE) + { + fail("keyFlags wrong"); + } + } + } + else + { + for (Iterator sit = pKey.getSignatures(); sit.hasNext();) + { + PGPSignature sig = (PGPSignature)sit.next(); + PGPSignatureSubpacketVector v = sig.getHashedSubPackets(); + + if (!Arrays.areEqual(v.getPreferredSymmetricAlgorithms(), encAlgs)) + { + fail("preferred encryption algs don't match"); + } + if (!Arrays.areEqual(v.getPreferredHashAlgorithms(), hashAlgs)) + { + fail("preferred hash algs don't match"); + } + if (!Arrays.areEqual(v.getPreferredCompressionAlgorithms(), comprAlgs)) + { + fail("preferred compression algs don't match"); + } + if (!v.getFeatures().supportsFeature(Features.FEATURE_MODIFICATION_DETECTION)) + { + fail("features wrong"); + } + if (v.getKeyFlags() != KeyFlags.CERTIFY_OTHER + KeyFlags.SIGN_DATA) + { + fail("keyFlags wrong"); + } + } + } + } + } + + public void performTest() + throws Exception + { + PublicKey pubKey = null; + + // + // Read the public key + // + PGPPublicKeyRing pgpPub = new PGPPublicKeyRing(testPubKey, new BcKeyFingerprintCalculator()); + + pubKey = new JcaPGPKeyConverter().setProvider("SC").getPublicKey(pgpPub.getPublicKey()); + + Iterator it = pgpPub.getPublicKey().getUserIDs(); + + String uid = (String)it.next(); + + it = pgpPub.getPublicKey().getSignaturesForID(uid); + + PGPSignature sig = (PGPSignature)it.next(); + + sig.init(new BcPGPContentVerifierBuilderProvider(), pgpPub.getPublicKey()); + + if (!sig.verifyCertification(uid, pgpPub.getPublicKey())) + { + fail("failed to verify certification"); + } + + // + // write a public key + // + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut); + + pgpPub.encode(pOut); + + if (!areEqual(bOut.toByteArray(), testPubKey)) + { + fail("public key rewrite failed"); + } + + // + // Read the public key + // + PGPPublicKeyRing pgpPubV3 = new PGPPublicKeyRing(testPubKeyV3, new BcKeyFingerprintCalculator()); + PublicKey pubKeyV3 = new JcaPGPKeyConverter().setProvider("SC").getPublicKey(pgpPub.getPublicKey()); + + // + // write a V3 public key + // + bOut = new ByteArrayOutputStream(); + pOut = new BCPGOutputStream(bOut); + + pgpPubV3.encode(pOut); + + // + // Read a v3 private key + // + char[] passP = "FIXCITY_QA".toCharArray(); + + if (!noIDEA()) + { + PGPSecretKeyRing pgpPriv = new PGPSecretKeyRing(testPrivKeyV3, new BcKeyFingerprintCalculator()); + PGPPrivateKey pgpPrivKey = pgpPriv.getSecretKey().extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(passP)); + + // + // write a v3 private key + // + bOut = new ByteArrayOutputStream(); + pOut = new BCPGOutputStream(bOut); + + pgpPriv.encode(pOut); + + if (!areEqual(bOut.toByteArray(), testPrivKeyV3)) + { + fail("private key V3 rewrite failed"); + } + } + + // + // Read the private key + // + PGPSecretKeyRing pgpPriv = new PGPSecretKeyRing(testPrivKey, new BcKeyFingerprintCalculator()); + PGPPrivateKey pgpPrivKey = pgpPriv.getSecretKey().extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass)); + + // + // write a private key + // + bOut = new ByteArrayOutputStream(); + pOut = new BCPGOutputStream(bOut); + + pgpPriv.encode(pOut); + + if (!areEqual(bOut.toByteArray(), testPrivKey)) + { + fail("private key rewrite failed"); + } + + + // + // test encryption + // + Cipher c = Cipher.getInstance("RSA", "SC"); + + c.init(Cipher.ENCRYPT_MODE, pubKey); + + byte[] in = "hello world".getBytes(); + + byte[] out = c.doFinal(in); + + c.init(Cipher.DECRYPT_MODE, new JcaPGPKeyConverter().setProvider("SC").getPrivateKey(pgpPrivKey)); + + out = c.doFinal(out); + + if (!areEqual(in, out)) + { + fail("decryption failed."); + } + + // + // test signature message + // + PGPObjectFactory pgpFact = new PGPObjectFactory(sig1, new BcKeyFingerprintCalculator()); + + PGPCompressedData c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new PGPObjectFactory(c1.getDataStream(), new BcKeyFingerprintCalculator()); + + PGPOnePassSignatureList p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + + PGPOnePassSignature ops = p1.get(0); + + PGPLiteralData p2 = (PGPLiteralData)pgpFact.nextObject(); + + InputStream dIn = p2.getInputStream(); + int ch; + + ops.init(new BcPGPContentVerifierBuilderProvider(), pgpPub.getPublicKey(ops.getKeyID())); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + PGPSignatureList p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed signature check"); + } + + // + // encrypted message - read subkey + // + pgpPriv = new PGPSecretKeyRing(subKey, new BcKeyFingerprintCalculator()); + + // + // encrypted message + // + byte[] text = { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)' ', (byte)'w', (byte)'o', (byte)'r', (byte)'l', (byte)'d', (byte)'!', (byte)'\n' }; + + PGPObjectFactory pgpF = new PGPObjectFactory(enc1, new BcKeyFingerprintCalculator()); + + PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpF.nextObject(); + + PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0); + + pgpPrivKey = pgpPriv.getSecretKey(encP.getKeyID()).extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass)); + + InputStream clear = encP.getDataStream(new BcPublicKeyDataDecryptorFactory(pgpPrivKey)); + + pgpFact = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator()); + + c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new PGPObjectFactory(c1.getDataStream(), new BcKeyFingerprintCalculator()); + + PGPLiteralData ld = (PGPLiteralData)pgpFact.nextObject(); + + bOut = new ByteArrayOutputStream(); + + if (!ld.getFileName().equals("test.txt")) + { + throw new RuntimeException("wrong filename in packet"); + } + + InputStream inLd = ld.getDataStream(); + + while ((ch = inLd.read()) >= 0) + { + bOut.write(ch); + } + + if (!areEqual(bOut.toByteArray(), text)) + { + fail("wrong plain text in decrypted packet"); + } + + // + // encrypt - short message + // + byte[] shortText = { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o' }; + + ByteArrayOutputStream cbOut = new ByteArrayOutputStream(); + PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5).setSecureRandom(new SecureRandom())); + PGPPublicKey puK = pgpPriv.getSecretKey(encP.getKeyID()).getPublicKey(); + + cPk.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(puK)); + + OutputStream cOut = cPk.open(new UncloseableOutputStream(cbOut), shortText.length); + + cOut.write(shortText); + + cOut.close(); + + pgpF = new PGPObjectFactory(cbOut.toByteArray(), new BcKeyFingerprintCalculator()); + + encList = (PGPEncryptedDataList)pgpF.nextObject(); + + encP = (PGPPublicKeyEncryptedData)encList.get(0); + + pgpPrivKey = pgpPriv.getSecretKey(encP.getKeyID()).extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass)); + + PublicKeyDataDecryptorFactory dataDecryptorFactory = new BcPublicKeyDataDecryptorFactory(pgpPrivKey); + + if (encP.getSymmetricAlgorithm(dataDecryptorFactory) != SymmetricKeyAlgorithmTags.CAST5) + { + fail("symmetric algorithm mismatch"); + } + + clear = encP.getDataStream(dataDecryptorFactory); + + bOut.reset(); + + while ((ch = clear.read()) >= 0) + { + bOut.write(ch); + } + + out = bOut.toByteArray(); + + if (!areEqual(out, shortText)) + { + fail("wrong plain text in generated short text packet"); + } + + // + // encrypt + // + cbOut = new ByteArrayOutputStream(); + cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5).setSecureRandom(new SecureRandom())); + puK = pgpPriv.getSecretKey(encP.getKeyID()).getPublicKey(); + + cPk.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(puK)); + + cOut = cPk.open(new UncloseableOutputStream(cbOut), text.length); + + cOut.write(text); + + cOut.close(); + + pgpF = new PGPObjectFactory(cbOut.toByteArray(), new BcKeyFingerprintCalculator()); + + encList = (PGPEncryptedDataList)pgpF.nextObject(); + + encP = (PGPPublicKeyEncryptedData)encList.get(0); + + pgpPrivKey = pgpPriv.getSecretKey(encP.getKeyID()).extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass)); + + clear = encP.getDataStream(new BcPublicKeyDataDecryptorFactory(pgpPrivKey)); + + bOut.reset(); + + while ((ch = clear.read()) >= 0) + { + bOut.write(ch); + } + + out = bOut.toByteArray(); + + if (!areEqual(out, text)) + { + fail("wrong plain text in generated packet"); + } + + // + // read public key with sub key. + // + pgpF = new PGPObjectFactory(subPubKey, new BcKeyFingerprintCalculator()); + Object o; + + while ((o = pgpFact.nextObject()) != null) + { + // System.out.println(o); + } + + // + // key pair generation - CAST5 encryption + // + char[] passPhrase = "hello".toCharArray(); + + RSAKeyPairGenerator kpg = new RSAKeyPairGenerator(); + + kpg.init(new RSAKeyGenerationParameters(BigInteger.valueOf(0x11), new SecureRandom(), 1024, 25)); + + AsymmetricCipherKeyPair kp = kpg.generateKeyPair(); + + PGPSecretKey secretKey = new PGPSecretKey(PGPSignature.DEFAULT_CERTIFICATION, new BcPGPKeyPair(PublicKeyAlgorithmTags.RSA_GENERAL, kp, new Date()), "fred", null, null, new BcPGPContentSignerBuilder(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1), new BcPBESecretKeyEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5).build(passPhrase)); + + PGPPublicKey key = secretKey.getPublicKey(); + + it = key.getUserIDs(); + + uid = (String)it.next(); + + it = key.getSignaturesForID(uid); + + sig = (PGPSignature)it.next(); + + sig.init(new BcPGPContentVerifierBuilderProvider(), key); + + if (!sig.verifyCertification(uid, key)) + { + fail("failed to verify certification"); + } + + pgpPrivKey = secretKey.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(passPhrase)); + + key = PGPPublicKey.removeCertification(key, uid, sig); + + if (key == null) + { + fail("failed certification removal"); + } + + byte[] keyEnc = key.getEncoded(); + + key = PGPPublicKey.addCertification(key, uid, sig); + + keyEnc = key.getEncoded(); + + PGPSignatureGenerator sGen = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1)); + + sGen.init(PGPSignature.KEY_REVOCATION, secretKey.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(passPhrase))); + + sig = sGen.generateCertification(key); + + key = PGPPublicKey.addCertification(key, sig); + + keyEnc = key.getEncoded(); + + PGPPublicKeyRing tmpRing = new PGPPublicKeyRing(keyEnc, new BcKeyFingerprintCalculator()); + + key = tmpRing.getPublicKey(); + + Iterator sgIt = key.getSignaturesOfType(PGPSignature.KEY_REVOCATION); + + sig = (PGPSignature)sgIt.next(); + + sig.init(new BcPGPContentVerifierBuilderProvider(), key); + + if (!sig.verifyCertification(key)) + { + fail("failed to verify revocation certification"); + } + + // + // use of PGPKeyPair + // + PGPKeyPair pgpKp = new BcPGPKeyPair(PGPPublicKey.RSA_GENERAL , kp, new Date()); + + PGPPublicKey k1 = pgpKp.getPublicKey(); + + PGPPrivateKey k2 = pgpKp.getPrivateKey(); + + k1.getEncoded(); + + mixedTest(k2, k1); + + // + // key pair generation - AES_256 encryption. + // + kp = kpg.generateKeyPair(); + + secretKey = new PGPSecretKey(PGPSignature.DEFAULT_CERTIFICATION, new BcPGPKeyPair(PublicKeyAlgorithmTags.RSA_GENERAL, kp, new Date()), "fred", null, null, new BcPGPContentSignerBuilder(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1), new BcPBESecretKeyEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256).build(passPhrase)); + + secretKey.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(passPhrase)); + + secretKey.encode(new ByteArrayOutputStream()); + + // + // secret key password changing. + // + String newPass = "newPass"; + + secretKey = PGPSecretKey.copyWithNewPassword(secretKey, new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(passPhrase), new BcPBESecretKeyEncryptorBuilder(secretKey.getKeyEncryptionAlgorithm()).build(newPass.toCharArray())); + + secretKey.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(newPass.toCharArray())); + + secretKey.encode(new ByteArrayOutputStream()); + + key = secretKey.getPublicKey(); + + key.encode(new ByteArrayOutputStream()); + + it = key.getUserIDs(); + + uid = (String)it.next(); + + it = key.getSignaturesForID(uid); + + sig = (PGPSignature)it.next(); + + sig.init(new BcPGPContentVerifierBuilderProvider(), key); + + if (!sig.verifyCertification(uid, key)) + { + fail("failed to verify certification"); + } + + pgpPrivKey = secretKey.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(newPass.toCharArray())); + + // + // signature generation + // + String data = "hello world!"; + + bOut = new ByteArrayOutputStream(); + + ByteArrayInputStream testIn = new ByteArrayInputStream(data.getBytes()); + + sGen = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1)); + + sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey); + + PGPCompressedDataGenerator cGen = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + BCPGOutputStream bcOut = new BCPGOutputStream( + cGen.open(new UncloseableOutputStream(bOut))); + + sGen.generateOnePassVersion(false).encode(bcOut); + + PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); + + Date testDate = new Date((System.currentTimeMillis() / 1000) * 1000); + OutputStream lOut = lGen.open( + new UncloseableOutputStream(bcOut), + PGPLiteralData.BINARY, + "_CONSOLE", + data.getBytes().length, + testDate); + + while ((ch = testIn.read()) >= 0) + { + lOut.write(ch); + sGen.update((byte)ch); + } + + lOut.close(); + + sGen.generate().encode(bcOut); + + bcOut.close(); + + // + // verify generated signature + // + pgpFact = new PGPObjectFactory(bOut.toByteArray(), new BcKeyFingerprintCalculator()); + + c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new PGPObjectFactory(c1.getDataStream(), new BcKeyFingerprintCalculator()); + + p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + + ops = p1.get(0); + + p2 = (PGPLiteralData)pgpFact.nextObject(); + if (!p2.getModificationTime().equals(testDate)) + { + fail("Modification time not preserved: " + p2.getModificationTime() + " " + testDate); + } + + dIn = p2.getInputStream(); + + ops.init(new BcPGPContentVerifierBuilderProvider(), secretKey.getPublicKey()); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed generated signature check"); + } + + // + // signature generation - version 3 + // + bOut = new ByteArrayOutputStream(); + + testIn = new ByteArrayInputStream(data.getBytes()); + PGPV3SignatureGenerator sGenV3 = new PGPV3SignatureGenerator(new BcPGPContentSignerBuilder(PGPPublicKey.RSA_GENERAL, PGPUtil.SHA1)); + + sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey); + + cGen = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + bcOut = new BCPGOutputStream(cGen.open(bOut)); + + sGen.generateOnePassVersion(false).encode(bcOut); + + lGen = new PGPLiteralDataGenerator(); + lOut = lGen.open( + new UncloseableOutputStream(bcOut), + PGPLiteralData.BINARY, + "_CONSOLE", + data.getBytes().length, + testDate); + + while ((ch = testIn.read()) >= 0) + { + lOut.write(ch); + sGen.update((byte)ch); + } + + lOut.close(); + + sGen.generate().encode(bcOut); + + bcOut.close(); + + // + // verify generated signature + // + pgpFact = new PGPObjectFactory(bOut.toByteArray(), new BcKeyFingerprintCalculator()); + + c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new PGPObjectFactory(c1.getDataStream(), new BcKeyFingerprintCalculator()); + + p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + + ops = p1.get(0); + + p2 = (PGPLiteralData)pgpFact.nextObject(); + if (!p2.getModificationTime().equals(testDate)) + { + fail("Modification time not preserved"); + } + + dIn = p2.getInputStream(); + + ops.init(new BcPGPContentVerifierBuilderProvider(), secretKey.getPublicKey()); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed v3 generated signature check"); + } + + // + // extract PGP 8 private key + // + pgpPriv = new PGPSecretKeyRing(pgp8Key, new BcKeyFingerprintCalculator()); + + secretKey = pgpPriv.getSecretKey(); + + pgpPrivKey = secretKey.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pgp8Pass)); + + // + // expiry + // + testExpiry(expiry60and30daysSig13Key, 60, 30); + + fingerPrintTest(); + existingEmbeddedJpegTest(); + embeddedJpegTest(); + sigsubpacketTest(); + } + + private void testExpiry( + byte[] encodedRing, + int masterDays, + int subKeyDays) + throws Exception + { + PGPPublicKeyRing pubRing = new PGPPublicKeyRing(encodedRing, new BcKeyFingerprintCalculator()); + PGPPublicKey k = pubRing.getPublicKey(); + + if (k.getValidDays() != masterDays) + { + fail("mismatch on master valid days."); + } + + Iterator it = pubRing.getPublicKeys(); + + it.next(); + + k = (PGPPublicKey)it.next(); + + if (k.getValidDays() != subKeyDays) + { + fail("mismatch on subkey valid days."); + } + } + + private boolean noIDEA() + { + return true; + } + + public String getName() + { + return "BcPGPRSATest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new BcPGPRSATest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/DSA2Test.java b/pg/src/test/java/org/spongycastle/openpgp/test/DSA2Test.java new file mode 100644 index 00000000..5e0ea682 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/DSA2Test.java @@ -0,0 +1,295 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.Security; +import java.util.Date; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.spongycastle.bcpg.BCPGOutputStream; +import org.spongycastle.bcpg.PublicKeyAlgorithmTags; +import org.spongycastle.openpgp.PGPCompressedData; +import org.spongycastle.openpgp.PGPLiteralData; +import org.spongycastle.openpgp.PGPLiteralDataGenerator; +import org.spongycastle.openpgp.PGPOnePassSignature; +import org.spongycastle.openpgp.PGPOnePassSignatureList; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPUtil; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +import org.spongycastle.util.test.UncloseableOutputStream; + +/** + * GPG compatability test vectors + */ +public class DSA2Test + extends TestCase +{ + private static final String TEST_DATA_HOME = "bc.test.data.home"; + + public void setUp() + { + if (Security.getProvider("SC") == null) + { + Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider()); + } + } + + public void testK1024H160() + throws Exception + { + doSigVerifyTest("DSA-1024-160.pub", "dsa-1024-160-sign.gpg"); + } + + public void testK1024H224() + throws Exception + { + doSigVerifyTest("DSA-1024-160.pub", "dsa-1024-224-sign.gpg"); + } + + public void testK1024H256() + throws Exception + { + doSigVerifyTest("DSA-1024-160.pub", "dsa-1024-256-sign.gpg"); + } + + public void testK1024H384() + throws Exception + { + doSigVerifyTest("DSA-1024-160.pub", "dsa-1024-384-sign.gpg"); + } + + public void testK1024H512() + throws Exception + { + doSigVerifyTest("DSA-1024-160.pub", "dsa-1024-512-sign.gpg"); + } + + public void testK2048H224() + throws Exception + { + doSigVerifyTest("DSA-2048-224.pub", "dsa-2048-224-sign.gpg"); + } + + public void testK3072H256() + throws Exception + { + doSigVerifyTest("DSA-3072-256.pub", "dsa-3072-256-sign.gpg"); + } + + public void testK7680H384() + throws Exception + { + doSigVerifyTest("DSA-7680-384.pub", "dsa-7680-384-sign.gpg"); + } + + public void testK15360H512() + throws Exception + { + doSigVerifyTest("DSA-15360-512.pub", "dsa-15360-512-sign.gpg"); + } + + public void testGenerateK1024H224() + throws Exception + { + doSigGenerateTest("DSA-1024-160.sec", "DSA-1024-160.pub", PGPUtil.SHA224); + } + + public void testGenerateK1024H256() + throws Exception + { + doSigGenerateTest("DSA-1024-160.sec", "DSA-1024-160.pub", PGPUtil.SHA256); + } + + public void testGenerateK1024H384() + throws Exception + { + doSigGenerateTest("DSA-1024-160.sec", "DSA-1024-160.pub", PGPUtil.SHA384); + } + + public void testGenerateK1024H512() + throws Exception + { + doSigGenerateTest("DSA-1024-160.sec", "DSA-1024-160.pub", PGPUtil.SHA512); + } + + public void testGenerateK2048H256() + throws Exception + { + doSigGenerateTest("DSA-2048-224.sec", "DSA-2048-224.pub", PGPUtil.SHA256); + } + + public void testGenerateK2048H512() + throws Exception + { + doSigGenerateTest("DSA-2048-224.sec", "DSA-2048-224.pub", PGPUtil.SHA512); + } + + private void doSigGenerateTest(String privateKeyFile, String publicKeyFile, int digest) + throws Exception + { + PGPSecretKeyRing secRing = loadSecretKey(privateKeyFile); + PGPPublicKeyRing pubRing = loadPublicKey(publicKeyFile); + String data = "hello world!"; + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ByteArrayInputStream testIn = new ByteArrayInputStream(data.getBytes()); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(PublicKeyAlgorithmTags.DSA, digest).setProvider("SC")); + + sGen.init(PGPSignature.BINARY_DOCUMENT, secRing.getSecretKey().extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build("test".toCharArray()))); + + BCPGOutputStream bcOut = new BCPGOutputStream(bOut); + + sGen.generateOnePassVersion(false).encode(bcOut); + + PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); + + Date testDate = new Date((System.currentTimeMillis() / 1000) * 1000); + OutputStream lOut = lGen.open( + new UncloseableOutputStream(bcOut), + PGPLiteralData.BINARY, + "_CONSOLE", + data.getBytes().length, + testDate); + + int ch; + while ((ch = testIn.read()) >= 0) + { + lOut.write(ch); + sGen.update((byte)ch); + } + + lGen.close(); + + sGen.generate().encode(bcOut); + + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(bOut.toByteArray()); + PGPOnePassSignatureList p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + PGPOnePassSignature ops = p1.get(0); + + assertEquals(digest, ops.getHashAlgorithm()); + assertEquals(PublicKeyAlgorithmTags.DSA, ops.getKeyAlgorithm()); + + PGPLiteralData p2 = (PGPLiteralData)pgpFact.nextObject(); + if (!p2.getModificationTime().equals(testDate)) + { + fail("Modification time not preserved"); + } + + InputStream dIn = p2.getInputStream(); + + ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pubRing.getPublicKey()); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + PGPSignatureList p3 = (PGPSignatureList)pgpFact.nextObject(); + PGPSignature sig = p3.get(0); + + assertEquals(digest, sig.getHashAlgorithm()); + assertEquals(PublicKeyAlgorithmTags.DSA, sig.getKeyAlgorithm()); + + assertTrue(ops.verify(sig)); + } + + private void doSigVerifyTest( + String publicKeyFile, + String sigFile) + throws Exception + { + PGPPublicKeyRing publicKey = loadPublicKey(publicKeyFile); + JcaPGPObjectFactory pgpFact = loadSig(sigFile); + + PGPCompressedData c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + PGPOnePassSignatureList p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + PGPOnePassSignature ops = p1.get(0); + + PGPLiteralData p2 = (PGPLiteralData)pgpFact.nextObject(); + + InputStream dIn = p2.getInputStream(); + + ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), publicKey.getPublicKey()); + + int ch; + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + PGPSignatureList p3 = (PGPSignatureList)pgpFact.nextObject(); + + assertTrue(ops.verify(p3.get(0))); + } + + private JcaPGPObjectFactory loadSig( + String sigName) + throws Exception + { + FileInputStream fIn = new FileInputStream(getDataHome() + "/sigs/" + sigName); + + return new JcaPGPObjectFactory(fIn); + } + + private PGPPublicKeyRing loadPublicKey( + String keyName) + throws Exception + { + FileInputStream fIn = new FileInputStream(getDataHome() + "/keys/" + keyName); + + return new PGPPublicKeyRing(fIn, new JcaKeyFingerprintCalculator()); + } + + private PGPSecretKeyRing loadSecretKey( + String keyName) + throws Exception + { + FileInputStream fIn = new FileInputStream(getDataHome() + "/keys/" + keyName); + + return new PGPSecretKeyRing(fIn, new JcaKeyFingerprintCalculator()); + } + + private String getDataHome() + { + String dataHome = System.getProperty(TEST_DATA_HOME); + + if (dataHome == null) + { + throw new IllegalStateException(TEST_DATA_HOME + " property not set"); + } + + return dataHome + "/openpgp/dsa"; + } + + public static void main (String[] args) + throws Exception + { + junit.textui.TestRunner.run(suite()); + } + + public static Test suite() + throws Exception + { + TestSuite suite = new TestSuite("GPG DSA2 tests"); + + suite.addTestSuite(DSA2Test.class); + + return suite; + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPArmoredTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPArmoredTest.java new file mode 100644 index 00000000..e6647026 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPArmoredTest.java @@ -0,0 +1,255 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +import org.spongycastle.bcpg.ArmoredInputStream; +import org.spongycastle.bcpg.ArmoredOutputStream; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.Strings; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class PGPArmoredTest + extends SimpleTest +{ + byte[] sample = Base64.decode( + "mQGiBEA83v0RBADzKVLVCnpWQxX0LCsevw/3OLs0H7MOcLBQ4wMO9sYmzGYn" + + "xpVj+4e4PiCP7QBayWyy4lugL6Lnw7tESvq3A4v3fefcxaCTkJrryiKn4+Cg" + + "y5rIBbrSKNtCEhVi7xjtdnDjP5kFKgHYjVOeIKn4Cz/yzPG3qz75kDknldLf" + + "yHxp2wCgwW1vAE5EnZU4/UmY7l8kTNkMltMEAJP4/uY4zcRwLI9Q2raPqAOJ" + + "TYLd7h+3k/BxI0gIw96niQ3KmUZDlobbWBI+VHM6H99vcttKU3BgevNf8M9G" + + "x/AbtW3SS4De64wNSU3189XDG8vXf0vuyW/K6Pcrb8exJWY0E1zZQ1WXT0gZ" + + "W0kH3g5ro//Tusuil9q2lVLF2ovJA/0W+57bPzi318dWeNs0tTq6Njbc/GTG" + + "FUAVJ8Ss5v2u6h7gyJ1DB334ExF/UdqZGldp0ugkEXaSwBa2R7d3HBgaYcoP" + + "Ck1TrovZzEY8gm7JNVy7GW6mdOZuDOHTxyADEEP2JPxh6eRcZbzhGuJuYIif" + + "IIeLOTI5Dc4XKeV32a+bWrQidGVzdCAoVGVzdCBrZXkpIDx0ZXN0QHViaWNh" + + "bGwuY29tPohkBBMRAgAkBQJAPN79AhsDBQkB4TOABgsJCAcDAgMVAgMDFgIB" + + "Ah4BAheAAAoJEJh8Njfhe8KmGDcAoJWr8xgPr75y/Cp1kKn12oCCOb8zAJ4p" + + "xSvk4K6tB2jYbdeSrmoWBZLdMLACAAC5AQ0EQDzfARAEAJeUAPvUzJJbKcc5" + + "5Iyb13+Gfb8xBWE3HinQzhGr1v6A1aIZbRj47UPAD/tQxwz8VAwJySx82ggN" + + "LxCk4jW9YtTL3uZqfczsJngV25GoIN10f4/j2BVqZAaX3q79a3eMiql1T0oE" + + "AGmD7tO1LkTvWfm3VvA0+t8/6ZeRLEiIqAOHAAQNBACD0mVMlAUgd7REYy/1" + + "mL99Zlu9XU0uKyUex99sJNrcx1aj8rIiZtWaHz6CN1XptdwpDeSYEOFZ0PSu" + + "qH9ByM3OfjU/ya0//xdvhwYXupn6P1Kep85efMBA9jUv/DeBOzRWMFG6sC6y" + + "k8NGG7Swea7EHKeQI40G3jgO/+xANtMyTIhPBBgRAgAPBQJAPN8BAhsMBQkB" + + "4TOAAAoJEJh8Njfhe8KmG7kAn00mTPGJCWqmskmzgdzeky5fWd7rAKCNCp3u" + + "ZJhfg0htdgAfIy8ppm05vLACAAA="); + + byte[] marker = Hex.decode("2d2d2d2d2d454e4420504750205055424c4943204b455920424c4f434b2d2d2d2d2d"); + + // Contains "Hello World!" as an armored message + // The 'blank line' after the headers contains (legal) whitespace - see RFC2440 6.2 + private static final String blankLineData = + "-----BEGIN PGP MESSAGE-----\n" + + "Version: BCPG v1.32\n" + + "Comment: A dummy message\n" + + " \t \t\n" + + "SGVsbG8gV29ybGQh\n" + + "=d9Xi\n" + + "-----END PGP MESSAGE-----\n"; + + private int markerCount( + byte[] data) + { + int ind = 0; + int matches = 0; + + while (ind < data.length) + { + if (data[ind] == 0x2d) + { + int count = 0; + while (count < marker.length) + { + if (data[ind + count] != marker[count]) + { + break; + } + count++; + } + + if (count == marker.length) + { + matches++; + } + + ind += count; + } + else + { + ind++; + } + } + + return matches; + } + + private void blankLineTest() throws Exception + { + byte[] blankLineBytes = Strings.toByteArray(blankLineData); + ByteArrayInputStream bIn = new ByteArrayInputStream(blankLineBytes); + ArmoredInputStream aIn = new ArmoredInputStream(bIn, true); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + int c; + while ((c = aIn.read()) >= 0) + { + bOut.write(c); + } + + byte[] expected = Strings.toByteArray("Hello World!"); + + if (!Arrays.areEqual(expected, bOut.toByteArray())) + { + fail("Incorrect message retrieved in blank line test."); + } + } + + public void performTest() + throws Exception + { + // + // test immediate close + // + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ArmoredOutputStream aOut = new ArmoredOutputStream(bOut); + + aOut.close(); + + byte[] data = bOut.toByteArray(); + + if (data.length != 0) + { + fail("No data should have been written"); + } + + // + // multiple close + // + bOut = new ByteArrayOutputStream(); + aOut = new ArmoredOutputStream(bOut); + + aOut.write(sample); + + aOut.close(); + + aOut.close(); + + int mc = markerCount(bOut.toByteArray()); + + if (mc < 1) + { + fail("No end marker found"); + } + + if (mc > 1) + { + fail("More than one end marker found"); + } + + // + // writing and reading single objects + // + bOut = new ByteArrayOutputStream(); + aOut = new ArmoredOutputStream(bOut); + + aOut.write(sample); + + aOut.close(); + + ArmoredInputStream aIn = new ArmoredInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + JcaPGPObjectFactory fact = new JcaPGPObjectFactory(aIn); + int count = 0; + + while (fact.nextObject() != null) + { + count++; + } + + if (count != 1) + { + fail("wrong number of objects found: " + count); + } + + // + // writing and reading multiple objects - in single block + // + bOut = new ByteArrayOutputStream(); + aOut = new ArmoredOutputStream(bOut); + + aOut.write(sample); + aOut.write(sample); + + aOut.close(); + + aIn = new ArmoredInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + fact = new JcaPGPObjectFactory(aIn); + count = 0; + + while (fact.nextObject() != null) + { + count++; + } + + if (count != 2) + { + fail("wrong number of objects found: " + count); + } + + // + // writing and reading multiple objects - in single block + // + bOut = new ByteArrayOutputStream(); + aOut = new ArmoredOutputStream(bOut); + + aOut.write(sample); + + aOut.close(); // does not close underlying stream + + aOut = new ArmoredOutputStream(bOut); + + aOut.write(sample); + + aOut.close(); + + aIn = new ArmoredInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + count = 0; + boolean atLeastOne; + do + { + atLeastOne = false; + fact = new JcaPGPObjectFactory(aIn); + + while (fact.nextObject() != null) + { + atLeastOne = true; + count++; + } + } + while (atLeastOne); + + if (count != 2) + { + fail("wrong number of objects found: " + count); + } + + blankLineTest(); + } + + public String getName() + { + return "PGPArmoredTest"; + } + + public static void main( + String[] args) + { + runTest(new PGPArmoredTest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPClearSignedSignatureTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPClearSignedSignatureTest.java new file mode 100644 index 00000000..6b3f019e --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPClearSignedSignatureTest.java @@ -0,0 +1,459 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.SignatureException; +import java.util.Iterator; + +import org.spongycastle.bcpg.ArmoredInputStream; +import org.spongycastle.bcpg.ArmoredOutputStream; +import org.spongycastle.bcpg.BCPGOutputStream; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPPublicKeyRingCollection; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSecretKeyRingCollection; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.spongycastle.openpgp.PGPUtil; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.test.SimpleTest; + +public class PGPClearSignedSignatureTest + extends SimpleTest +{ + byte[] publicKey = Base64.decode( + "mQELBEQh2+wBCAD26kte0hO6flr7Y2aetpPYutHY4qsmDPy+GwmmqVeCDkX+" + + "r1g7DuFbMhVeu0NkKDnVl7GsJ9VarYsFYyqu0NzLa9XS2qlTIkmJV+2/xKa1" + + "tzjn18fT/cnAWL88ZLCOWUr241aPVhLuIc6vpHnySpEMkCh4rvMaimnTrKwO" + + "42kgeDGd5cXfs4J4ovRcTbc4hmU2BRVsRjiYMZWWx0kkyL2zDVyaJSs4yVX7" + + "Jm4/LSR1uC/wDT0IJJuZT/gQPCMJNMEsVCziRgYkAxQK3OWojPSuv4rXpyd4" + + "Gvo6IbvyTgIskfpSkCnQtORNLIudQSuK7pW+LkL62N+ohuKdMvdxauOnAAYp" + + "tBNnZ2dnZ2dnZyA8Z2dnQGdnZ2c+iQE2BBMBAgAgBQJEIdvsAhsDBgsJCAcD" + + "AgQVAggDBBYCAwECHgECF4AACgkQ4M/Ier3f9xagdAf/fbKWBjLQM8xR7JkR" + + "P4ri8YKOQPhK+VrddGUD59/wzVnvaGyl9MZE7TXFUeniQq5iXKnm22EQbYch" + + "v2Jcxyt2H9yptpzyh4tP6tEHl1C887p2J4qe7F2ATua9CzVGwXQSUbKtj2fg" + + "UZP5SsNp25guhPiZdtkf2sHMeiotmykFErzqGMrvOAUThrO63GiYsRk4hF6r" + + "cQ01d+EUVpY/sBcCxgNyOiB7a84sDtrxnX5BTEZDTEj8LvuEyEV3TMUuAjx1" + + "7Eyd+9JtKzwV4v3hlTaWOvGro9nPS7YaPuG+RtufzXCUJPbPfTjTvtGOqvEz" + + "oztls8tuWA0OGHba9XfX9rfgorACAAM="); + + byte[] secretKey = Base64.decode( + "lQOWBEQh2+wBCAD26kte0hO6flr7Y2aetpPYutHY4qsmDPy+GwmmqVeCDkX+" + + "r1g7DuFbMhVeu0NkKDnVl7GsJ9VarYsFYyqu0NzLa9XS2qlTIkmJV+2/xKa1" + + "tzjn18fT/cnAWL88ZLCOWUr241aPVhLuIc6vpHnySpEMkCh4rvMaimnTrKwO" + + "42kgeDGd5cXfs4J4ovRcTbc4hmU2BRVsRjiYMZWWx0kkyL2zDVyaJSs4yVX7" + + "Jm4/LSR1uC/wDT0IJJuZT/gQPCMJNMEsVCziRgYkAxQK3OWojPSuv4rXpyd4" + + "Gvo6IbvyTgIskfpSkCnQtORNLIudQSuK7pW+LkL62N+ohuKdMvdxauOnAAYp" + + "AAf+JCJJeAXEcrTVHotsrRR5idzmg6RK/1MSQUijwPmP7ZGy1BmpAmYUfbxn" + + "B56GvXyFV3Pbj9PgyJZGS7cY+l0BF4ZqN9USiQtC9OEpCVT5LVMCFXC/lahC" + + "/O3EkjQy0CYK+GwyIXa+Flxcr460L/Hvw2ZEXJZ6/aPdiR+DU1l5h99Zw8V1" + + "Y625MpfwN6ufJfqE0HLoqIjlqCfi1iwcKAK2oVx2SwnT1W0NwUUXjagGhD2s" + + "VzJVpLqhlwmS0A+RE9Niqrf80/zwE7QNDF2DtHxmMHJ3RY/pfu5u1rrFg9YE" + + "lmS60mzOe31CaD8Li0k5YCJBPnmvM9mN3/DWWprSZZKtmQQA96C2/VJF5EWm" + + "+/Yxi5J06dG6Bkz311Ui4p2zHm9/4GvTPCIKNpGx9Zn47YFD3tIg3fIBVPOE" + + "ktG38pEPx++dSSFF9Ep5UgmYFNOKNUVq3yGpatBtCQBXb1LQLAMBJCJ5TQmk" + + "68hMOEaqjMHSOa18cS63INgA6okb/ueAKIHxYQcEAP9DaXu5n9dZQw7pshbN" + + "Nu/T5IP0/D/wqM+W5r+j4P1N7PgiAnfKA4JjKrUgl8PGnI2qM/Qu+g3qK++c" + + "F1ESHasnJPjvNvY+cfti06xnJVtCB/EBOA2UZkAr//Tqa76xEwYAWRBnO2Y+" + + "KIVOT+nMiBFkjPTrNAD6fSr1O4aOueBhBAC6aA35IfjC2h5MYk8+Z+S4io2o" + + "mRxUZ/dUuS+kITvWph2e4DT28Xpycpl2n1Pa5dCDO1lRqe/5JnaDYDKqxfmF" + + "5tTG8GR4d4nVawwLlifXH5Ll7t5NcukGNMCsGuQAHMy0QHuAaOvMdLs5kGHn" + + "8VxfKEVKhVrXsvJSwyXXSBtMtUcRtBNnZ2dnZ2dnZyA8Z2dnQGdnZ2c+iQE2" + + "BBMBAgAgBQJEIdvsAhsDBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQ4M/I" + + "er3f9xagdAf/fbKWBjLQM8xR7JkRP4ri8YKOQPhK+VrddGUD59/wzVnvaGyl" + + "9MZE7TXFUeniQq5iXKnm22EQbYchv2Jcxyt2H9yptpzyh4tP6tEHl1C887p2" + + "J4qe7F2ATua9CzVGwXQSUbKtj2fgUZP5SsNp25guhPiZdtkf2sHMeiotmykF" + + "ErzqGMrvOAUThrO63GiYsRk4hF6rcQ01d+EUVpY/sBcCxgNyOiB7a84sDtrx" + + "nX5BTEZDTEj8LvuEyEV3TMUuAjx17Eyd+9JtKzwV4v3hlTaWOvGro9nPS7Ya" + + "PuG+RtufzXCUJPbPfTjTvtGOqvEzoztls8tuWA0OGHba9XfX9rfgorACAAA="); + + String crOnlyMessage = + "\r" + + " hello world!\r" + + "\r" + + "- dash\r"; + + String nlOnlyMessage = + "\n" + + " hello world!\n" + + "\n" + + "- dash\n"; + + String crNlMessage = + "\r\n" + + " hello world!\r\n" + + "\r\n" + + "- dash\r\n"; + + String crOnlySignedMessage = + "-----BEGIN PGP SIGNED MESSAGE-----\r" + + "Hash: SHA256\r" + + "\r" + + "\r" + + " hello world!\r" + + "\r" + + "- - dash\r" + + "-----BEGIN PGP SIGNATURE-----\r" + + "Version: GnuPG v1.4.2.1 (GNU/Linux)\r" + + "\r" + + "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\r" + + "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\r" + + "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\r" + + "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\r" + + "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\r" + + "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\r" + + "=84Nd\r" + + "-----END PGP SIGNATURE-----\r"; + + + String nlOnlySignedMessage = + "-----BEGIN PGP SIGNED MESSAGE-----\n" + + "Hash: SHA256\n" + + "\n" + + "\n" + + " hello world!\n" + + "\n" + + "- - dash\n" + + "-----BEGIN PGP SIGNATURE-----\n" + + "Version: GnuPG v1.4.2.1 (GNU/Linux)\n" + + "\n" + + "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\n" + + "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\n" + + "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\n" + + "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\n" + + "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\n" + + "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\n" + + "=84Nd\n" + + "-----END PGP SIGNATURE-----\n"; + + String crNlSignedMessage = + "-----BEGIN PGP SIGNED MESSAGE-----\r\n" + + "Hash: SHA256\r\n" + + "\r\n" + + "\r\n" + + " hello world!\r\n" + + "\r\n" + + "- - dash\r\n" + + "-----BEGIN PGP SIGNATURE-----\r\n" + + "Version: GnuPG v1.4.2.1 (GNU/Linux)\r\n" + + "\r\n" + + "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\r\n" + + "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\r\n" + + "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\r\n" + + "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\r\n" + + "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\r\n" + + "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\r\n" + + "=84Nd\r" + + "-----END PGP SIGNATURE-----\r\n"; + + String crNlSignedMessageTrailingWhiteSpace = + "-----BEGIN PGP SIGNED MESSAGE-----\r\n" + + "Hash: SHA256\r\n" + + "\r\n" + + "\r\n" + + " hello world! \t\r\n" + + "\r\n" + + "- - dash\r\n" + + "-----BEGIN PGP SIGNATURE-----\r\n" + + "Version: GnuPG v1.4.2.1 (GNU/Linux)\r\n" + + "\r\n" + + "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\r\n" + + "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\r\n" + + "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\r\n" + + "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\r\n" + + "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\r\n" + + "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\r\n" + + "=84Nd\r" + + "-----END PGP SIGNATURE-----\r\n"; + + public String getName() + { + return "PGPClearSignedSignature"; + } + + private void messageTest( + String message, + String type) + throws Exception + { + ArmoredInputStream aIn = new ArmoredInputStream(new ByteArrayInputStream(message.getBytes())); + + String[] headers = aIn.getArmorHeaders(); + + if (headers == null || headers.length != 1) + { + fail("wrong number of headers found"); + } + + if (!"Hash: SHA256".equals(headers[0])) + { + fail("header value wrong: " + headers[0]); + } + + // + // read the input, making sure we ingore the last newline. + // + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + int ch; + + while ((ch = aIn.read()) >= 0 && aIn.isClearText()) + { + bOut.write((byte)ch); + } + + PGPPublicKeyRingCollection pgpRings = new PGPPublicKeyRingCollection(publicKey, new JcaKeyFingerprintCalculator()); + + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(aIn); + PGPSignatureList p3 = (PGPSignatureList)pgpFact.nextObject(); + PGPSignature sig = p3.get(0); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pgpRings.getPublicKey(sig.getKeyID())); + + ByteArrayOutputStream lineOut = new ByteArrayOutputStream(); + InputStream sigIn = new ByteArrayInputStream(bOut.toByteArray()); + int lookAhead = readInputLine(lineOut, sigIn); + + processLine(sig, lineOut.toByteArray()); + + if (lookAhead != -1) + { + do + { + lookAhead = readInputLine(lineOut, lookAhead, sigIn); + + sig.update((byte)'\r'); + sig.update((byte)'\n'); + + processLine(sig, lineOut.toByteArray()); + } + while (lookAhead != -1); + } + + if (!sig.verify()) + { + fail("signature failed to verify in " + type); + } + } + + private PGPSecretKey readSecretKey( + InputStream in) + throws IOException, PGPException + { + PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(in, new JcaKeyFingerprintCalculator()); + + PGPSecretKey key = null; + + // + // iterate through the key rings. + // + Iterator rIt = pgpSec.getKeyRings(); + + while (key == null && rIt.hasNext()) + { + PGPSecretKeyRing kRing = (PGPSecretKeyRing)rIt.next(); + Iterator kIt = kRing.getSecretKeys(); + + while (key == null && kIt.hasNext()) + { + PGPSecretKey k = (PGPSecretKey)kIt.next(); + + if (k.isSigningKey()) + { + key = k; + } + } + } + + if (key == null) + { + throw new IllegalArgumentException("Can't find signing key in key ring."); + } + + return key; + } + + private void generateTest( + String message, + String type) + throws Exception + { + PGPSecretKey pgpSecKey = readSecretKey(new ByteArrayInputStream(secretKey)); + PGPPrivateKey pgpPrivKey = pgpSecKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build("".toCharArray())); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(pgpSecKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256).setProvider("SC")); + PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); + + sGen.init(PGPSignature.CANONICAL_TEXT_DOCUMENT, pgpPrivKey); + + Iterator it = pgpSecKey.getPublicKey().getUserIDs(); + if (it.hasNext()) + { + spGen.setSignerUserID(false, (String)it.next()); + sGen.setHashedSubpackets(spGen.generate()); + } + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ArmoredOutputStream aOut = new ArmoredOutputStream(bOut); + ByteArrayInputStream bIn = new ByteArrayInputStream(message.getBytes()); + + aOut.beginClearText(PGPUtil.SHA256); + + // + // note the last \n in the file is ignored + // + ByteArrayOutputStream lineOut = new ByteArrayOutputStream(); + int lookAhead = readInputLine(lineOut, bIn); + + processLine(aOut, sGen, lineOut.toByteArray()); + + if (lookAhead != -1) + { + do + { + lookAhead = readInputLine(lineOut, lookAhead, bIn); + + sGen.update((byte)'\r'); + sGen.update((byte)'\n'); + + processLine(aOut, sGen, lineOut.toByteArray()); + } + while (lookAhead != -1); + } + + aOut.endClearText(); + + BCPGOutputStream bcpgOut = new BCPGOutputStream(aOut); + + sGen.generate().encode(bcpgOut); + + aOut.close(); + + messageTest(new String(bOut.toByteArray()), type); + } + + private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn) + throws IOException + { + bOut.reset(); + + int lookAhead = -1; + int ch; + + while ((ch = fIn.read()) >= 0) + { + bOut.write(ch); + if (ch == '\r' || ch == '\n') + { + lookAhead = readPassedEOL(bOut, ch, fIn); + break; + } + } + + return lookAhead; + } + + private static int readInputLine(ByteArrayOutputStream bOut, int lookAhead, InputStream fIn) + throws IOException + { + bOut.reset(); + + int ch = lookAhead; + + do + { + bOut.write(ch); + if (ch == '\r' || ch == '\n') + { + lookAhead = readPassedEOL(bOut, ch, fIn); + break; + } + } + while ((ch = fIn.read()) >= 0); + + return lookAhead; + } + + private static int readPassedEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn) + throws IOException + { + int lookAhead = fIn.read(); + + if (lastCh == '\r' && lookAhead == '\n') + { + bOut.write(lookAhead); + lookAhead = fIn.read(); + } + + return lookAhead; + } + + private static void processLine(PGPSignature sig, byte[] line) + throws SignatureException, IOException + { + int length = getLengthWithoutWhiteSpace(line); + if (length > 0) + { + sig.update(line, 0, length); + } + } + + private static void processLine(OutputStream aOut, PGPSignatureGenerator sGen, byte[] line) + throws SignatureException, IOException + { + int length = getLengthWithoutWhiteSpace(line); + if (length > 0) + { + sGen.update(line, 0, length); + } + + aOut.write(line, 0, line.length); + } + + private static int getLengthWithoutWhiteSpace(byte[] line) + { + int end = line.length - 1; + + while (end >= 0 && isWhiteSpace(line[end])) + { + end--; + } + + return end + 1; + } + + private static boolean isWhiteSpace(byte b) + { + return b == '\r' || b == '\n' || b == '\t' || b == ' '; + } + + public void performTest() + throws Exception + { + messageTest(crOnlySignedMessage, "\\r"); + messageTest(nlOnlySignedMessage, "\\n"); + messageTest(crNlSignedMessage, "\\r\\n"); + messageTest(crNlSignedMessageTrailingWhiteSpace, "\\r\\n"); + + generateTest(nlOnlyMessage, "\\r"); + generateTest(crOnlyMessage, "\\n"); + generateTest(crNlMessage, "\\r\\n"); + } + + public static void main( + String[] args) + { + runTest(new PGPClearSignedSignatureTest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPCompressionTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPCompressionTest.java new file mode 100644 index 00000000..a9a600f1 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPCompressionTest.java @@ -0,0 +1,143 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.Security; + +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPCompressedData; +import org.spongycastle.openpgp.PGPCompressedDataGenerator; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.util.test.SimpleTest; +import org.spongycastle.util.test.UncloseableOutputStream; + +public class PGPCompressionTest + extends SimpleTest +{ + public void performTest() + throws Exception + { + testCompression(PGPCompressedData.UNCOMPRESSED); + testCompression(PGPCompressedData.ZIP); + testCompression(PGPCompressedData.ZLIB); + testCompression(PGPCompressedData.BZIP2); + + // + // new style - using stream close + // + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + PGPCompressedDataGenerator cPacket = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + OutputStream out = cPacket.open(new UncloseableOutputStream(bOut), new byte[4]); + + out.write("hello world! !dlrow olleh".getBytes()); + + out.close(); + + validateData(bOut.toByteArray()); + + try + { + out.close(); + cPacket.close(); + } + catch (Exception e) + { + fail("Redundant close() should be ignored"); + } + + // + // new style - using generator close + // + bOut = new ByteArrayOutputStream(); + cPacket = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + out = cPacket.open(new UncloseableOutputStream(bOut), new byte[4]); + + out.write("hello world! !dlrow olleh".getBytes()); + + cPacket.close(); + + validateData(bOut.toByteArray()); + + try + { + out.close(); + cPacket.close(); + } + catch (Exception e) + { + fail("Redundant close() should be ignored"); + } + } + + private void validateData(byte[] data) + throws IOException, PGPException + { + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(data); + PGPCompressedData c1 = (PGPCompressedData)pgpFact.nextObject(); + InputStream pIn = c1.getDataStream(); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + int ch; + while ((ch = pIn.read()) >= 0) + { + bOut.write(ch); + } + + if (!areEqual(bOut.toByteArray(), "hello world! !dlrow olleh".getBytes())) + { + fail("compression test failed"); + } + } + + private void testCompression( + int type) + throws IOException, PGPException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + PGPCompressedDataGenerator cPacket = new PGPCompressedDataGenerator(type); + + OutputStream out = cPacket.open(new UncloseableOutputStream(bOut)); + + out.write("hello world!".getBytes()); + + out.close(); + + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(bOut.toByteArray()); + PGPCompressedData c1 = (PGPCompressedData)pgpFact.nextObject(); + InputStream pIn = c1.getDataStream(); + + bOut.reset(); + + int ch; + while ((ch = pIn.read()) >= 0) + { + bOut.write(ch); + } + + if (!areEqual(bOut.toByteArray(), "hello world!".getBytes())) + { + fail("compression test failed"); + } + } + + public String getName() + { + return "PGPCompressionTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PGPCompressionTest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPDSAElGamalTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPDSAElGamalTest.java new file mode 100644 index 00000000..32a2806b --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPDSAElGamalTest.java @@ -0,0 +1,562 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.AlgorithmParameterGenerator; +import java.security.AlgorithmParameters; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Date; +import java.util.Iterator; + +import javax.crypto.Cipher; +import javax.crypto.spec.DHParameterSpec; + +import org.spongycastle.bcpg.BCPGOutputStream; +import org.spongycastle.bcpg.PublicKeyAlgorithmTags; +import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.jce.spec.ElGamalParameterSpec; +import org.spongycastle.openpgp.PGPCompressedData; +import org.spongycastle.openpgp.PGPCompressedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedDataList; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPKeyPair; +import org.spongycastle.openpgp.PGPLiteralData; +import org.spongycastle.openpgp.PGPLiteralDataGenerator; +import org.spongycastle.openpgp.PGPOnePassSignature; +import org.spongycastle.openpgp.PGPOnePassSignatureList; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPUtil; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyConverter; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.test.SimpleTest; +import org.spongycastle.util.test.UncloseableOutputStream; + +public class PGPDSAElGamalTest + extends SimpleTest +{ + + byte[] testPubKeyRing = + Base64.decode( + "mQGiBEAR8jYRBADNifuSopd20JOQ5x30ljIaY0M6927+vo09NeNxS3KqItba" + + "nz9o5e2aqdT0W1xgdHYZmdElOHTTsugZxdXTEhghyxoo3KhVcNnTABQyrrvX" + + "qouvmP2fEDEw0Vpyk+90BpyY9YlgeX/dEA8OfooRLCJde/iDTl7r9FT+mts8" + + "g3azjwCgx+pOLD9LPBF5E4FhUOdXISJ0f4EEAKXSOi9nZzajpdhe8W2ZL9gc" + + "BpzZi6AcrRZBHOEMqd69gtUxA4eD8xycUQ42yH89imEcwLz8XdJ98uHUxGJi" + + "qp6hq4oakmw8GQfiL7yQIFgaM0dOAI9Afe3m84cEYZsoAFYpB4/s9pVMpPRH" + + "NsVspU0qd3NHnSZ0QXs8L8DXGO1uBACjDUj+8GsfDCIP2QF3JC+nPUNa0Y5t" + + "wKPKl+T8hX/0FBD7fnNeC6c9j5Ir/Fp/QtdaDAOoBKiyNLh1JaB1NY6US5zc" + + "qFks2seZPjXEiE6OIDXYra494mjNKGUobA4hqT2peKWXt/uBcuL1mjKOy8Qf" + + "JxgEd0MOcGJO+1PFFZWGzLQ3RXJpYyBILiBFY2hpZG5hICh0ZXN0IGtleSBv" + + "bmx5KSA8ZXJpY0Bib3VuY3ljYXN0bGUub3JnPohZBBMRAgAZBQJAEfI2BAsH" + + "AwIDFQIDAxYCAQIeAQIXgAAKCRAOtk6iUOgnkDdnAKC/CfLWikSBdbngY6OK" + + "5UN3+o7q1ACcDRqjT3yjBU3WmRUNlxBg3tSuljmwAgAAuQENBEAR8jgQBAC2" + + "kr57iuOaV7Ga1xcU14MNbKcA0PVembRCjcVjei/3yVfT/fuCVtGHOmYLEBqH" + + "bn5aaJ0P/6vMbLCHKuN61NZlts+LEctfwoya43RtcubqMc7eKw4k0JnnoYgB" + + "ocLXOtloCb7jfubOsnfORvrUkK0+Ne6anRhFBYfaBmGU75cQgwADBQP/XxR2" + + "qGHiwn+0YiMioRDRiIAxp6UiC/JQIri2AKSqAi0zeAMdrRsBN7kyzYVVpWwN" + + "5u13gPdQ2HnJ7d4wLWAuizUdKIQxBG8VoCxkbipnwh2RR4xCXFDhJrJFQUm+" + + "4nKx9JvAmZTBIlI5Wsi5qxst/9p5MgP3flXsNi1tRbTmRhqIRgQYEQIABgUC" + + "QBHyOAAKCRAOtk6iUOgnkBStAJoCZBVM61B1LG2xip294MZecMtCwQCbBbsk" + + "JVCXP0/Szm05GB+WN+MOCT2wAgAA"); + + byte[] testPrivKeyRing = + Base64.decode( + "lQHhBEAR8jYRBADNifuSopd20JOQ5x30ljIaY0M6927+vo09NeNxS3KqItba" + + "nz9o5e2aqdT0W1xgdHYZmdElOHTTsugZxdXTEhghyxoo3KhVcNnTABQyrrvX" + + "qouvmP2fEDEw0Vpyk+90BpyY9YlgeX/dEA8OfooRLCJde/iDTl7r9FT+mts8" + + "g3azjwCgx+pOLD9LPBF5E4FhUOdXISJ0f4EEAKXSOi9nZzajpdhe8W2ZL9gc" + + "BpzZi6AcrRZBHOEMqd69gtUxA4eD8xycUQ42yH89imEcwLz8XdJ98uHUxGJi" + + "qp6hq4oakmw8GQfiL7yQIFgaM0dOAI9Afe3m84cEYZsoAFYpB4/s9pVMpPRH" + + "NsVspU0qd3NHnSZ0QXs8L8DXGO1uBACjDUj+8GsfDCIP2QF3JC+nPUNa0Y5t" + + "wKPKl+T8hX/0FBD7fnNeC6c9j5Ir/Fp/QtdaDAOoBKiyNLh1JaB1NY6US5zc" + + "qFks2seZPjXEiE6OIDXYra494mjNKGUobA4hqT2peKWXt/uBcuL1mjKOy8Qf" + + "JxgEd0MOcGJO+1PFFZWGzP4DAwLeUcsVxIC2s2Bb9ab2XD860TQ2BI2rMD/r" + + "7/psx9WQ+Vz/aFAT3rXkEJ97nFeqEACgKmUCAEk9939EwLQ3RXJpYyBILiBF" + + "Y2hpZG5hICh0ZXN0IGtleSBvbmx5KSA8ZXJpY0Bib3VuY3ljYXN0bGUub3Jn" + + "PohZBBMRAgAZBQJAEfI2BAsHAwIDFQIDAxYCAQIeAQIXgAAKCRAOtk6iUOgn" + + "kDdnAJ9Ala3OcwEV1DbK906CheYWo4zIQwCfUqUOLMp/zj6QAk02bbJAhV1r" + + "sAewAgAAnQFYBEAR8jgQBAC2kr57iuOaV7Ga1xcU14MNbKcA0PVembRCjcVj" + + "ei/3yVfT/fuCVtGHOmYLEBqHbn5aaJ0P/6vMbLCHKuN61NZlts+LEctfwoya" + + "43RtcubqMc7eKw4k0JnnoYgBocLXOtloCb7jfubOsnfORvrUkK0+Ne6anRhF" + + "BYfaBmGU75cQgwADBQP/XxR2qGHiwn+0YiMioRDRiIAxp6UiC/JQIri2AKSq" + + "Ai0zeAMdrRsBN7kyzYVVpWwN5u13gPdQ2HnJ7d4wLWAuizUdKIQxBG8VoCxk" + + "bipnwh2RR4xCXFDhJrJFQUm+4nKx9JvAmZTBIlI5Wsi5qxst/9p5MgP3flXs" + + "Ni1tRbTmRhr+AwMC3lHLFcSAtrNg/EiWFLAnKNXH27zjwuhje8u2r+9iMTYs" + + "GjbRxaxRY0GKRhttCwqe2BC0lHhzifdlEcc9yjIjuKfepG2fnnSIRgQYEQIA" + + "BgUCQBHyOAAKCRAOtk6iUOgnkBStAJ9HFejVtVJ/A9LM/mDPe0ExhEXt/QCg" + + "m/KM7hJ/JrfnLQl7IaZsdg1F6vCwAgAA"); + + byte[] encMessage = + Base64.decode( + "hQEOAynbo4lhNjcHEAP/dgCkMtPB6mIgjFvNiotjaoh4sAXf4vFNkSeehQ2c" + + "r+IMt9CgIYodJI3FoJXxOuTcwesqTp5hRzgUBJS0adLDJwcNubFMy0M2tp5o" + + "KTWpXulIiqyO6f5jI/oEDHPzFoYgBmR4x72l/YpMy8UoYGtNxNvR7LVOfqJv" + + "uDY/71KMtPQEAIadOWpf1P5Td+61Zqn2VH2UV7H8eI6hGa6Lsy4sb9iZNE7f" + + "c+spGJlgkiOt8TrQoq3iOK9UN9nHZLiCSIEGCzsEn3uNuorD++Qs065ij+Oy" + + "36TKeuJ+38CfT7u47dEshHCPqWhBKEYrxZWHUJU/izw2Q1Yxd2XRxN+nafTL" + + "X1fQ0lABQUASa18s0BkkEERIdcKQXVLEswWcGqWNv1ZghC7xO2VDBX4HrPjp" + + "drjL63p2UHzJ7/4gPWGGtnqq1Xita/1mrImn7pzLThDWiT55vjw6Hw=="); + + byte[] signedAndEncMessage = + Base64.decode( + "hQEOAynbo4lhNjcHEAP+K20MVhzdX57hf/cU8TH0prP0VePr9mmeBedzqqMn" + + "fp2p8Zb68zmcMlI/WiL5XMNLYRmCgEcXyWbKdP/XV9m9LDBe1CMAGrkCeGBy" + + "je69IQQ5LS9vDPyEMF4iAAv/EqACjqHkizdY/a/FRx/t2ioXYdEC2jA6kS9C" + + "McpsNz16DE8EAIk3uKn4bGo/+15TXkyFYzW5Cf71SfRoHNmU2zAI93zhjN+T" + + "B7mGJwWXzsMkIO6FkMU5TCSrwZS3DBWCIaJ6SYoaawE/C/2j9D7bX1Jv8kum" + + "4cq+eZM7z6JYs6xend+WAwittpUxbEiyC2AJb3fBSXPAbLqWd6J6xbZZ7GDK" + + "r2Ca0pwBxwGhbMDyi2zpHLzw95H7Ah2wMcGU6kMLB+hzBSZ6mSTGFehqFQE3" + + "2BnAj7MtnbghiefogacJ891jj8Y2ggJeKDuRz8j2iICaTOy+Y2rXnnJwfYzm" + + "BMWcd2h1C5+UeBJ9CrrLniCCI8s5u8z36Rno3sfhBnXdRmWSxExXtocbg1Ht" + + "dyiThf6TK3W29Yy/T6x45Ws5zOasaJdsFKM="); + char[] pass = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' }; + + public void performTest() + throws Exception + { + try + { + PGPPublicKey pubKey = null; + + PGPUtil.setDefaultProvider("SC"); + + // + // Read the public key + // + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(testPubKeyRing); + + PGPPublicKeyRing pgpPub = (PGPPublicKeyRing)pgpFact.nextObject(); + + pubKey = pgpPub.getPublicKey(); + + if (pubKey.getBitStrength() != 1024) + { + fail("failed - key strength reported incorrectly."); + } + + // + // Read the private key + // + PGPSecretKeyRing sKey = new PGPSecretKeyRing(testPrivKeyRing, new JcaKeyFingerprintCalculator()); + PGPPrivateKey pgpPrivKey = sKey.getSecretKey().extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(pass)); + + // + // signature generation + // + String data = "hello world!"; + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ByteArrayInputStream testIn = new ByteArrayInputStream(data.getBytes()); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(PGPPublicKey.DSA, PGPUtil.SHA1).setProvider("SC")); + + sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey); + + PGPCompressedDataGenerator cGen = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + BCPGOutputStream bcOut = new BCPGOutputStream( + cGen.open(new UncloseableOutputStream(bOut))); + + sGen.generateOnePassVersion(false).encode(bcOut); + + PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); + + Date testDate = new Date((System.currentTimeMillis() / 1000) * 1000); + OutputStream lOut = lGen.open( + new UncloseableOutputStream(bcOut), + PGPLiteralData.BINARY, + "_CONSOLE", + data.getBytes().length, + testDate); + + int ch; + while ((ch = testIn.read()) >= 0) + { + lOut.write(ch); + sGen.update((byte)ch); + } + + lGen.close(); + + sGen.generate().encode(bcOut); + + cGen.close(); + + // + // verify generated signature + // + pgpFact = new JcaPGPObjectFactory(bOut.toByteArray()); + + PGPCompressedData c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + PGPOnePassSignatureList p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + + PGPOnePassSignature ops = p1.get(0); + + PGPLiteralData p2 = (PGPLiteralData)pgpFact.nextObject(); + if (!p2.getModificationTime().equals(testDate)) + { + fail("Modification time not preserved"); + } + + InputStream dIn = p2.getInputStream(); + + ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pubKey); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + PGPSignatureList p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed generated signature check"); + } + + // + // test encryption + // + + // + // find a key suitable for encryption + // + long pgpKeyID = 0; + PublicKey pKey = null; + + Iterator it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + PGPPublicKey pgpKey = (PGPPublicKey)it.next(); + + if (pgpKey.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT + || pgpKey.getAlgorithm() == PGPPublicKey.ELGAMAL_GENERAL) + { + pKey = new JcaPGPKeyConverter().setProvider("SC").getPublicKey(pgpKey); + pgpKeyID = pgpKey.getKeyID(); + if (pgpKey.getBitStrength() != 1024) + { + fail("failed - key strength reported incorrectly."); + } + + // + // verify the key + // + + } + } + + Cipher c = Cipher.getInstance("ElGamal/None/PKCS1Padding", "SC"); + + c.init(Cipher.ENCRYPT_MODE, pKey); + + byte[] in = "hello world".getBytes(); + + byte[] out = c.doFinal(in); + + pgpPrivKey = sKey.getSecretKey(pgpKeyID).extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(pass)); + + c.init(Cipher.DECRYPT_MODE, new JcaPGPKeyConverter().setProvider("SC").getPrivateKey(pgpPrivKey)); + + out = c.doFinal(out); + + if (!areEqual(in, out)) + { + fail("decryption failed."); + } + + // + // encrypted message + // + byte[] text = { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)' ', (byte)'w', (byte)'o', (byte)'r', (byte)'l', (byte)'d', (byte)'!', (byte)'\n' }; + + JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(encMessage); + + PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpF.nextObject(); + + PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0); + + InputStream clear = encP.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("SC").build(pgpPrivKey)); + + pgpFact = new JcaPGPObjectFactory(clear); + + c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + PGPLiteralData ld = (PGPLiteralData)pgpFact.nextObject(); + + bOut = new ByteArrayOutputStream(); + + if (!ld.getFileName().equals("test.txt")) + { + throw new RuntimeException("wrong filename in packet"); + } + + InputStream inLd = ld.getDataStream(); + + while ((ch = inLd.read()) >= 0) + { + bOut.write(ch); + } + + if (!areEqual(bOut.toByteArray(), text)) + { + fail("wrong plain text in decrypted packet"); + } + + // + // signed and encrypted message + // + pgpF = new JcaPGPObjectFactory(signedAndEncMessage); + + encList = (PGPEncryptedDataList)pgpF.nextObject(); + + encP = (PGPPublicKeyEncryptedData)encList.get(0); + + clear = encP.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("SC").build(pgpPrivKey)); + + pgpFact = new JcaPGPObjectFactory(clear); + + c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + + ops = p1.get(0); + + ld = (PGPLiteralData)pgpFact.nextObject(); + + bOut = new ByteArrayOutputStream(); + + if (!ld.getFileName().equals("test.txt")) + { + throw new RuntimeException("wrong filename in packet"); + } + + inLd = ld.getDataStream(); + + // + // note: we use the DSA public key here. + // + ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pgpPub.getPublicKey()); + + while ((ch = inLd.read()) >= 0) + { + ops.update((byte)ch); + bOut.write(ch); + } + + p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed signature check"); + } + + if (!areEqual(bOut.toByteArray(), text)) + { + fail("wrong plain text in decrypted packet"); + } + + // + // encrypt + // + ByteArrayOutputStream cbOut = new ByteArrayOutputStream(); + PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.TRIPLE_DES).setSecureRandom(new SecureRandom()).setProvider("SC")); + PGPPublicKey puK = sKey.getSecretKey(pgpKeyID).getPublicKey(); + + cPk.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(puK).setProvider("SC")); + + OutputStream cOut = cPk.open(new UncloseableOutputStream(cbOut), bOut.toByteArray().length); + + cOut.write(text); + + cOut.close(); + + pgpF = new JcaPGPObjectFactory(cbOut.toByteArray()); + + encList = (PGPEncryptedDataList)pgpF.nextObject(); + + encP = (PGPPublicKeyEncryptedData)encList.get(0); + + pgpPrivKey = sKey.getSecretKey(pgpKeyID).extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(pass)); + + clear = encP.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("SC").build(pgpPrivKey)); + + bOut.reset(); + + while ((ch = clear.read()) >= 0) + { + bOut.write(ch); + } + + out = bOut.toByteArray(); + + if (!areEqual(out, text)) + { + fail("wrong plain text in generated packet"); + } + + // + // use of PGPKeyPair + // + BigInteger g = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + BigInteger p = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + KeyPairGenerator kpg = KeyPairGenerator.getInstance("ElGamal", "SC"); + + ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g); + + kpg.initialize(elParams); + + KeyPair kp = kpg.generateKeyPair(); + + PGPKeyPair pgpKp = new JcaPGPKeyPair(PGPPublicKey.ELGAMAL_GENERAL, kp, new Date()); + + PGPPublicKey k1 = pgpKp.getPublicKey(); + + PGPPrivateKey k2 = pgpKp.getPrivateKey(); + + + + // Test bug with ElGamal P size != 0 mod 8 (don't use these sizes at home!) + SecureRandom random = new SecureRandom(); + for (int pSize = 257; pSize < 264; ++pSize) + { + // Generate some parameters of the given size + AlgorithmParameterGenerator a = AlgorithmParameterGenerator.getInstance("ElGamal", "SC"); + a.init(pSize, new SecureRandom()); + AlgorithmParameters params = a.generateParameters(); + + DHParameterSpec elP = (DHParameterSpec)params.getParameterSpec(DHParameterSpec.class); + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ElGamal", "SC"); + + keyGen.initialize(elP); + + + // Run a short encrypt/decrypt test with random key for the given parameters + kp = keyGen.generateKeyPair(); + + PGPKeyPair elGamalKeyPair = new JcaPGPKeyPair( + PublicKeyAlgorithmTags.ELGAMAL_GENERAL, kp, new Date()); + + cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5).setSecureRandom(new SecureRandom()).setProvider("SC")); + + puK = elGamalKeyPair.getPublicKey(); + + cPk.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(puK).setProvider("SC")); + + cbOut = new ByteArrayOutputStream(); + + cOut = cPk.open(cbOut, text.length); + + cOut.write(text); + + cOut.close(); + + pgpF = new JcaPGPObjectFactory(cbOut.toByteArray()); + + encList = (PGPEncryptedDataList)pgpF.nextObject(); + + encP = (PGPPublicKeyEncryptedData)encList.get(0); + + pgpPrivKey = elGamalKeyPair.getPrivateKey(); + + // Note: This is where an exception would be expected if the P size causes problems + clear = encP.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("SC").build(pgpPrivKey)); + + ByteArrayOutputStream dec = new ByteArrayOutputStream(); + + int b; + while ((b = clear.read()) >= 0) + { + dec.write(b); + } + + byte[] decText = dec.toByteArray(); + + if (!areEqual(text, decText)) + { + fail("decrypted message incorrect"); + } + } + + // check sub key encoding + + it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + PGPPublicKey pgpKey = (PGPPublicKey)it.next(); + + if (!pgpKey.isMasterKey()) + { + byte[] kEnc = pgpKey.getEncoded(); + + JcaPGPObjectFactory objF = new JcaPGPObjectFactory(kEnc); + + PGPPublicKey k = (PGPPublicKey)objF.nextObject(); + + pKey = new JcaPGPKeyConverter().setProvider("SC").getPublicKey(k); + pgpKeyID = k.getKeyID(); + if (k.getBitStrength() != 1024) + { + fail("failed - key strength reported incorrectly."); + } + + if (objF.nextObject() != null) + { + fail("failed - stream not fully parsed."); + } + } + } + + } + catch (PGPException e) + { + fail("exception: " + e.getMessage(), e.getUnderlyingException()); + } + } + + public String getName() + { + return "PGPDSAElGamalTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PGPDSAElGamalTest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPDSATest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPDSATest.java new file mode 100644 index 00000000..53f1c58b --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPDSATest.java @@ -0,0 +1,635 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.Security; +import java.util.Date; +import java.util.Iterator; + +import org.spongycastle.bcpg.BCPGOutputStream; +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.bcpg.PublicKeyAlgorithmTags; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPCompressedData; +import org.spongycastle.openpgp.PGPCompressedDataGenerator; +import org.spongycastle.openpgp.PGPKeyPair; +import org.spongycastle.openpgp.PGPLiteralData; +import org.spongycastle.openpgp.PGPLiteralDataGenerator; +import org.spongycastle.openpgp.PGPOnePassSignature; +import org.spongycastle.openpgp.PGPOnePassSignatureList; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; +import org.spongycastle.openpgp.PGPUtil; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyConverter; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.test.SimpleTest; +import org.spongycastle.util.test.UncloseableOutputStream; + +public class PGPDSATest + extends SimpleTest +{ + byte[] testPubKey = + Base64.decode( + "mQGiBD9HBzURBACzkxRCVGJg5+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/V2X1y26VKsipolPfja4uyBOOyvbLQzRXJpYyBFY2hp" + + "ZG5hIChEU0EgVGVzdCBLZXkpIDxlcmljQGJvdW5jeWNhc3RsZS5vcmc+iFkEExEC" + + "ABkFAj9HBzUECwcDAgMVAgMDFgIBAh4BAheAAAoJEM0j9enEyjRDAlwAn2rrom0s" + + "MhufWK5vIRwg7gj5qsLEAJ4vnT5dPBVblofsG+pDoCVeJXGGng=="); + + byte[] testPrivKey = + 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=="); + + byte[] testPrivKey2 = + Base64.decode( + "lQHhBEAnoewRBADRvKgDhbV6pMzqYfUgBsLxSHzmycpuxGbjMrpyKHDOEemj" + + "iQb6TyyBKUoR28/pfshFP9R5urtKIT7wjVrDuOkxYkgRhNm+xmPXW2Lw3D++" + + "MQrC5VWe8ywBltz6T9msmChsaKo2hDhIiRI/mg9Q6rH9pJKtVGi4R7CgGxM2" + + "STQ5fwCgub38qGS1W2O4hUsa+3gva5gaNZUEAItegda4/H4t88XdWxW3D8pv" + + "RnFz26/ADdImVaQlBoumD15VmcgYoT1Djizey7X8vfV+pntudESzLbn3GHlI" + + "6C09seH4e8eYP63t7KU/qbUCDomlSswd1OgQ/RxfN86q765K2t3K1i3wDSxe" + + "EgSRyGKee0VNvOBFOFhuWt+patXaBADE1riNkUxg2P4lBNWwu8tEZRmsl/Ys" + + "DBIzXBshoMzZCvS5PnNXMW4G3SAaC9OC9jvKSx9IEWhKjfjs3QcWzXR28mcm" + + "5na0bTxeOMlaPPhBdkTCmFl0IITWlH/pFlR2ah9WYoWYhZEL2tqB82wByzxH" + + "SkSeD9V5oeSCdCcqiqkEmv4DAwLeNsQ2XGJVRmA4lld+CR5vRxpT/+/2xklp" + + "lxVf/nx0+thrHDpro3u/nINIIObk0gh59+zaEEe3APlHqbQVYWFhIGJiYiA8" + + "Y2NjQGRkZC5lZWU+iFoEExECABoFAkAnoewFCwcDAgEDFQIDAxYCAQIeAQIX" + + "gAAKCRA5nBpCS63az85BAKCbPfU8ATrFvkXhzGNGlc1BJo6DWQCgnK125xVK" + + "lWLpt6ZJJ7TXcx3nkm6wAgAAnQFXBEAnoe0QBACsQxPvaeBcv2TkbgU/5Wc/" + + "tO222dPE1mxFbXjGTKfb+6ge96iyD8kTRLrKCkEEeVBa8AZqMSoXUVN6tV8j" + + "/zD8Bc76o5iJ6wgpg3Mmy2GxInVfsfZN6/G3Y2ukmouz+CDNvQdUw8cTguIb" + + "QoV3XhQ03MLbfVmNcHsku9F4CuKNWwADBQP0DSSe8v5PXF9CSCXOIxBDcQ5x" + + "RKjyYOveqoH/4lbOV0YNUbIDZq4RaUdotpADuPREFmWf0zTB6KV/WIiag8XU" + + "WU9zdDvLKR483Bo6Do5pDBcN+NqfQ+ntGY9WJ7BSFnhQ3+07i1K+NsfFTRfv" + + "hf9X3MP75rCf7MxAIWHTabEmUf4DAwLeNsQ2XGJVRmA8DssBUCghogG9n8T3" + + "qfBeKsplGyCcF+JjPeQXkKQaoYGJ0aJz36qFP9d8DuWtT9soQcqIxVf6mTa8" + + "kN1594hGBBgRAgAGBQJAJ6HtAAoJEDmcGkJLrdrPpMkAnRyjQSKugz0YJqOB" + + "yGasMLQLxd2OAKCEIlhtCarlufVQNGZsuWxHVbU8crACAAA="); + + byte[] sig1 = + Base64.decode( + "owGbwMvMwCR4VvnryyOnTJwZ10gncZSkFpfolVSU2Ltz78hIzcnJVyjPL8pJUeTq" + + "sGdmZQCJwpQLMq3ayTA/0Fj3xf4jbwPfK/H3zj55Z9L1n2k/GOapKJrvMZ4tLiCW" + + "GtP/XeDqX4fORDUA"); + + byte[] sig1crc = Base64.decode("OZa/"); + + byte[] testPubWithUserAttr = + Base64.decode( + "mQGiBD2Rqv0RBADqKCkhVEtB/lEEr/9CubuHEy2oN/yU5j+2GXSdcNdVnRI/rwFy" + + "fHEQIk3uU7zHSUKFrC59yDm0sODYyjEdE3BVb0xvEJ5LE/OdndcIMXT1DungZ1vB" + + "zIK/3lr33W/PHixYxv9jduH3WrTehBpiKkgMZp8XloSFj2Cnw9LDyfqB7QCg/8K1" + + "o2k75NkOd9ZjnA9ye7Ri3bEEAKyr61Mo7viPWBK1joWAEsxG0OBWM+iSlG7kwh31" + + "8efgC/7Os6x4Y0jzs8mpcbBjeZtZjS9lRbfp7RinhF269xL0TZ3JxIdtaAV/6yDQ" + + "9NXfZY9dskN++HIR/5GCEEgq/qTJZt6ti5k7aV19ZFfO6wiK3NUy08wOrVsdOkVE" + + "w9IcBADaplhpcel3201uU3OCboogJtw81R5MJMZ4Y9cKL/ca2jGISn0nA7KrAw9v" + + "ShheSixGO4BV9JECkLEbtg7i+W/j/De6S+x2GLNcphuTP3UmgtKbhs0ItRqzW561" + + "s6gLkqi6aWmgaFLd8E1pMJcd9DSY95P13EYB9VJIUxFNUopzo7QcUmFsZiBIYXVz" + + "ZXIgPGhhdXNlckBhY20ub3JnPokAWAQQEQIAGAUCPZGq/QgLAwkIBwIBCgIZAQUb" + + "AwAAAAAKCRAqIBiOh4JvOKg4AJ9j14yygOqqzqiLKeaasIzqT8LCIgCggx14WuLO" + + "wOUTUswTaVKMFnU7tseJAJwEEAECAAYFAj2Rqx8ACgkQ9aWTKMpUDFV+9QP/RiWT" + + "5FAF5Rgb7beaApsgXsME+Pw7HEYFtqGa6VcXEpbcUXO6rjaXsgMgY90klWlWCF1T" + + "HOyKITvj2FdhE+0j8NQn4vaGpiTwORW/zMf/BZ0abdSWQybp10Yjs8gXw30UheO+" + + "F1E524MC+s2AeUi2hwHMiS+AVYd4WhxWHmWuBpTRypP/AAALTgEQAAEBAAAAAQAA" + + "AAABAAAA/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAoHBwgHBgoICAgLCgoLDhgQ" + + "Dg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/" + + "2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7" + + "Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wAARCABqAF0DASIAAhEBAxEB/8QAHwAAAQUB" + + "AQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQID" + + "AAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0" + + "NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKT" + + "lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl" + + "5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL" + + "/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHB" + + "CSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpj" + + "ZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3" + + "uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIR" + + "AxEAPwD2aiiq9xcxWsRllcKqjOT06E/0oAsVm6jrmm6VGXvLuOPGflz8x+grzXxV" + + "8U51u5LXRgBGowZHXknnkc9OQcV51caneXdw9xPOXlckl2AJHY4J6cD1oA9J1z4p" + + "TRkrYQhRyQ0hIY5/2QRx7k9ulczN8SvEEshdZkX0UorDrznI759a5Mksckkknqec" + + "mkoA7WD4oavEoEttbTepYEZ+mCMVv6H8SLTULhbe/gFozAYkD5Unp3Ax/kV5XRQB" + + "9EAhgCDkHkEcgilryTwd4zn0m4WzvpTJZSMBuY5MfbueletKyugZWDKwyCOc/j3o" + + "AduyWLDeWB5Ynj8jSUUUAdFXn/xU15dO0RbGGYC5uWwUB6L1Jx+n413F1cJa2stz" + + "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" + + "7DGrzw=="); + + byte[] aesSecretKey = Base64.decode( + "lQHpBEBSdIYRBADpd7MeIxRk4RsvyMnJNIYe4FiVv6i7I7+LPRvnIjDct0bN" + + "1gCV48QFej7g/PsvXRjYSowV3VIvchWX8OERd/5i10cLbcs7X52EP1vwYaLj" + + "uRfNUBg8Q51RQsKR+/rBmnVsi68rjU4yTH6wpo6FOO4pz4wFV+tWwGOwOitA" + + "K31L4wCgqh59eFFBrOlRFAbDvaL7emoCIR8EAOLxDKiLQJYQrKZfXdZnifeo" + + "dhEP0uuV4O5TG6nrqkhWffzC9cSoFD0BhMl979d8IB2Uft4FNvQc2u8hbJL5" + + "7OCGDCUAidlB9jSdu0/J+kfRaTGhYDjBgw7AA42576BBSMNouJg/aOOQENEN" + + "Nn4n7NxR3viBzIsL/OIeU8HSkBgaA/41PsvcgZ3kwpdltJ/FVRWhmMmv/q/X" + + "qp1YOnF8xPU9bv2ofELrxJfRsbS4GW1etzD+nXs/woW4Vfixs01x+cutR4iF" + + "3hw+eU+yLToMPmmo8D2LUvX1SRODJpx5yBBeRIYv6nz9H3sQRDx3kaLASxDV" + + "jTxKmrLYnZz5w5qyVpvRyv4JAwKyWlhdblPudWBFXNkW5ydKn0AV2f51wEtj" + + "Zy0aLIeutVMSJf1ytLqjFqrnFe6pdJrHO3G00TE8OuFhftWosLGLbEGytDtF" + + "cmljIEguIEVjaGlkbmEgKHRlc3Qga2V5IC0gQUVTMjU2KSA8ZXJpY0Bib3Vu" + + "Y3ljYXN0bGUub3JnPohZBBMRAgAZBQJAUnSGBAsHAwIDFQIDAxYCAQIeAQIX" + + "gAAKCRBYt1NnUiCgeFKaAKCiqtOO+NQES1gJW6XuOGmSkXt8bQCfcuW7SXZH" + + "zxK1FfdcG2HEDs3YEVawAgAA"); + + byte[] aesPublicKey = Base64.decode( + "mQGiBEBSdIYRBADpd7MeIxRk4RsvyMnJNIYe4FiVv6i7I7+LPRvnIjDct0bN" + + "1gCV48QFej7g/PsvXRjYSowV3VIvchWX8OERd/5i10cLbcs7X52EP1vwYaLj" + + "uRfNUBg8Q51RQsKR+/rBmnVsi68rjU4yTH6wpo6FOO4pz4wFV+tWwGOwOitA" + + "K31L4wCgqh59eFFBrOlRFAbDvaL7emoCIR8EAOLxDKiLQJYQrKZfXdZnifeo" + + "dhEP0uuV4O5TG6nrqkhWffzC9cSoFD0BhMl979d8IB2Uft4FNvQc2u8hbJL5" + + "7OCGDCUAidlB9jSdu0/J+kfRaTGhYDjBgw7AA42576BBSMNouJg/aOOQENEN" + + "Nn4n7NxR3viBzIsL/OIeU8HSkBgaA/41PsvcgZ3kwpdltJ/FVRWhmMmv/q/X" + + "qp1YOnF8xPU9bv2ofELrxJfRsbS4GW1etzD+nXs/woW4Vfixs01x+cutR4iF" + + "3hw+eU+yLToMPmmo8D2LUvX1SRODJpx5yBBeRIYv6nz9H3sQRDx3kaLASxDV" + + "jTxKmrLYnZz5w5qyVpvRyrQ7RXJpYyBILiBFY2hpZG5hICh0ZXN0IGtleSAt" + + "IEFFUzI1NikgPGVyaWNAYm91bmN5Y2FzdGxlLm9yZz6IWQQTEQIAGQUCQFJ0" + + "hgQLBwMCAxUCAwMWAgECHgECF4AACgkQWLdTZ1IgoHhSmgCfU83BLBF2nCua" + + "zk2dXB9zO1l6XS8AnA07U4cq5W0GrKM6/kP9HWtPhgOFsAIAAA=="); + + byte[] twofishSecretKey = Base64.decode( + "lQHpBEBSdtIRBACf7WfrqTl8F051+EbaljPf/8/ajFpAfMq/7p3Hri8OCsuc" + + "fJJIufEEOV1/Lt/wkN67MmSyrU0fUCsRbEckRiB4EJ0zGHVFfAnku2lzdgc8" + + "AVounqcHOmqA/gliFDEnhYOx3bOIAOav+yiOqfKVBhWRCpFdOTE+w/XoDM+p" + + "p8bH5wCgmP2FuWpzfSut7GVKp51xNEBRNuED/3t2Q+Mq834FVynmLKEmeXB/" + + "qtIz5reHEQR8eMogsOoJS3bXs6v3Oblj4in1gLyTVfcID5tku6kLP20xMRM2" + + "zx2oRbz7TyOCrs15IpRXyqqJxUWD8ipgJPkPXE7hK8dh4YSTUi4i5a1ug8xG" + + "314twlPzrchpWZiutDvZ+ks1rzOtBACHrEFG2frUu+qVkL43tySE0cV2bnuK" + + "LVhXbpzF3Qdkfxou2nuzsCbl6m87OWocJX8uYcQGlHLKv8Q2cfxZyieLFg6v" + + "06LSFdE9drGBWz7mbrT4OJjxPyvnkffPfLOOqae3PMYIIuscvswuhm4X5aoj" + + "KJs01YT3L6f0iIj03hCeV/4KAwLcGrxT3X0qR2CZyZYSVBdjXeNYKXuGBtOf" + + "ood26WOtwLw4+l9sHVoiXNv0LomkO58ndJRPGCeZWZEDMVrfkS7rcOlktDxF" + + "cmljIEguIEVjaGlkbmEgKHRlc3Qga2V5IC0gdHdvZmlzaCkgPGVyaWNAYm91" + + "bmN5Y2FzdGxlLm9yZz6IWQQTEQIAGQUCQFJ20gQLBwMCAxUCAwMWAgECHgEC" + + "F4AACgkQaCCMaHh9zR2+RQCghcQwlt4B4YmNxp2b3v6rP3E8M0kAn2Gspi4u" + + "A/ynoqnC1O8HNlbjPdlVsAIAAA=="); + + byte[] twofishPublicKey = Base64.decode( + "mQGiBEBSdtIRBACf7WfrqTl8F051+EbaljPf/8/ajFpAfMq/7p3Hri8OCsuc" + + "fJJIufEEOV1/Lt/wkN67MmSyrU0fUCsRbEckRiB4EJ0zGHVFfAnku2lzdgc8" + + "AVounqcHOmqA/gliFDEnhYOx3bOIAOav+yiOqfKVBhWRCpFdOTE+w/XoDM+p" + + "p8bH5wCgmP2FuWpzfSut7GVKp51xNEBRNuED/3t2Q+Mq834FVynmLKEmeXB/" + + "qtIz5reHEQR8eMogsOoJS3bXs6v3Oblj4in1gLyTVfcID5tku6kLP20xMRM2" + + "zx2oRbz7TyOCrs15IpRXyqqJxUWD8ipgJPkPXE7hK8dh4YSTUi4i5a1ug8xG" + + "314twlPzrchpWZiutDvZ+ks1rzOtBACHrEFG2frUu+qVkL43tySE0cV2bnuK" + + "LVhXbpzF3Qdkfxou2nuzsCbl6m87OWocJX8uYcQGlHLKv8Q2cfxZyieLFg6v" + + "06LSFdE9drGBWz7mbrT4OJjxPyvnkffPfLOOqae3PMYIIuscvswuhm4X5aoj" + + "KJs01YT3L6f0iIj03hCeV7Q8RXJpYyBILiBFY2hpZG5hICh0ZXN0IGtleSAt" + + "IHR3b2Zpc2gpIDxlcmljQGJvdW5jeWNhc3RsZS5vcmc+iFkEExECABkFAkBS" + + "dtIECwcDAgMVAgMDFgIBAh4BAheAAAoJEGggjGh4fc0dvkUAn2QGdNk8Wrrd" + + "+DvKECrO5+yoPRx3AJ91DhCMme6uMrQorKSDYxHlgc7iT7ACAAA="); + + char[] pass = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' }; + + /** + * Generated signature test + * + * @param sKey + * @param pgpPrivKey + */ + public void generateTest( + PGPSecretKeyRing sKey, + PGPPublicKey pgpPubKey, + PGPPrivateKey pgpPrivKey) + throws Exception + { + String data = "hello world!"; + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ByteArrayInputStream testIn = new ByteArrayInputStream(data.getBytes()); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1).setProvider("SC")); + + sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey); + + PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); + + Iterator it = sKey.getSecretKey().getPublicKey().getUserIDs(); + String primaryUserID = (String)it.next(); + + spGen.setSignerUserID(true, primaryUserID); + + sGen.setHashedSubpackets(spGen.generate()); + + PGPCompressedDataGenerator cGen = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + BCPGOutputStream bcOut = new BCPGOutputStream( + cGen.open(new UncloseableOutputStream(bOut))); + + sGen.generateOnePassVersion(false).encode(bcOut); + + PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); + + Date testDate = new Date((System.currentTimeMillis() / 1000) * 1000); + OutputStream lOut = lGen.open( + new UncloseableOutputStream(bcOut), + PGPLiteralData.BINARY, + "_CONSOLE", + data.getBytes().length, + testDate); + + int ch; + while ((ch = testIn.read()) >= 0) + { + lOut.write(ch); + sGen.update((byte)ch); + } + + lGen.close(); + + sGen.generate().encode(bcOut); + + cGen.close(); + + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(bOut.toByteArray()); + PGPCompressedData c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + + PGPOnePassSignatureList p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + PGPOnePassSignature ops = p1.get(0); + + PGPLiteralData p2 = (PGPLiteralData)pgpFact.nextObject(); + if (!p2.getModificationTime().equals(testDate)) + { + fail("Modification time not preserved"); + } + + InputStream dIn = p2.getInputStream(); + + ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pgpPubKey); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + PGPSignatureList p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed generated signature check"); + } + } + + public void performTest() + throws Exception + { + String file = null; + KeyFactory fact = KeyFactory.getInstance("DSA", "SC"); + PGPPublicKey pubKey = null; + PrivateKey privKey = null; + + PGPUtil.setDefaultProvider("SC"); + + // + // Read the public key + // + PGPPublicKeyRing pgpPub = new PGPPublicKeyRing(testPubKey, new JcaKeyFingerprintCalculator()); + + pubKey = pgpPub.getPublicKey(); + + // + // Read the private key + // + PGPSecretKeyRing sKey = new PGPSecretKeyRing(testPrivKey, new JcaKeyFingerprintCalculator()); + PGPPrivateKey pgpPrivKey = sKey.getSecretKey().extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(pass)); + + // + // test signature message + // + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(sig1); + + PGPCompressedData c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + PGPOnePassSignatureList p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + + PGPOnePassSignature ops = p1.get(0); + + PGPLiteralData p2 = (PGPLiteralData)pgpFact.nextObject(); + + InputStream dIn = p2.getInputStream(); + int ch; + + ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pubKey); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + PGPSignatureList p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed signature check"); + } + + // + // signature generation + // + generateTest(sKey, pubKey, pgpPrivKey); + + // + // signature generation - canonical text + // + String data = "hello world!"; + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ByteArrayInputStream testIn = new ByteArrayInputStream(data.getBytes()); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(PGPPublicKey.DSA, PGPUtil.SHA1).setProvider("SC")); + + sGen.init(PGPSignature.CANONICAL_TEXT_DOCUMENT, pgpPrivKey); + + PGPCompressedDataGenerator cGen = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + BCPGOutputStream bcOut = new BCPGOutputStream( + cGen.open(new UncloseableOutputStream(bOut))); + + sGen.generateOnePassVersion(false).encode(bcOut); + + PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); + Date testDate = new Date((System.currentTimeMillis() / 1000) * 1000); + OutputStream lOut = lGen.open( + new UncloseableOutputStream(bcOut), + PGPLiteralData.TEXT, + "_CONSOLE", + data.getBytes().length, + testDate); + + while ((ch = testIn.read()) >= 0) + { + lOut.write(ch); + sGen.update((byte)ch); + } + + lGen.close(); + + sGen.generate().encode(bcOut); + + cGen.close(); + + // + // verify generated signature - canconical text + // + pgpFact = new JcaPGPObjectFactory(bOut.toByteArray()); + + c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + + ops = p1.get(0); + + p2 = (PGPLiteralData)pgpFact.nextObject(); + if (!p2.getModificationTime().equals(testDate)) + { + fail("Modification time not preserved"); + } + + dIn = p2.getInputStream(); + + ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pubKey); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed generated signature check"); + } + + // + // Read the public key with user attributes + // + pgpPub = new PGPPublicKeyRing(testPubWithUserAttr, new JcaKeyFingerprintCalculator()); + + pubKey = pgpPub.getPublicKey(); + + Iterator it = pubKey.getUserAttributes(); + int count = 0; + while (it.hasNext()) + { + PGPUserAttributeSubpacketVector attributes = (PGPUserAttributeSubpacketVector)it.next(); + + Iterator sigs = pubKey.getSignaturesForUserAttribute(attributes); + int sigCount = 0; + while (sigs.hasNext()) + { + sigs.next(); + + sigCount++; + } + + if (sigCount != 1) + { + fail("Failed user attributes signature check"); + } + count++; + } + + if (count != 1) + { + fail("Failed user attributes check"); + } + + byte[] pgpPubBytes = pgpPub.getEncoded(); + + pgpPub = new PGPPublicKeyRing(pgpPubBytes, new JcaKeyFingerprintCalculator()); + + pubKey = pgpPub.getPublicKey(); + + it = pubKey.getUserAttributes(); + count = 0; + while (it.hasNext()) + { + it.next(); + count++; + } + + if (count != 1) + { + fail("Failed user attributes reread"); + } + + // + // reading test extra data - key with edge condition for DSA key password. + // + char [] passPhrase = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + + sKey = new PGPSecretKeyRing(testPrivKey2, new JcaKeyFingerprintCalculator()); + pgpPrivKey = sKey.getSecretKey().extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(passPhrase)); + + byte[] bytes = new JcaPGPKeyConverter().setProvider("SC").getPrivateKey(pgpPrivKey).getEncoded(); + + // + // reading test - aes256 encrypted passphrase. + // + sKey = new PGPSecretKeyRing(aesSecretKey, new JcaKeyFingerprintCalculator()); + pgpPrivKey = sKey.getSecretKey().extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(pass)); + + bytes = new JcaPGPKeyConverter().setProvider("SC").getPrivateKey(pgpPrivKey).getEncoded(); + + // + // reading test - twofish encrypted passphrase. + // + sKey = new PGPSecretKeyRing(twofishSecretKey, new JcaKeyFingerprintCalculator()); + pgpPrivKey = sKey.getSecretKey().extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(pass)); + + bytes = new JcaPGPKeyConverter().setProvider("SC").getPrivateKey(pgpPrivKey).getEncoded(); + + // + // use of PGPKeyPair + // + KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA", "SC"); + + kpg.initialize(512); + + KeyPair kp = kpg.generateKeyPair(); + + PGPKeyPair pgpKp = new JcaPGPKeyPair(PGPPublicKey.DSA , kp, new Date()); + + PGPPublicKey k1 = pgpKp.getPublicKey(); + + PGPPrivateKey k2 = pgpKp.getPrivateKey(); + } + + public String getName() + { + return "PGPDSATest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PGPDSATest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPECDHTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPECDHTest.java new file mode 100644 index 00000000..1526e825 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPECDHTest.java @@ -0,0 +1,394 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.security.Security; +import java.security.SignatureException; +import java.security.spec.ECGenParameterSpec; +import java.util.Date; +import java.util.Iterator; + +import org.spongycastle.asn1.nist.NISTNamedCurves; +import org.spongycastle.asn1.x9.X9ECParameters; +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.generators.ECKeyPairGenerator; +import org.spongycastle.crypto.params.ECKeyGenerationParameters; +import org.spongycastle.crypto.params.ECNamedDomainParameters; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPEncryptedData; +import org.spongycastle.openpgp.PGPEncryptedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedDataList; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPKeyPair; +import org.spongycastle.openpgp.PGPKeyRingGenerator; +import org.spongycastle.openpgp.PGPLiteralData; +import org.spongycastle.openpgp.PGPLiteralDataGenerator; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPUtil; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.openpgp.operator.KeyFingerPrintCalculator; +import org.spongycastle.openpgp.operator.PGPDigestCalculator; +import org.spongycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder; +import org.spongycastle.openpgp.operator.bc.BcPGPKeyPair; +import org.spongycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory; +import org.spongycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator; +import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.test.SimpleTest; +import org.spongycastle.util.test.UncloseableOutputStream; + +public class PGPECDHTest + extends SimpleTest +{ + byte[] testPubKey = + Base64.decode( + "mFIEUb4GwBMIKoZIzj0DAQcCAwS8p3TFaRAx58qCG63W+UNthXBPSJDnVDPTb/sT" + + "iXePaAZ/Gh1GKXTq7k6ab/67MMeVFp/EdySumqdWLtvceFKstFBUZXN0IEVDRFNB" + + "LUVDREggKEtleSBhbmQgc3Via2V5IGFyZSAyNTYgYml0cyBsb25nKSA8dGVzdC5l" + + "Y2RzYS5lY2RoQGV4YW1wbGUuY29tPoh6BBMTCAAiBQJRvgbAAhsDBgsJCAcDAgYV" + + "CAIJCgsEFgIDAQIeAQIXgAAKCRD3wDlWjFo9U5O2AQDi89NO6JbaIObC63jMMWsi" + + "AaQHrBCPkDZLibgNv73DLgD/faouH4YZJs+cONQBPVnP1baG1NpWR5ppN3JULFcr" + + "hcq4VgRRvgbAEggqhkjOPQMBBwIDBLtY8Nmfz0zSEa8C1snTOWN+VcT8pXPwgJRy" + + "z6kSP4nPt1xj1lPKj5zwPXKWxMkPO9ocqhKdg2mOh6/rc1ObIoMDAQgHiGEEGBMI" + + "AAkFAlG+BsACGwwACgkQ98A5VoxaPVN8cgEAj4dMNMNwRSg2ZBWunqUAHqIedVbS" + + "dmwmbysD192L3z4A/ReXEa0gtv8OFWjuALD1ovEK8TpDORLUb6IuUb5jUIzY"); + + byte[] testPrivKey = + Base64.decode( + "lKUEUb4GwBMIKoZIzj0DAQcCAwS8p3TFaRAx58qCG63W+UNthXBPSJDnVDPTb/sT" + + "iXePaAZ/Gh1GKXTq7k6ab/67MMeVFp/EdySumqdWLtvceFKs/gcDAo11YYCae/K2" + + "1uKGJ/uU4b4QHYnPIsAdYpuo5HIdoAOL/WwduRa8C6vSFrtMJLDqPK3BUpMz3CXN" + + "GyMhjuaHKP5MPbBZkIfgUGZO5qvU9+i0UFRlc3QgRUNEU0EtRUNESCAoS2V5IGFu" + + "ZCBzdWJrZXkgYXJlIDI1NiBiaXRzIGxvbmcpIDx0ZXN0LmVjZHNhLmVjZGhAZXhh" + + "bXBsZS5jb20+iHoEExMIACIFAlG+BsACGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4B" + + "AheAAAoJEPfAOVaMWj1Tk7YBAOLz007oltog5sLreMwxayIBpAesEI+QNkuJuA2/" + + "vcMuAP99qi4fhhkmz5w41AE9Wc/VtobU2lZHmmk3clQsVyuFyg=="); + + byte[] testMessage = + Base64.decode( + "hH4Dp5+FdoujIBwSAgMErx4BSvgXY3irwthgxU8zPoAoR+8rhmxdpwbw6ZJAO2GX" + + "azWJ85JNcobHKDeGeUq6wkTFu+g6yG99gIX8J5xJAjBRhyCRcaFgwbdDV4orWTe3" + + "iewiT8qs4BQ23e0c8t+thdKoK4thMsCJy7wSKqY0sJTSVAELroNbCOi2lcO15YmW" + + "6HiuFH7VKWcxPUBjXwf5+Z3uOKEp28tBgNyDrdbr1BbqlgYzIKq/pe9zUbUXfitn" + + "vFc6HcGhvmRQreQ+Yw1x3x0HJeoPwg=="); + + private void generate() + throws Exception + { + // + // Generate a master key + // + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDSA", "SC"); + + keyGen.initialize(new ECGenParameterSpec("P-256")); + + KeyPair kpSign = keyGen.generateKeyPair(); + + PGPKeyPair ecdsaKeyPair = new JcaPGPKeyPair(PGPPublicKey.ECDSA, kpSign, new Date()); + + // + // Generate an encryption key + // + keyGen = KeyPairGenerator.getInstance("ECDH", "SC"); + + keyGen.initialize(new ECGenParameterSpec("P-256")); + + KeyPair kpEnc = keyGen.generateKeyPair(); + + PGPKeyPair ecdhKeyPair = new JcaPGPKeyPair(PGPPublicKey.ECDH, kpEnc, new Date()); + + // + // generate a key ring + // + char[] passPhrase = "test".toCharArray(); + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, ecdsaKeyPair, + "test@bouncycastle.org", sha1Calc, null, null, + new JcaPGPContentSignerBuilder(ecdsaKeyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1), + new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, sha1Calc).setProvider("SC").build(passPhrase)); + + keyRingGen.addSubKey(ecdhKeyPair); + + PGPPublicKeyRing pubRing = keyRingGen.generatePublicKeyRing(); + + // TODO: add check of KdfParameters + doBasicKeyRingCheck(pubRing); + + PGPSecretKeyRing secRing = keyRingGen.generateSecretKeyRing(); + + KeyFingerPrintCalculator fingerCalc = new JcaKeyFingerprintCalculator(); + + PGPPublicKeyRing pubRingEnc = new PGPPublicKeyRing(pubRing.getEncoded(), fingerCalc); + + if (!Arrays.areEqual(pubRing.getEncoded(), pubRingEnc.getEncoded())) + { + fail("public key ring encoding failed"); + } + + PGPSecretKeyRing secRingEnc = new PGPSecretKeyRing(secRing.getEncoded(), fingerCalc); + + if (!Arrays.areEqual(secRing.getEncoded(), secRingEnc.getEncoded())) + { + fail("secret key ring encoding failed"); + } + + PGPPrivateKey pgpPrivKey = secRing.getSecretKey().extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("SC").build(passPhrase)); + } + + private void testDecrypt(PGPSecretKeyRing secretKeyRing) + throws Exception + { + JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(testMessage); + + PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpF.nextObject(); + + PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0); + + PGPSecretKey secretKey = secretKeyRing.getSecretKey(); // secretKeyRing.getSecretKey(encP.getKeyID()); + +// PGPPrivateKey pgpPrivKey = secretKey.extractPrivateKey(new JcePBESecretKeyEncryptorBuilder()); + +// clear = encP.getDataStream(pgpPrivKey, "SC"); +// +// bOut.reset(); +// +// while ((ch = clear.read()) >= 0) +// { +// bOut.write(ch); +// } +// +// out = bOut.toByteArray(); +// +// if (!areEqual(out, text)) +// { +// fail("wrong plain text in generated packet"); +// } + } + + private void encryptDecryptTest() + throws Exception + { + byte[] text = { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)' ', (byte)'w', (byte)'o', (byte)'r', (byte)'l', (byte)'d', (byte)'!', (byte)'\n' }; + + + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDH", "SC"); + + keyGen.initialize(new ECGenParameterSpec("P-256")); + + KeyPair kpEnc = keyGen.generateKeyPair(); + + PGPKeyPair ecdhKeyPair = new JcaPGPKeyPair(PGPPublicKey.ECDH, kpEnc, new Date()); + + PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator(); + ByteArrayOutputStream ldOut = new ByteArrayOutputStream(); + OutputStream pOut = lData.open(ldOut, PGPLiteralDataGenerator.UTF8, PGPLiteralData.CONSOLE, text.length, new Date()); + + pOut.write(text); + + pOut.close(); + + byte[] data = ldOut.toByteArray(); + + ByteArrayOutputStream cbOut = new ByteArrayOutputStream(); + + PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5).setProvider("SC").setSecureRandom(new SecureRandom())); + + cPk.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(ecdhKeyPair.getPublicKey()).setProvider("SC")); + + OutputStream cOut = cPk.open(new UncloseableOutputStream(cbOut), data.length); + + cOut.write(data); + + cOut.close(); + + JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(cbOut.toByteArray()); + + PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpF.nextObject(); + + PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0); + + InputStream clear = encP.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("SC").build(ecdhKeyPair.getPrivateKey())); + + pgpF = new JcaPGPObjectFactory(clear); + + PGPLiteralData ld = (PGPLiteralData)pgpF.nextObject(); + + clear = ld.getInputStream(); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + int ch; + while ((ch = clear.read()) >= 0) + { + bOut.write(ch); + } + + byte[] out = bOut.toByteArray(); + + if (!areEqual(out, text)) + { + fail("wrong plain text in generated packet"); + } + } + + private void encryptDecryptBCTest() + throws Exception + { + byte[] text = { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)' ', (byte)'w', (byte)'o', (byte)'r', (byte)'l', (byte)'d', (byte)'!', (byte)'\n' }; + + + ECKeyPairGenerator keyGen = new ECKeyPairGenerator(); + + X9ECParameters x9ECParameters = NISTNamedCurves.getByName("P-256"); + keyGen.init(new ECKeyGenerationParameters(new ECNamedDomainParameters(NISTNamedCurves.getOID("P-256"), x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()), new SecureRandom())); + + AsymmetricCipherKeyPair kpEnc = keyGen.generateKeyPair(); + + PGPKeyPair ecdhKeyPair = new BcPGPKeyPair(PGPPublicKey.ECDH, kpEnc, new Date()); + + PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator(); + ByteArrayOutputStream ldOut = new ByteArrayOutputStream(); + OutputStream pOut = lData.open(ldOut, PGPLiteralDataGenerator.UTF8, PGPLiteralData.CONSOLE, text.length, new Date()); + + pOut.write(text); + + pOut.close(); + + byte[] data = ldOut.toByteArray(); + + ByteArrayOutputStream cbOut = new ByteArrayOutputStream(); + + PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5).setSecureRandom(new SecureRandom())); + + cPk.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(ecdhKeyPair.getPublicKey())); + + OutputStream cOut = cPk.open(new UncloseableOutputStream(cbOut), data.length); + + cOut.write(data); + + cOut.close(); + + JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(cbOut.toByteArray()); + + PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpF.nextObject(); + + PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0); + + InputStream clear = encP.getDataStream(new BcPublicKeyDataDecryptorFactory(ecdhKeyPair.getPrivateKey())); + + pgpF = new JcaPGPObjectFactory(clear); + + PGPLiteralData ld = (PGPLiteralData)pgpF.nextObject(); + + clear = ld.getInputStream(); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + int ch; + while ((ch = clear.read()) >= 0) + { + bOut.write(ch); + } + + byte[] out = bOut.toByteArray(); + + if (!areEqual(out, text)) + { + fail("wrong plain text in generated packet"); + } + } + + public void performTest() + throws Exception + { + PGPUtil.setDefaultProvider("SC"); + + // + // Read the public key + // + PGPPublicKeyRing pubKeyRing = new PGPPublicKeyRing(testPubKey, new JcaKeyFingerprintCalculator()); + + doBasicKeyRingCheck(pubKeyRing); + + // + // Read the private key + // + PGPSecretKeyRing secretKeyRing = new PGPSecretKeyRing(testPrivKey, new JcaKeyFingerprintCalculator()); + + testDecrypt(secretKeyRing); + + encryptDecryptTest(); + encryptDecryptBCTest(); + + generate(); + } + + private void doBasicKeyRingCheck(PGPPublicKeyRing pubKeyRing) + throws PGPException, SignatureException + { + for (Iterator it = pubKeyRing.getPublicKeys(); it.hasNext();) + { + PGPPublicKey pubKey = (PGPPublicKey)it.next(); + + if (pubKey.isMasterKey()) + { + if (pubKey.isEncryptionKey()) + { + fail("master key showed as encryption key!"); + } + } + else + { + if (!pubKey.isEncryptionKey()) + { + fail("sub key not encryption key!"); + } + + for (Iterator sigIt = pubKeyRing.getPublicKey().getSignatures(); sigIt.hasNext();) + { + PGPSignature certification = (PGPSignature)sigIt.next(); + + certification.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pubKeyRing.getPublicKey()); + + if (!certification.verifyCertification((String)pubKeyRing.getPublicKey().getUserIDs().next(), pubKeyRing.getPublicKey())) + { + fail("subkey certification does not verify"); + } + } + } + } + } + + public String getName() + { + return "PGPECDHTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PGPECDHTest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPECDSATest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPECDSATest.java new file mode 100644 index 00000000..b7a6bcc3 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPECDSATest.java @@ -0,0 +1,314 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayInputStream; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.security.Security; +import java.security.spec.ECGenParameterSpec; +import java.util.Date; +import java.util.Iterator; + +import org.spongycastle.asn1.nist.NISTNamedCurves; +import org.spongycastle.asn1.x9.X9ECParameters; +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.generators.ECKeyPairGenerator; +import org.spongycastle.crypto.params.ECKeyGenerationParameters; +import org.spongycastle.crypto.params.ECNamedDomainParameters; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPEncryptedData; +import org.spongycastle.openpgp.PGPKeyPair; +import org.spongycastle.openpgp.PGPKeyRingGenerator; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.PGPUtil; +import org.spongycastle.openpgp.operator.KeyFingerPrintCalculator; +import org.spongycastle.openpgp.operator.PGPDigestCalculator; +import org.spongycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder; +import org.spongycastle.openpgp.operator.bc.BcPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; +import org.spongycastle.openpgp.operator.bc.BcPGPKeyPair; +import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair; +import org.spongycastle.openpgp.operator.jcajce.JcePBEProtectionRemoverFactory; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.test.SimpleTest; + +public class PGPECDSATest + extends SimpleTest +{ + byte[] testPubKey = + Base64.decode( + "mFIEUb4HqBMIKoZIzj0DAQcCAwSQynmjwsGJHYJakAEVYxrm3tt/1h8g9Uksx32J" + + "zG/ZH4RwaD0PbjzEe5EVBmCwSErRZxt/5AxXa0TEHWjya8FetDVFQ0RTQSAoS2V5" + + "IGlzIDI1NiBiaXRzIGxvbmcpIDx0ZXN0LmVjZHNhQGV4YW1wbGUuY29tPoh6BBMT" + + "CAAiBQJRvgeoAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRDqO46kgPLi" + + "vN1hAP4n0UApR36ziS5D8KUt7wEpBujQE4G3+efATJ+DMmY/SgEA+wbdDynFf/V8" + + "pQs0+FtCYQ9schzIur+peRvol7OrNnc="); + + byte[] testPrivKey = + Base64.decode( + "lKUEUb4HqBMIKoZIzj0DAQcCAwSQynmjwsGJHYJakAEVYxrm3tt/1h8g9Uksx32J" + + "zG/ZH4RwaD0PbjzEe5EVBmCwSErRZxt/5AxXa0TEHWjya8Fe/gcDAqTWSUiFpEno" + + "1n8izmLaWTy8GYw5/lK4R2t6D347YGgTtIiXfoNPOcosmU+3OibyTm2hc/WyG4fL" + + "a0nxFtj02j0Bt/Fw0N4VCKJwKL/QJT+0NUVDRFNBIChLZXkgaXMgMjU2IGJpdHMg" + + "bG9uZykgPHRlc3QuZWNkc2FAZXhhbXBsZS5jb20+iHoEExMIACIFAlG+B6gCGwMG" + + "CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEOo7jqSA8uK83WEA/ifRQClHfrOJ" + + "LkPwpS3vASkG6NATgbf558BMn4MyZj9KAQD7Bt0PKcV/9XylCzT4W0JhD2xyHMi6" + + "v6l5G+iXs6s2dw=="); + + byte[] sExprKey = + Base64.decode( + "KDIxOnByb3RlY3RlZC1wcml2YXRlLWtleSgzOmVjYyg1OmN1cnZlMTU6YnJh" + + "aW5wb29sUDM4NHIxKSgxOnE5NzoEi29XCqkugtlRvONnpAVMQgfecL+Gk86O" + + "t8LnUizfHG2TqRrtqlMg1DdU8Z8dJWmhJG84IUOURCyjt8nE4BeeCfRIbTU5" + + "7CB13OqveBdNIRfK45UQnxHLO2MPVXf4GMdtKSg5OnByb3RlY3RlZDI1Om9w" + + "ZW5wZ3AtczJrMy1zaGExLWFlcy1jYmMoKDQ6c2hhMTg6itLEzGV4Cfg4OjEy" + + "OTA1NDcyKTE2OgxmufENKFTZUB72+X7AwkgpMTEyOvMWNLZgaGdlTN8XCxa6" + + "8ia0Xqqb9RvHgTh+iBf0RgY5Tx5hqO9fHOi76LTBMfxs9VC4f1rTketjEUKR" + + "f5amKb8lrJ67kKEsny4oRtP9ejkNzcvHFqRdxmHyL10ui8M8rJN9OU8ArqWf" + + "g22dTcKu02cpKDEyOnByb3RlY3RlZC1hdDE1OjIwMTQwNjA4VDE2MDg1MCkp" + + "KQ=="); + + private void generateAndSign() + throws Exception + { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDSA", "SC"); + + keyGen.initialize(new ECGenParameterSpec("P-256")); + + KeyPair kpSign = keyGen.generateKeyPair(); + + PGPKeyPair ecdsaKeyPair = new JcaPGPKeyPair(PGPPublicKey.ECDSA, kpSign, new Date()); + + // + // try a signature + // + PGPSignatureGenerator signGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(PGPPublicKey.ECDSA, HashAlgorithmTags.SHA256).setProvider("SC")); + + signGen.init(PGPSignature.BINARY_DOCUMENT, ecdsaKeyPair.getPrivateKey()); + + signGen.update("hello world!".getBytes()); + + PGPSignature sig = signGen.generate(); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), ecdsaKeyPair.getPublicKey()); + + sig.update("hello world!".getBytes()); + + if (!sig.verify()) + { + fail("signature failed to verify!"); + } + + // + // generate a key ring + // + char[] passPhrase = "test".toCharArray(); + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, ecdsaKeyPair, + "test@bouncycastle.org", sha1Calc, null, null, new JcaPGPContentSignerBuilder(ecdsaKeyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, sha1Calc).setProvider("SC").build(passPhrase)); + + PGPPublicKeyRing pubRing = keyRingGen.generatePublicKeyRing(); + + PGPSecretKeyRing secRing = keyRingGen.generateSecretKeyRing(); + + KeyFingerPrintCalculator fingerCalc = new JcaKeyFingerprintCalculator(); + + PGPPublicKeyRing pubRingEnc = new PGPPublicKeyRing(pubRing.getEncoded(), fingerCalc); + + if (!Arrays.areEqual(pubRing.getEncoded(), pubRingEnc.getEncoded())) + { + fail("public key ring encoding failed"); + } + + PGPSecretKeyRing secRingEnc = new PGPSecretKeyRing(secRing.getEncoded(), fingerCalc); + + if (!Arrays.areEqual(secRing.getEncoded(), secRingEnc.getEncoded())) + { + fail("secret key ring encoding failed"); + } + + + // + // try a signature using encoded key + // + signGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(PGPPublicKey.ECDSA, HashAlgorithmTags.SHA256).setProvider("SC")); + + signGen.init(PGPSignature.BINARY_DOCUMENT, secRing.getSecretKey().extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("SC").build(passPhrase))); + + signGen.update("hello world!".getBytes()); + + sig = signGen.generate(); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), secRing.getSecretKey().getPublicKey()); + + sig.update("hello world!".getBytes()); + + if (!sig.verify()) + { + fail("re-encoded signature failed to verify!"); + } + } + + private void generateAndSignBC() + throws Exception + { + ECKeyPairGenerator keyGen = new ECKeyPairGenerator(); + + X9ECParameters x9ECParameters = NISTNamedCurves.getByName("P-256"); + keyGen.init(new ECKeyGenerationParameters(new ECNamedDomainParameters(NISTNamedCurves.getOID("P-256"), x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()), new SecureRandom())); + + AsymmetricCipherKeyPair kpEnc = keyGen.generateKeyPair(); + + PGPKeyPair ecdsaKeyPair = new BcPGPKeyPair(PGPPublicKey.ECDSA, kpEnc, new Date()); + + // + // try a signature + // + PGPSignatureGenerator signGen = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(PGPPublicKey.ECDSA, HashAlgorithmTags.SHA256)); + + signGen.init(PGPSignature.BINARY_DOCUMENT, ecdsaKeyPair.getPrivateKey()); + + signGen.update("hello world!".getBytes()); + + PGPSignature sig = signGen.generate(); + + sig.init(new BcPGPContentVerifierBuilderProvider(), ecdsaKeyPair.getPublicKey()); + + sig.update("hello world!".getBytes()); + + if (!sig.verify()) + { + fail("signature failed to verify!"); + } + + // + // generate a key ring + // + char[] passPhrase = "test".toCharArray(); + PGPDigestCalculator sha1Calc = new BcPGPDigestCalculatorProvider().get(HashAlgorithmTags.SHA1); + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, ecdsaKeyPair, + "test@bouncycastle.org", sha1Calc, null, null, new BcPGPContentSignerBuilder(ecdsaKeyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, sha1Calc).setProvider("SC").build(passPhrase)); + + PGPPublicKeyRing pubRing = keyRingGen.generatePublicKeyRing(); + + PGPSecretKeyRing secRing = keyRingGen.generateSecretKeyRing(); + + KeyFingerPrintCalculator fingerCalc = new BcKeyFingerprintCalculator(); + + PGPPublicKeyRing pubRingEnc = new PGPPublicKeyRing(pubRing.getEncoded(), fingerCalc); + + if (!Arrays.areEqual(pubRing.getEncoded(), pubRingEnc.getEncoded())) + { + fail("public key ring encoding failed"); + } + + PGPSecretKeyRing secRingEnc = new PGPSecretKeyRing(secRing.getEncoded(), fingerCalc); + + if (!Arrays.areEqual(secRing.getEncoded(), secRingEnc.getEncoded())) + { + fail("secret key ring encoding failed"); + } + + + // + // try a signature using encoded key + // + signGen = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(PGPPublicKey.ECDSA, HashAlgorithmTags.SHA256)); + + signGen.init(PGPSignature.BINARY_DOCUMENT, secRing.getSecretKey().extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(passPhrase))); + + signGen.update("hello world!".getBytes()); + + sig = signGen.generate(); + + sig.init(new BcPGPContentVerifierBuilderProvider(), secRing.getSecretKey().getPublicKey()); + + sig.update("hello world!".getBytes()); + + if (!sig.verify()) + { + fail("re-encoded signature failed to verify!"); + } + } + + public void performTest() + throws Exception + { + PGPUtil.setDefaultProvider("SC"); + + // + // Read the public key + // + PGPPublicKeyRing pubKeyRing = new PGPPublicKeyRing(testPubKey, new JcaKeyFingerprintCalculator()); + + for (Iterator it = pubKeyRing.getPublicKey().getSignatures(); it.hasNext();) + { + PGPSignature certification = (PGPSignature)it.next(); + + certification.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pubKeyRing.getPublicKey()); + + if (!certification.verifyCertification((String)pubKeyRing.getPublicKey().getUserIDs().next(), pubKeyRing.getPublicKey())) + { + fail("self certification does not verify"); + } + } + + // + // Read the private key + // + PGPSecretKeyRing secretKeyRing = new PGPSecretKeyRing(testPrivKey, new JcaKeyFingerprintCalculator()); + + generateAndSign(); + generateAndSignBC(); + + // + // sExpr + // + PGPSecretKey key = PGPSecretKey.parseSecretKeyFromSExpr(new ByteArrayInputStream(sExprKey), new JcePBEProtectionRemoverFactory("test".toCharArray()), new JcaKeyFingerprintCalculator()); + + PGPSignatureGenerator signGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(PGPPublicKey.ECDSA, HashAlgorithmTags.SHA256).setProvider("SC")); + + signGen.init(PGPSignature.BINARY_DOCUMENT, key.extractPrivateKey(null)); + + signGen.update("hello world!".getBytes()); + + PGPSignature sig = signGen.generate(); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), key.getPublicKey()); + + sig.update("hello world!".getBytes()); + + if (!sig.verify()) + { + fail("signature failed to verify!"); + } + } + + public String getName() + { + return "PGPECDSATest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PGPECDSATest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPECMessageTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPECMessageTest.java new file mode 100644 index 00000000..a3112227 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPECMessageTest.java @@ -0,0 +1,296 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.security.Security; + +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPCompressedData; +import org.spongycastle.openpgp.PGPEncryptedDataList; +import org.spongycastle.openpgp.PGPLiteralData; +import org.spongycastle.openpgp.PGPObjectFactory; +import org.spongycastle.openpgp.PGPOnePassSignature; +import org.spongycastle.openpgp.PGPOnePassSignatureList; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.openpgp.jcajce.JcaPGPPublicKeyRing; +import org.spongycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory; +import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.jcajce.JcePBEProtectionRemoverFactory; +import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.test.SimpleTest; + +public class PGPECMessageTest + extends SimpleTest +{ + byte[] testPubKey = + Base64.decode( + "mFIEU5SAxhMIKoZIzj0DAQcCAwRqnFLCB8EEZkAELNqznk8yQau/f1PACUTU/Qe9\n" + + "jlybc22bO55BdvZdFoa3RmNQHhR980/KeVwCQ3cPpe6OQJFAtD9OSVNUIFAtMjU2\n" + + "IChHZW5lcmF0ZWQgYnkgR1BHIDIuMSBiZXRhKSA8bmlzdC1wLTI1NkBleGFtcGxl\n" + + "LmNvbT6IeQQTEwgAIQUCU5SAxgIbAwYLCQgHAwIGFQgCCQoLAxYCAQIeAQIXgAAK\n" + + "CRA2iYNe+deDntxvAP90U2BUL2YcxrJYnsK783VIPM5U5/2IhH7azbRfaHiLZgEA\n" + + "1/BVNxRG/Q07gPSdEGagRZcrzPxMQPLjBL4T7Nq5eSG4VgRTlIDqEggqhkjOPQMB\n" + + "BwIDBJlWEj5qR12xbmp5dkjEkV+PRSfk37NKnw8axSJkyDTsFNZLIugMLX/zTn3r\n" + + "rOamvHUdXNbLy1s8PeyrztMcOnwDAQgHiGEEGBMIAAkFAlOUgOoCGwwACgkQNomD\n" + + "XvnXg556SQD+MCXRkYgLPd0NWWbCKl5wYk4NwWRvOCDFGk7eYoRTKaYBAIkt3J86\n" + + "Bn0zCzsphjrIUlGPXhLSX/2aJQDuuK3zzLmn"); + + byte[] sExprKeySub = + Base64.decode( + "KDIxOnByb3RlY3RlZC1wcml2YXRlLWtleSgzOmVjYyg1OmN1cnZlMTA6TklT" + + "VCBQLTI1NikoMTpxNjU6BJlWEj5qR12xbmp5dkjEkV+PRSfk37NKnw8axSJk" + + "yDTsFNZLIugMLX/zTn3rrOamvHUdXNbLy1s8PeyrztMcOnwpKDk6cHJvdGVj" + + "dGVkMjU6b3BlbnBncC1zMmszLXNoYTEtYWVzLWNiYygoNDpzaGExODpu2e7w" + + "pW4L5jg6MTI5MDU0NzIpMTY6ohIkbi1P1O7QX1zgPd7Ejik5NjrCoM9qBxzy" + + "LVJJMVRGlsjltF9/CeLnRPN1sjeiQrP1vAlZMPiOpYTmGDVRcZhdkCRO06MY" + + "UTLDZK1wsxELVD0s9irpbskcOnXwqtXbIqhoK4B+9pnkR0h5gi0xPIGSTtYp" + + "KDEyOnByb3RlY3RlZC1hdDE1OjIwMTQwNjA4VDE1MjgxMCkpKQ=="); + + byte[] sExprKeyMaster = + Base64.decode( + "KDIxOnByb3RlY3RlZC1wcml2YXRlLWtleSgzOmVjYyg1OmN1cnZlMTA6TklT" + + "VCBQLTI1NikoMTpxNjU6BGqcUsIHwQRmQAQs2rOeTzJBq79/U8AJRNT9B72O" + + "XJtzbZs7nkF29l0WhrdGY1AeFH3zT8p5XAJDdw+l7o5AkUApKDk6cHJvdGVj" + + "dGVkMjU6b3BlbnBncC1zMmszLXNoYTEtYWVzLWNiYygoNDpzaGExODr4PqHT" + + "9W4lpTg6MTI5MDU0NzIpMTY6VsooQy9aGsuMpiObZk4y1ik5NjoCArOSmSsJ" + + "IYUzxkRwy/HyDYPqjAqrNrh3m8lQco6k64Pf4SDda/0gKjkum7zYDEzBEvXI" + + "+ZodAST6z3IDkPHL7LUy5qp2LdG73xLRFjfsqOsZgP+nwoOSUiC7N4AWJPAp" + + "KDEyOnByb3RlY3RlZC1hdDE1OjIwMTQwNjA4VDE1MjcwOSkpKQ=="); + + byte[] encMessage = + Base64.decode("hH4DrQCblwYU61MSAgMEVXjgPW2hvIhUMQ2qlAQlAliZKbyujaYfLnwZTeGvu+pt\n"+ + "gJXt+JJ8zWoENxLAp+Nb3PxJW4CjvkXQ2dEmmvkhBzAhDer86XJBrQLBQUL+6EmE\n"+ + "l+/3Yzt+cPEyEn32BSpkt31F2yGncoefCUDgj9tKiFXSRwGhjRno0qzB3CfRWzDu\n"+ + "eelwwtRcxnvXNc44TuHRf4PgZ3d4dDU69bWQswdQ5UTP/Bjjo92yMLtJ3HtBuym+\n"+ + "NazbQUh4M+SP"); + + byte[] signedEncMessage = + Base64.decode("hH4DrQCblwYU61MSAgMEC/jpqjgnqotzKWNWJ3bhOxmmChghrV2PLQbQqtHtVvbj\n" + + "zyLpaPgeqLslMAjsdy8rlANCjlweZhtP1DmvHiYgjDAA54eptpLMtbULaQOoRcsZ\n" + + "ZnMqhx9s5phAohNFGC+DnVU/IwxDOnI+ya54LOoXUrrSsgEKDTlAmYr4/oDmLTXt\n" + + "TaLgk0T9nBxGe8WbLwhPRBIyq6NX151aQ+pOobajrRiLwg/CwUsbAZ50bBPn2JjX\n" + + "wgBhBjyAn7D6bZ4hMl3YSluSiFkJhxZcYSydtIAlX35q4D/pJjT4mPT/y7ypytCU\n" + + "0wWo53O6NCSeM/EpeFw8RRh8fe+m33qpA6T5sR3Alg4ZukiIxLa36k6Cv5KTHmB3\n" + + "6lKZcgQDHNIKStV1bW4Cva1aXXQ="); + + private void testMasterKey() + throws Exception + { + PGPSecretKey key = PGPSecretKey.parseSecretKeyFromSExpr(new ByteArrayInputStream(sExprKeyMaster), new JcePBEProtectionRemoverFactory("test".toCharArray()), new JcaKeyFingerprintCalculator()); + + PGPSignatureGenerator signGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(PGPPublicKey.ECDSA, HashAlgorithmTags.SHA256).setProvider("SC")); + + signGen.init(PGPSignature.BINARY_DOCUMENT, key.extractPrivateKey(null)); + + signGen.update("hello world!".getBytes()); + + PGPSignature sig = signGen.generate(); + + PGPPublicKey publicKey = new JcaPGPPublicKeyRing(testPubKey).getPublicKey(); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), publicKey); + + sig.update("hello world!".getBytes()); + + if (!sig.verify()) + { + fail("signature failed to verify!"); + } + } + + private void testEncMessage() + throws Exception + { + PGPObjectFactory pgpFact = new JcaPGPObjectFactory(encMessage); + + PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpFact.nextObject(); + + PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0); + + PGPPublicKey publicKey = new JcaPGPPublicKeyRing(testPubKey).getPublicKey(encP.getKeyID()); + + PGPSecretKey secretKey = PGPSecretKey.parseSecretKeyFromSExpr(new ByteArrayInputStream(sExprKeySub), new JcePBEProtectionRemoverFactory("test".toCharArray()), publicKey); + + InputStream clear = encP.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("SC").build(secretKey.extractPrivateKey(null))); + + PGPObjectFactory plainFact = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator()); + + PGPCompressedData cData = (PGPCompressedData)plainFact.nextObject(); + + PGPObjectFactory compFact = new PGPObjectFactory(cData.getDataStream(), new BcKeyFingerprintCalculator()); + + PGPLiteralData lData = (PGPLiteralData)compFact.nextObject(); + + if (!"test.txt".equals(lData.getFileName())) + { + fail("wrong file name detected"); + } + } + + private void testSignedEncMessage() + throws Exception + { + PGPObjectFactory pgpFact = new JcaPGPObjectFactory(signedEncMessage); + + PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpFact.nextObject(); + + PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0); + + JcaPGPPublicKeyRing publicKeyRing = new JcaPGPPublicKeyRing(testPubKey); + + PGPPublicKey publicKey = publicKeyRing.getPublicKey(encP.getKeyID()); + + PGPSecretKey secretKey = PGPSecretKey.parseSecretKeyFromSExpr(new ByteArrayInputStream(sExprKeySub), new JcePBEProtectionRemoverFactory("test".toCharArray()), publicKey); + + InputStream clear = encP.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("SC").build(secretKey.extractPrivateKey(null))); + + PGPObjectFactory plainFact = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator()); + + PGPCompressedData cData = (PGPCompressedData)plainFact.nextObject(); + + PGPObjectFactory compFact = new PGPObjectFactory(cData.getDataStream(), new BcKeyFingerprintCalculator()); + + PGPOnePassSignatureList sList = (PGPOnePassSignatureList)compFact.nextObject(); + + PGPOnePassSignature ops = sList.get(0); + + PGPLiteralData lData = (PGPLiteralData)compFact.nextObject(); + + if (!"test.txt".equals(lData.getFileName())) + { + fail("wrong file name detected"); + } + + InputStream dIn = lData .getInputStream(); + int ch; + + ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), publicKeyRing.getPublicKey(ops.getKeyID())); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + PGPSignatureList p3 = (PGPSignatureList)compFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed signature check"); + } + } + + private void testBCEncMessage() + throws Exception + { + PGPObjectFactory pgpFact = new JcaPGPObjectFactory(encMessage); + + PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpFact.nextObject(); + + PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0); + + PGPPublicKey publicKey = new JcaPGPPublicKeyRing(testPubKey).getPublicKey(encP.getKeyID()); + + PGPSecretKey secretKey = PGPSecretKey.parseSecretKeyFromSExpr(new ByteArrayInputStream(sExprKeySub), new JcePBEProtectionRemoverFactory("test".toCharArray()), publicKey); + + InputStream clear = encP.getDataStream(new BcPublicKeyDataDecryptorFactory(secretKey.extractPrivateKey(null))); + + PGPObjectFactory plainFact = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator()); + + PGPCompressedData cData = (PGPCompressedData)plainFact.nextObject(); + + PGPObjectFactory compFact = new PGPObjectFactory(cData.getDataStream(), new BcKeyFingerprintCalculator()); + + PGPLiteralData lData = (PGPLiteralData)compFact.nextObject(); + + if (!"test.txt".equals(lData.getFileName())) + { + fail("wrong file name detected"); + } + } + + private void testBCSignedEncMessage() + throws Exception + { + PGPObjectFactory pgpFact = new JcaPGPObjectFactory(signedEncMessage); + + PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpFact.nextObject(); + + PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0); + + JcaPGPPublicKeyRing publicKeyRing = new JcaPGPPublicKeyRing(testPubKey); + + PGPPublicKey publicKey = publicKeyRing.getPublicKey(encP.getKeyID()); + + PGPSecretKey secretKey = PGPSecretKey.parseSecretKeyFromSExpr(new ByteArrayInputStream(sExprKeySub), new JcePBEProtectionRemoverFactory("test".toCharArray()), publicKey); + + InputStream clear = encP.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("SC").build(secretKey.extractPrivateKey(null))); + + PGPObjectFactory plainFact = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator()); + + PGPCompressedData cData = (PGPCompressedData)plainFact.nextObject(); + + PGPObjectFactory compFact = new PGPObjectFactory(cData.getDataStream(), new BcKeyFingerprintCalculator()); + + PGPOnePassSignatureList sList = (PGPOnePassSignatureList)compFact.nextObject(); + + PGPOnePassSignature ops = sList.get(0); + + PGPLiteralData lData = (PGPLiteralData)compFact.nextObject(); + + if (!"test.txt".equals(lData.getFileName())) + { + fail("wrong file name detected"); + } + + InputStream dIn = lData .getInputStream(); + int ch; + + ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), publicKeyRing.getPublicKey(ops.getKeyID())); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + PGPSignatureList p3 = (PGPSignatureList)compFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed signature check"); + } + } + + public void performTest() + throws Exception + { + testMasterKey(); + testEncMessage(); + testSignedEncMessage(); + testBCEncMessage(); + testBCSignedEncMessage(); + } + + public String getName() + { + return "PGPECMessageTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PGPECMessageTest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPKeyRingTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPKeyRingTest.java new file mode 100644 index 00000000..442ceedd --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPKeyRingTest.java @@ -0,0 +1,2790 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayInputStream; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Security; +import java.util.Date; +import java.util.Iterator; + +import javax.crypto.Cipher; + +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.jce.spec.ElGamalParameterSpec; +import org.spongycastle.openpgp.PGPEncryptedData; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPKeyPair; +import org.spongycastle.openpgp.PGPKeyRingGenerator; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.jcajce.JcaPGPPublicKeyRing; +import org.spongycastle.openpgp.jcajce.JcaPGPPublicKeyRingCollection; +import org.spongycastle.openpgp.jcajce.JcaPGPSecretKeyRingCollection; +import org.spongycastle.openpgp.operator.PGPDigestCalculator; +import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider; +import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyConverter; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPPrivateKey; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class PGPKeyRingTest + extends SimpleTest +{ + byte[] pub1 = Base64.decode( + "mQGiBEA83v0RBADzKVLVCnpWQxX0LCsevw/3OLs0H7MOcLBQ4wMO9sYmzGYn" + + "xpVj+4e4PiCP7QBayWyy4lugL6Lnw7tESvq3A4v3fefcxaCTkJrryiKn4+Cg" + + "y5rIBbrSKNtCEhVi7xjtdnDjP5kFKgHYjVOeIKn4Cz/yzPG3qz75kDknldLf" + + "yHxp2wCgwW1vAE5EnZU4/UmY7l8kTNkMltMEAJP4/uY4zcRwLI9Q2raPqAOJ" + + "TYLd7h+3k/BxI0gIw96niQ3KmUZDlobbWBI+VHM6H99vcttKU3BgevNf8M9G" + + "x/AbtW3SS4De64wNSU3189XDG8vXf0vuyW/K6Pcrb8exJWY0E1zZQ1WXT0gZ" + + "W0kH3g5ro//Tusuil9q2lVLF2ovJA/0W+57bPzi318dWeNs0tTq6Njbc/GTG" + + "FUAVJ8Ss5v2u6h7gyJ1DB334ExF/UdqZGldp0ugkEXaSwBa2R7d3HBgaYcoP" + + "Ck1TrovZzEY8gm7JNVy7GW6mdOZuDOHTxyADEEP2JPxh6eRcZbzhGuJuYIif" + + "IIeLOTI5Dc4XKeV32a+bWrQidGVzdCAoVGVzdCBrZXkpIDx0ZXN0QHViaWNh" + + "bGwuY29tPohkBBMRAgAkBQJAPN79AhsDBQkB4TOABgsJCAcDAgMVAgMDFgIB" + + "Ah4BAheAAAoJEJh8Njfhe8KmGDcAoJWr8xgPr75y/Cp1kKn12oCCOb8zAJ4p" + + "xSvk4K6tB2jYbdeSrmoWBZLdMLACAAC5AQ0EQDzfARAEAJeUAPvUzJJbKcc5" + + "5Iyb13+Gfb8xBWE3HinQzhGr1v6A1aIZbRj47UPAD/tQxwz8VAwJySx82ggN" + + "LxCk4jW9YtTL3uZqfczsJngV25GoIN10f4/j2BVqZAaX3q79a3eMiql1T0oE" + + "AGmD7tO1LkTvWfm3VvA0+t8/6ZeRLEiIqAOHAAQNBACD0mVMlAUgd7REYy/1" + + "mL99Zlu9XU0uKyUex99sJNrcx1aj8rIiZtWaHz6CN1XptdwpDeSYEOFZ0PSu" + + "qH9ByM3OfjU/ya0//xdvhwYXupn6P1Kep85efMBA9jUv/DeBOzRWMFG6sC6y" + + "k8NGG7Swea7EHKeQI40G3jgO/+xANtMyTIhPBBgRAgAPBQJAPN8BAhsMBQkB" + + "4TOAAAoJEJh8Njfhe8KmG7kAn00mTPGJCWqmskmzgdzeky5fWd7rAKCNCp3u" + + "ZJhfg0htdgAfIy8ppm05vLACAAA="); + + byte[] sec1 = Base64.decode( + "lQHhBEA83v0RBADzKVLVCnpWQxX0LCsevw/3OLs0H7MOcLBQ4wMO9sYmzGYn" + + "xpVj+4e4PiCP7QBayWyy4lugL6Lnw7tESvq3A4v3fefcxaCTkJrryiKn4+Cg" + + "y5rIBbrSKNtCEhVi7xjtdnDjP5kFKgHYjVOeIKn4Cz/yzPG3qz75kDknldLf" + + "yHxp2wCgwW1vAE5EnZU4/UmY7l8kTNkMltMEAJP4/uY4zcRwLI9Q2raPqAOJ" + + "TYLd7h+3k/BxI0gIw96niQ3KmUZDlobbWBI+VHM6H99vcttKU3BgevNf8M9G" + + "x/AbtW3SS4De64wNSU3189XDG8vXf0vuyW/K6Pcrb8exJWY0E1zZQ1WXT0gZ" + + "W0kH3g5ro//Tusuil9q2lVLF2ovJA/0W+57bPzi318dWeNs0tTq6Njbc/GTG" + + "FUAVJ8Ss5v2u6h7gyJ1DB334ExF/UdqZGldp0ugkEXaSwBa2R7d3HBgaYcoP" + + "Ck1TrovZzEY8gm7JNVy7GW6mdOZuDOHTxyADEEP2JPxh6eRcZbzhGuJuYIif" + + "IIeLOTI5Dc4XKeV32a+bWv4CAwJ5KgazImo+sGBfMhDiBcBTqyDGhKHNgHic" + + "0Pky9FeRvfXTc2AO+jGmFPjcs8BnTWuDD0/jkQnRZpp1TrQidGVzdCAoVGVz" + + "dCBrZXkpIDx0ZXN0QHViaWNhbGwuY29tPohkBBMRAgAkBQJAPN79AhsDBQkB" + + "4TOABgsJCAcDAgMVAgMDFgIBAh4BAheAAAoJEJh8Njfhe8KmGDcAn3XeXDMg" + + "BZgrZzFWU2IKtA/5LG2TAJ0Vf/jjyq0jZNZfGfoqGTvD2MAl0rACAACdAVgE" + + "QDzfARAEAJeUAPvUzJJbKcc55Iyb13+Gfb8xBWE3HinQzhGr1v6A1aIZbRj4" + + "7UPAD/tQxwz8VAwJySx82ggNLxCk4jW9YtTL3uZqfczsJngV25GoIN10f4/j" + + "2BVqZAaX3q79a3eMiql1T0oEAGmD7tO1LkTvWfm3VvA0+t8/6ZeRLEiIqAOH" + + "AAQNBACD0mVMlAUgd7REYy/1mL99Zlu9XU0uKyUex99sJNrcx1aj8rIiZtWa" + + "Hz6CN1XptdwpDeSYEOFZ0PSuqH9ByM3OfjU/ya0//xdvhwYXupn6P1Kep85e" + + "fMBA9jUv/DeBOzRWMFG6sC6yk8NGG7Swea7EHKeQI40G3jgO/+xANtMyTP4C" + + "AwJ5KgazImo+sGBl2C7CFuI+5KM4ZhbtVie7l+OiTpr5JW2z5VgnV3EX9p04" + + "LcGKfQvD65+ELwli6yh8B2zGcipqTaYk3QoYNIhPBBgRAgAPBQJAPN8BAhsM" + + "BQkB4TOAAAoJEJh8Njfhe8KmG7kAniuRkaFFv1pdCBN8JJXpcorHmyouAJ9L" + + "xxmusffR6OI7WgD3XZ0AL8zUC7ACAAA="); + + char[] pass1 = "qwertzuiop".toCharArray(); + + byte[] pub2 = Base64.decode( + "mQGiBEBtfW8RBADfWjTxFedIbGBNVgh064D/OCf6ul7x4PGsCl+BkAyheYkr" + + "mVUsChmBKoeXaY+Fb85wwusXzyM/6JFK58Rg+vEb3Z19pue8Ixxq7cRtCtOA" + + "tOP1eKXLNtTRWJutvLkQmeOa19UZ6ziIq23aWuWKSq+KKMWek2GUnGycnx5M" + + "W0pn1QCg/39r9RKhY9cdKYqRcqsr9b2B/AsD/Ru24Q15Jmrsl9zZ6EC47J49" + + "iNW5sLQx1qf/mgfVWQTmU2j6gq4ND1OuK7+0OP/1yMOUpkjjcqxFgTnDAAoM" + + "hHDTzCv/aZzIzmMvgLsYU3aIMfbz+ojpuASMCMh+te01cEMjiPWwDtdWWOdS" + + "OSyX9ylzhO3PiNDks8R83onsacYpA/9WhTcg4bvkjaj66I7wGZkm3BmTxNSb" + + "pE4b5HZDh31rRYhY9tmrryCfFnU4BS2Enjj5KQe9zFv7pUBCBW2oFo8i8Osn" + + "O6fa1wVN4fBHC6wqWmmpnkFerNPkiC9V75KUFIfeWHmT3r2DVSO3dfdHDERA" + + "jFIAioMLjhaX6DnODF5KQrABh7QmU2FpIFB1bGxhYmhvdGxhIDxwc2FpQG15" + + "amF2YXdvcmxkLmNvbT6wAwP//4kAVwQQEQIAFwUCQG19bwcLCQgHAwIKAhkB" + + "BRsDAAAAAAoJEKXQf/RT99uYmfAAoMKxV5g2owIfmy2w7vSLvOQUpvvOAJ4n" + + "jB6xJot523rPAQW9itPoGGekirABZ7kCDQRAbX1vEAgA9kJXtwh/CBdyorrW" + + "qULzBej5UxE5T7bxbrlLOCDaAadWoxTpj0BV89AHxstDqZSt90xkhkn4DIO9" + + "ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeSWc39uK50T8X8dryDxUcwYc58yWb/" + + "Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0iP1YTknbzSC0neSRBzZrM2w4" + + "DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdXQ6MdGGzeMyEs" + + "tSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQClCbAkbTCD1mpF1B" + + "n5x8vYlLIhkmuquiXsNV6TILOwACAgf9F7/nJHDayJ3pBVTTVSq2g5WKUXMg" + + "xxGKTvOahiVRcbO03w0pKAkH85COakVfe56sMYpWRl36adjNoKOxaciow74D" + + "1R5snY/hv/kBXPBkzo4UMkbANIVaZ0IcnLp+rkkXcDVbRCibZf8FfCY1zXbq" + + "d680UtEgRbv1D8wFBqfMt7kLsuf9FnIw6vK4DU06z5ZDg25RHGmswaDyY6Mw" + + "NGCrKGbHf9I/T7MMuhGF/in8UU8hv8uREOjseOqklG3/nsI1hD/MdUC7fzXi" + + "MRO4RvahLoeXOuaDkMYALdJk5nmNuCL1YPpbFGttI3XsK7UrP/Fhd8ND6Nro" + + "wCqrN6keduK+uLABh4kATAQYEQIADAUCQG19bwUbDAAAAAAKCRCl0H/0U/fb" + + "mC/0AJ4r1yvyu4qfOXlDgmVuCsvHFWo63gCfRIrCB2Jv/N1cgpmq0L8LGHM7" + + "G/KwAWeZAQ0EQG19owEIAMnavLYqR7ffaDPbbq+lQZvLCK/3uA0QlyngNyTa" + + "sDW0WC1/ryy2dx7ypOOCicjnPYfg3LP5TkYAGoMjxH5+xzM6xfOR+8/EwK1z" + + "N3A5+X/PSBDlYjQ9dEVKrvvc7iMOp+1K1VMf4Ug8Yah22Ot4eLGP0HRCXiv5" + + "vgdBNsAl/uXnBJuDYQmLrEniqq/6UxJHKHxZoS/5p13Cq7NfKB1CJCuJXaCE" + + "TW2do+cDpN6r0ltkF/r+ES+2L7jxyoHcvQ4YorJoDMlAN6xpIZQ8dNaTYP/n" + + "Mx/pDS3shUzbU+UYPQrreJLMF1pD+YWP5MTKaZTo+U/qPjDFGcadInhPxvh3" + + "1ssAEQEAAbABh7QuU2FuZGh5YSBQdWxsYWJob3RsYSA8cHNhbmRoeWFAbXlq" + + "YXZhd29ybGQuY29tPrADA///iQEtBBABAgAXBQJAbX2jBwsJCAcDAgoCGQEF" + + "GwMAAAAACgkQx87DL9gOvoeVUwgAkQXYiF0CxhKbDnuabAssnOEwJrutgCRO" + + "CJRQvIwTe3fe6hQaWn2Yowt8OQtNFiR8GfAY6EYxyFLKzZbAI/qtq5fHmN3e" + + "RSyNWe6d6e17hqZZL7kf2sVkyGTChHj7Jiuo7vWkdqT2MJN6BW5tS9CRH7Me" + + "D839STv+4mAAO9auGvSvicP6UEQikAyCy/ihoJxLQlspfbSNpi0vrUjCPT7N" + + "tWwfP0qF64i9LYkjzLqihnu+UareqOPhXcWnyFKrjmg4ezQkweNU2pdvCLbc" + + "W24FhT92ivHgpLyWTswXcqjhFjVlRr0+2sIz7v1k0budCsJ7PjzOoH0hJxCv" + + "sJQMlZR/e7ABZ7kBDQRAbX2kAQgAm5j+/LO2M4pKm/VUPkYuj3eefHkzjM6n" + + "KbvRZX1Oqyf+6CJTxQskUWKAtkzzKafPdS5Wg0CMqeXov+EFod4bPEYccszn" + + "cKd1U8NRwacbEpCvvvB84Yl2YwdWpDpkryyyLI4PbCHkeuwx9Dc2z7t4XDB6" + + "FyAJTMAkia7nzYa/kbeUO3c2snDb/dU7uyCsyKtTZyTyhTgtl/f9L03Bgh95" + + "y3mOUz0PimJ0Sg4ANczF4d04BpWkjLNVJi489ifWodPlHm1hag5drYekYpWJ" + + "+3g0uxs5AwayV9BcOkPKb1uU3EoYQw+nn0Kn314Nvx2M1tKYunuVNLEm0PhA" + + "/+B8PTq8BQARAQABsAGHiQEiBBgBAgAMBQJAbX2kBRsMAAAAAAoJEMfOwy/Y" + + "Dr6HkLoH/RBY8lvUv1r8IdTs5/fN8e/MnGeThLl+JrlYF/4t3tjXYIf5xUj/" + + "c9NdjreKYgHfMtrbVM08LlxUVQlkjuF3DIk5bVH9Blq8aXmyiwiM5GrCry+z" + + "WiqkpZze1G577C38mMJbHDwbqNCLALMzo+W2q04Avl5sniNnDNGbGz9EjhRg" + + "o7oS16KkkD6Ls4RnHTEZ0vyZOXodDHu+sk/2kzj8K07kKaM8rvR7aDKiI7HH" + + "1GxJz70fn1gkKuV2iAIIiU25bty+S3wr+5h030YBsUZF1qeKCdGOmpK7e9Of" + + "yv9U7rf6Z5l8q+akjqLZvej9RnxeH2Um7W+tGg2me482J+z6WOawAWc="); + + byte[] sec2 = Base64.decode( + "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" + + "Nifs+ljmsAFn"); + + + char[] sec2pass1 = "sandhya".toCharArray(); + char[] sec2pass2 = "psai".toCharArray(); + + byte[] pub3 = Base64.decode( + "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" + + "n3FaE6UZE9GMDmCIAjhI+0X9aH6CsAIAAw=="); + + byte[] sec3 = Base64.decode( + "lQHhBEB9BH0RBACtYQtE7tna6hgGyGLpq+ds3r2cLC0ISn5dNw7tm9vwiNVF" + + "JA2N37RRrifw4PvgelRSvLaX3M3ZBqC9s1Metg3v4FSlIRtSLWCNpHSvNw7i" + + "X8C2Xy9Hdlbh6Y/50o+iscojLRE14upfR1bIkcCZQGSyvGV52V2wBImUUZjV" + + "s2ZngwCg7mu852vK7+euz4WaL7ERVYtq9CMEAJ5swrljerDpz/RQ4Lhp6KER" + + "KyuI0PUttO57xINGshEINgYlZdGaZHRueHe7uKfI19mb0T4N3NJWaZ0wF+Cn" + + "rixsq0VrTUfiwfZeGluNG73aTCeY45fVXMGTTSYXzS8T0LW100Xn/0g9HRyA" + + "xUpuWo8IazxkMqHJis2uwriYKpAfA/9anvj5BS9p5pfPjp9dGM7GTMIYl5f2" + + "fcP57f+AW1TVR6IZiMJAvAdeWuLtwLnJiFpGlnFz273pfl+sAuqm1yNceImR" + + "2SDDP4+vtyycWy8nZhgEuhZx3W3cWMQz5WyNJSY1JJHh9TCQkCoN8E7XpVP4" + + "zEPboB2GzD93mfD8JLHP+/4DAwIvYrn+YqRaaGAu19XUj895g/GROyP8WEaU" + + "Bd/JNqWc4kE/0guetGnPzq7G3bLVwiKfFd4X7BrgHAo3mrQtVGVzdCBLZXkg" + + "KG5vIGNvbW1lbnQpIDx0ZXN0QGJvdW5jeWNhc3RsZS5vcmc+iFkEExECABkF" + + "AkB9BH0ECwcDAgMVAgMDFgIBAh4BAheAAAoJEKnMV8vjZQOpSRQAoKZy6YS1" + + "irF5/Q3JlWiwbkN6dEuLAJ9lldRLOlXsuQ5JW1+SLEc6K9ho4rACAADRwXPB" + + "cQEQAAEBAAAAAAAAAAAAAAAA/9j/4AAQSkZJRgABAQEASABIAAD//gAXQ3Jl" + + "YXRlZCB3aXRoIFRoZSBHSU1Q/9sAQwAIBgYHBgUIBwcHCQkICgwUDQwLCwwZ" + + "EhMPFB0aHx4dGhwcICQuJyAiLCMcHCg3KSwwMTQ0NB8nOT04MjwuMzQy/9sA" + + "QwEJCQkMCwwYDQ0YMiEcITIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy" + + "MjIyMjIyMjIyMjIyMjIyMjIyMjIy/8AAEQgAFAAUAwEiAAIRAQMRAf/EABoA" + + "AQACAwEAAAAAAAAAAAAAAAAEBQIDBgf/xAAoEAABAgUDBAEFAAAAAAAAAAAB" + + "AgMABBEhMQUSQQYTIiNhFFGBkcH/xAAXAQEAAwAAAAAAAAAAAAAAAAAEAgMF" + + "/8QAJBEAAQQAAwkAAAAAAAAAAAAAAQACERIEIfATMTJBUZGx0fH/2gAMAwEA" + + "AhEDEQA/APMuotJlJVxstqaPo22NlAUp+YsNO0qSUtBcMu6n6EtOHcfPAHHF" + + "I16++oajQtTA3DapK02HFR8UpE9pTbQWtKm2WG2rlxVyQTcfGbn7Qm0OIjL7" + + "7Wrs2NNm9lzTmmSxQ0PX4opSprk5tmESF6syggzGwOLG6gXgHFbZhBixk8Xl" + + "IDcOQLRKt+rX+3qC5ZLTQblpQlvwvxn9CMpZturVGkJHapQJphRH8hCLXbzr" + + "qpYsCx1zC5rtpJNuYQhASc0UAQv/2YhcBBMRAgAcBQJAfQV+AhsDBAsHAwID" + + "FQIDAxYCAQIeAQIXgAAKCRCpzFfL42UDqfa2AJ9hjtEeDTbTEAuuSbzhYFxN" + + "/qc0FACgsmzysdbBpuN65yK01tbEaeIMtqCwAgAAnQEUBEB9BH4QAwCqRuWO" + + "rxm5v/8WWBtPEUZnYuu3WYxefRKn6ON5ka5Ymp4AfKpKqKqn982tjlG13GVE" + + "P2ow11L4yQKGNm+VyVEapm7SpMD0SHg9vsJygAWrfMJnBYWSgE19W6o3ckUR" + + "sWsAAwYDAKDCSiSxC3Z5/POaCehw5iHs/vmVk5Wn831LSZEEwkSohNDbIEry" + + "ia/9tFXSt11AP4stJtZ0MH87/6JBbiIRD4JXcx+zfzchL7Teczr/06QMphSn" + + "sAENupbhLupfpR+BbP4DAwIvYrn+YqRaaGBjvFK1fbxCt7ZM4I2W/3BC0lCX" + + "m/NypKNspGflec8u96uUlA0fNCnxm6f9nbB0jpvoKi0g4iqAf+P2iEYEGBEC" + + "AAYFAkB9BH4ACgkQqcxXy+NlA6mtMgCgvccZA/Sg7BXVpxli47SYhxSHoM4A" + + "oNCOMplSnYTuh5ikKeBWtz36gC1psAIAAA=="); + + char[] sec3pass1 = "123456".toCharArray(); + + // + // GPG comment packets. + // + byte[] sec4 = Base64.decode( + "lQG7BD0PbK8RBAC0cW4Y2MZXmAmqYp5Txyw0kSQsFvwZKHNMFRv996IsN57URVF5" + + "BGMVPRBi9dNucWbjiSYpiYN13wE9IuLZsvVaQojV4XWGRDc+Rxz9ElsXnsYQ3mZU" + + "7H1bNQEofstChk4z+dlvPBN4GFahrIzn/CeVUn6Ut7dVdYbiTqviANqNXwCglfVA" + + "2OEePvqFnGxs1jhJyPSOnTED/RwRvsLH/k43mk6UEvOyN1RIpBXN+Ieqs7h1gFrQ" + + "kB+WMgeP5ZUsotTffVDSUS9UMxRQggVUW1Xml0geGwQsNfkr/ztWMs/T4xp1v5j+" + + "QyJx6OqNlkGdqOsoqkzJx0SQ1zBxdinFyyC4H95SDAb/RQOu5LQmxFG7quexztMs" + + "infEA/9cVc9+qCo92yRAaXRqKNVVQIQuPxeUsGMyVeJQvJBD4An8KTMCdjpF10Cp" + + "qA3t+n1S0zKr5WRUtvS6y60MOONO+EJWVWBNkx8HJDaIMNkfoqQoz3Krn7w6FE/v" + + "/5uwMd6jY3N3yJZn5nDZT9Yzv9Nx3j+BrY+henRlSU0c6xDc9QAAnjJYg0Z83VJG" + + "6HrBcgc4+4K6lHulCqH9JiM6RFNBX2ZhY3RvcjoAAK9hV206agp99GI6x5qE9+pU" + + "vs6O+Ich/SYjOkRTQV9mYWN0b3I6AACvYAfGn2FGrpBYbjnpTuFOHJMS/T5xg/0m" + + "IzpEU0FfZmFjdG9yOgAAr0dAQz6XxMwxWIn8xIZR/v2iN2L9C6O0EkZvbyBCYXIg" + + "PGJhekBxdXV4PohXBBMRAgAXBQI9D2yvBQsHCgMEAxUDAgMWAgECF4AACgkQUGLI" + + "YCIktfoGogCfZiXMJUKrScqozv5tMwzTTk2AaT8AniM5iRr0Du/Y08SL/NMhtF6H" + + "hJ89nO4EPQ9ssRADAI6Ggxj6ZBfoavuXd/ye99osW8HsNlbqhXObu5mCMNySX2wa" + + "HoWyRUEaUkI9eQw+MlHzIwzA32E7y2mU3OQBKdgLcBg4jxtcWVEg8ESKF9MpFXxl" + + "pExxWrr4DFBfCRcsTwAFEQL9G3OvwJuEZXgx2JSS41D3pG4/qiHYICVa0u3p/14i" + + "cq0kXajIk5ZJ6frCIAHIzuQ3n7jjzr05yR8s/qCrNbBA+nlkVNa/samk+jCzxxxa" + + "cR/Dbh2wkvTFuDFFETwQYLuZAADcDck4YGQAmHivVT2NNDCf/aTz0+CJWl+xRc2l" + + "Qw7D/SQjOkVMR19mYWN0b3I6AACbBnv9m5/bb/pjYAm2PtDp0CysQ9X9JCM6RUxH" + + "X2ZhY3RvcjoAAJsFyHnSmaWguTFf6lJ/j39LtUNtmf0kIzpFTEdfZmFjdG9yOgAA" + + "mwfwMD3LxmWtuCWBE9BptWMNH07Z/SQjOkVMR19mYWN0b3I6AACbBdhBrbSiM4UN" + + "y7khDW2Sk0e4v9mIRgQYEQIABgUCPQ9ssQAKCRBQYshgIiS1+jCMAJ9txwHnb1Kl" + + "6i/fSoDs8SkdM7w48wCdFvPEV0sSxE73073YhBgPZtMWbBo="); + + // + // PGP freeware version 7 + // + byte[] pub5 = Base64.decode( + "mQENBEBrBE4BCACjXVcNIFDQSofaIyZnALb2CRg+WY9uUqgHEEAOlPe03Cs5STM5" + + "HDlNmrh4TdFceJ46rxk1mQOjULES1YfHay8lCIzrD7FX4oj0r4DC14Fs1vXaSar2" + + "1szIpttOw3obL4A1e0p6N4jjsoG7N/pA0fEL0lSw92SoBrMbAheXRg4qNTZvdjOR" + + "grcuOuwgJRvPLtRXlhyLBoyhkd5mmrIDGv8QHJ/UjpeIcRXY9kn9oGXnEYcRbMaU" + + "VwXB4pLzWqz3ZejFI3lOxRWjm760puPOnGYlzSVBxlt2LgzUgSj1Mn+lIpWmAzsa" + + "xEiU4xUwEomQns72yYRZ6D3euNCibcte4SeXABEBAAG0KXBhbGFzaCBrYXNvZGhh" + + "biA8cGthc29kaGFuQHRpYWEtY3JlZi5vcmc+iQEuBBABAgAYBQJAawROCAsBAwkI" + + "BwIKAhkBBRsDAAAAAAoJEOfelumuiOrYqPEH+wYrdP5Tq5j+E5yN1pyCg1rwbSOt" + + "Dka0y0p7Oq/VIGLk692IWPItLEunnBXQtGBcWqklrvogvlhxtf16FgoyScfLJx1e" + + "1cJa+QQnVuH+VOESN6iS9Gp9lUfVOHv74mEMXw0l2Djfy/lnrkAMBatggyGnF9xF" + + "VXOLk1J2WVFm9KUE23o6qdB7RGkf31pN2eA7SWmkdJSkUH7o/QSFBI+UTRZ/IY5P" + + "ZIJpsdiIOqd9YMG/4RoSZuPqNRR6x7BSs8nQVR9bYs4PPlp4GfdRnOcRonoTeJCZ" + + "83RnsraWJnJTg34gRLBcqumhTuFKc8nuCNK98D6zkQESdcHLLTquCOaF5L+5AQ0E" + + "QGsETwEIAOVwNCTaDZvW4dowPbET1bI5UeYY8rAGLYsWSUfgaFv2srMiApyBVltf" + + "i6OLcPjcUCHDBjCv4pwx/C4qcHWb8av4xQIpqQXOpO9NxYE1eZnel/QB7DtH12ZO" + + "nrDNmHtaXlulcKNGe1i1utlFhgzfFx6rWkRL0ENmkTkaQmPY4gTGymJTUhBbsSRq" + + "2ivWqQA1TPwBuda73UgslIAHRd/SUaxjXoLpMbGOTeqzcKGjr5XMPTs7/YgBpWPP" + + "UxMlEQIiU3ia1bxpEhx05k97ceK6TSH2oCPQA7gumjxOSjKT+jEm+8jACVzymEmc" + + "XRy4D5Ztqkw/Z16pvNcu1DI5m6xHwr8AEQEAAYkBIgQYAQIADAUCQGsETwUbDAAA" + + "AAAKCRDn3pbprojq2EynB/4/cEOtKbI5UisUd3vkTzvWOcqWUqGqi5wjjioNtIM5" + + "pur2nFvhQE7SZ+PbAa87HRJU/4WcWMcoLkHD48JrQwHCHOLHSV5muYowb78X4Yh9" + + "epYtSJ0uUahcn4Gp48p4BkhgsPYXkxEImSYzAOWStv21/7WEMqItMYl89BV6Upm8" + + "HyTJx5MPTDbMR7X51hRg3OeQs6po3WTCWRzFIMyGm1rd/VK1L5ZDFPqO3S6YUJ0z" + + "cxecYruvfK0Wp7q834wE8Zkl/PQ3NhfEPL1ZiLr/L00Ty+77/FZqt8SHRCICzOfP" + + "OawcVGI+xHVXW6lijMpB5VaVIH8i2KdBMHXHtduIkPr9"); + + byte[] sec5 = Base64.decode( + "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"); + + char[] sec5pass1 = "12345678".toCharArray(); + + // + // Werner Koch "odd keys" + // + byte[] pub6 = Base64.decode( + "mQGiBDWiHh4RBAD+l0rg5p9rW4M3sKvmeyzhs2mDxhRKDTVVUnTwpMIR2kIA9pT4" + + "3No/coPajDvhZTaDM/vSz25IZDZWJ7gEu86RpoEdtr/eK8GuDcgsWvFs5+YpCDwW" + + "G2dx39ME7DN+SRvEE1xUm4E9G2Nnd2UNtLgg82wgi/ZK4Ih9CYDyo0a9awCgisn3" + + "RvZ/MREJmQq1+SjJgDx+c2sEAOEnxGYisqIKcOTdPOTTie7o7x+nem2uac7uOW68" + + "N+wRWxhGPIxsOdueMIa7U94Wg/Ydn4f2WngJpBvKNaHYmW8j1Q5zvZXXpIWRXSvy" + + "TR641BceGHNdYiR/PiDBJsGQ3ac7n7pwhV4qex3IViRDJWz5Dzr88x+Oju63KtxY" + + "urUIBACi7d1rUlHr4ok7iBRlWHYXU2hpUIQ8C+UOE1XXT+HB7mZLSRONQnWMyXnq" + + "bAAW+EUUX2xpb54CevAg4eOilt0es8GZMmU6c0wdUsnMWWqOKHBFFlDIvyI27aZ9" + + "quf0yvby63kFCanQKc0QnqGXQKzuXbFqBYW2UQrYgjXji8rd8bQnV2VybmVyIEtv" + + "Y2ggKGdudXBnIHNpZykgPGRkOWpuQGdudS5vcmc+iGUEExECAB0FAjZVoKYFCQht" + + "DIgDCwQDBRUDAgYBAxYCAQIXgAASCRBot6uJV1SNzQdlR1BHAAEBLj4AoId15gcy" + + "YpBX2YLtEQTlXPp3mtEGAJ9UxzJE/t3EHCHK2bAIOkBwIW8ItIkBXwMFEDWiHkMD" + + "bxG4/z6qCxADYzIFHR6I9Si9gzPQNRcFs2znrTp5pV5Mk6f1aqRgZxL3E4qUZ3xe" + + "PQhwAo3fSy3kCwLmFGqvzautSMHn8K5V1u+T5CSHqLFYKqj5FGtuB/xwoKDXH6UO" + + "P0+l5IP8H1RTjme3Fhqahec+zPG3NT57vc2Ru2t6PmuAwry2BMuSFMBs7wzXkyC3" + + "DbI54MV+IKPjHMORivK8uI8jmna9hdNVyBifCk1GcxkHBSCFvU8xJePsA/Q//zCe" + + "lvrnrIiMfY4CQTmKzke9MSzbAZQIRddgrGAsiX1tE8Z3YMd8lDpuujHLVEdWZo6s" + + "54OJuynHrtFFObdapu0uIrT+dEXSASMUbEuNCLL3aCnrEtGJCwxB2TPQvCCvR2BK" + + "zol6MGWxA+nmddeQib2r+GXoKXLdnHcpsAjA7lkXk3IFyJ7MLFK6uDrjGbGJs2FK" + + "SduUjS/Ib4hGBBARAgAGBQI1oic8AAoJEGx+4bhiHMATftYAn1fOaKDUOt+dS38r" + + "B+CJ2Q+iElWJAKDRPpp8q5GylbM8DPlMpClWN3TYqYhGBBARAgAGBQI27U5sAAoJ" + + "EF3iSZZbA1iiarYAn35qU3ZOlVECELE/3V6q98Q30eAaAKCtO+lacH0Qq1E6v4BP" + + "/9y6MoLIhohiBBMRAgAiAhsDBAsHAwIDFQIDAxYCAQIeAQIXgAUCP+mCaQUJDDMj" + + "ywAKCRBot6uJV1SNzaLvAJwLsPV1yfc2D+yT+2W11H/ftNMDvwCbBweORhCb/O/E" + + "Okg2UTXJBR4ekoCIXQQTEQIAHQMLBAMFFQMCBgEDFgIBAheABQI/6YJzBQkMMyPL" + + "AAoJEGi3q4lXVI3NgroAn2Z+4KgVo2nzW72TgCJwkAP0cOc2AJ0ZMilsOWmxmEG6" + + "B4sHMLkB4ir4GIhdBBMRAgAdAwsEAwUVAwIGAQMWAgECF4AFAj/pgnMFCQwzI8sA" + + "CgkQaLeriVdUjc2CugCfRrOIfllp3mSmGpHgIxvg5V8vtMcAn0BvKVehOn+12Yvn" + + "9BCHfg34jUZbiF0EExECAB0DCwQDBRUDAgYBAxYCAQIXgAUCP+mCcwUJDDMjywAK" + + "CRBot6uJV1SNzYK6AJ9x7R+daNIjkieNW6lJeVUIoj1UHgCeLZm025uULML/5DFs" + + "4tUvXs8n9XiZAaIENaIg8xEEALYPe0XNsPjx+inTQ+Izz527ZJnoc6BhWik/4a2b" + + "ZYENSOQXAMKTDQMv2lLeI0i6ceB967MNubhHeVdNeOWYHFSM1UGRfhmZERISho3b" + + "p+wVZvVG8GBVwpw34PJjgYU/0tDwnJaJ8BzX6j0ecTSTjQPnaUEtdJ/u/gmG9j02" + + "18TzAKDihdNoKJEU9IKUiSjdGomSuem/VwQArHfaucSiDmY8+zyZbVLLnK6UJMqt" + + "sIv1LvAg20xwXoUk2bY8H3tXL4UZ8YcoSXYozwALq3cIo5UZJ0q9Of71mI8WLK2i" + + "FSYVplpTX0WMClAdkGt3HgVb7xtOhGt1mEKeRQjNZ2LteUQrRDD9MTQ+XxcvEN0I" + + "pAj4kBJe9bR6HzAD/iecCmGwSlHUZZrgqWzv78o79XxDdcuLdl4i2fL7kwEOf9js" + + "De7hGs27yrdJEmAG9QF9TOF9LJFmE1CqkgW+EpKxsY01Wjm0BFJB1R7iPUaUtFRZ" + + "xYqfgXarmPjql2iBi+cVjLzGu+4BSojVAPgP/hhcnIowf4M4edPiICMP1GVjtCFX" + + "ZXJuZXIgS29jaCA8d2VybmVyLmtvY2hAZ3V1Zy5kZT6IYwQTEQIAGwUCNs8JNwUJ" + + "CCCxRAMLCgMDFQMCAxYCAQIXgAASCRBsfuG4YhzAEwdlR1BHAAEBaSAAn3YkpT5h" + + "xgehGFfnX7izd+c8jI0SAJ9qJZ6jJvXnGB07p60aIPYxgJbLmYkAdQMFEDWjdxQd" + + "GfTBDJhXpQEBPfMC/0cxo+4xYVAplFO0nIYyjQgP7D8O0ufzPsIwF3kvb7b5FNNj" + + "fp+DAhN6G0HOIgkL3GsWtCfH5UHali+mtNFIKDpTtr+F/lPpZP3OPzzsLZS4hYTq" + + "mMs1O/ACq8axKgAilYkBXwMFEDWiJw4DbxG4/z6qCxADB9wFH0i6mmn6rWYKFepJ" + + "hXyhE4wWqRPJAnvfoiWUntDp4aIQys6lORigVXIWo4k4SK/FH59YnzF7578qrTZW" + + "/RcA0bIqJqzqaqsOdTYEFa49cCjvLnBW4OebJlLTUs/nnmU0FWKW8OwwL+pCu8d7" + + "fLSSnggBsrUQwbepuw0cJoctFPAz5T1nQJieQKVsHaCNwL2du0XefOgF5ujB1jK1" + + "q3p4UysF9hEcBR9ltE3THr+iv4jtZXmC1P4at9W5LFWsYuwr0U3yJcaKSKp0v/wG" + + "EWe2J/gFQZ0hB1+35RrCZPgiWsEv87CHaG6XtQ+3HhirBCJsYhmOikVKoEan6PhU" + + "VR1qlXEytpAt389TBnvyceAX8hcHOE3diuGvILEgYes3gw3s5ZmM7bUX3jm2BrX8" + + "WchexUFUQIuKW2cL379MFXR8TbxpVxrsRYE/4jHZBYhGBBARAgAGBQI27U4LAAoJ" + + "EF3iSZZbA1iifJoAoLEsGy16hV/CfmDku6D1CBUIxXvpAJ9GBApdC/3OXig7sBrV" + + "CWOb3MQzcLkBjQQ2zwcIEAYA9zWEKm5eZpMMBRsipL0IUeSKEyeKUjABX4vYNurl" + + "44+2h6Y8rHn7rG1l/PNj39UJXBkLFj1jk8Q32v+3BQDjvwv8U5e/kTgGlf7hH3WS" + + "W38RkZw18OXYCvnoWkYneIuDj6/HH2bVNXmTac05RkBUPUv4yhqlaFpkVcswKGuE" + + "NRxujv/UWvVF+/2P8uSQgkmGp/cbwfMTkC8JBVLLBRrJhl1uap2JjZuSVklUUBez" + + "Vf3NJMagVzx47HPqLVl4yr4bAAMGBf9PujlH5I5OUnvZpz+DXbV/WQVfV1tGRCra" + + "kIj3mpN6GnUDF1LAbe6vayUUJ+LxkM1SqQVcmuy/maHXJ+qrvNLlPqUZPmU5cINl" + + "sA7bCo1ljVUp54J1y8PZUx6HxfEl/LzLVkr+ITWnyqeiRikDecUf4kix2teTlx6I" + + "3ecqT5oNqZSRXWwnN4SbkXtAd7rSgEptUYhQXgSEarp1pXJ4J4rgqFa49jKISDJq" + + "rn/ElltHe5Fx1bpfkCIYlYk45Cga9bOIVAQYEQIADAUCNs8HCAUJBvPJAAASCRBs" + + "fuG4YhzAEwdlR1BHAAEBeRUAoIGpCDmMy195TatlloHAJEjZu5KaAJwOvW989hOb" + + "8cg924YIFVA1+4/Ia7kBjQQ1oiE8FAYAkQmAlOXixb8wra83rE1i7LCENLzlvBZW" + + "KBXN4ONelZAnnkOm7IqRjMhtKRJN75zqVyKUaUwDKjpf9J5K2t75mSxBtnbNRqL3" + + "XodjHK93OcAUkz3ci7iuC/b24JI2q4XeQG/v4YR1VodM0zEQ1IC0JCq4Pl39QZyX" + + "JdZCrUFvMcXq5ruNSldztBqTFFUiFbkw1Fug/ZyXJve2FVcbsRXFrB7EEuy+iiU/" + + "kZ/NViKk0L4T6KRHVsEiriNlCiibW19fAAMFBf9Tbv67KFMDrLqQan/0oSSodjDQ" + + "KDGqtoh7KQYIKPXqfqT8ced9yd5MLFwPKf3t7AWG1ucW2x118ANYkPSU122UTndP" + + "sax0cY4XkaHxaNwpNFCotGQ0URShxKNpcqbdfvy+1d8ppEavgOyxnV1JOkLjZJLw" + + "K8bgxFdbPWcsJJnjuuH3Pwz87CzTgOSYQxMPnIwQcx5buZIV5NeELJtcbbd3RVua" + + "K/GQht8QJpuXSji8Nl1FihYDjACR8TaRlAh50GmIRgQoEQIABgUCOCv7gwAKCRBs" + + "fuG4YhzAE9hTAJ9cRHu+7q2hkxpFfnok4mRisofCTgCgzoPjNIuYiiV6+wLB5o11" + + "7MNWPZCIVAQYEQIADAUCNaIhPAUJB4TOAAASCRBsfuG4YhzAEwdlR1BHAAEBDfUA" + + "oLstR8cg5QtHwSQ3nFCOKEREUFIwAKDID3K3hM+b6jW1o+tNX9dnjb+YMZkAbQIw" + + "bYOUAAABAwC7ltmO5vdKssohwzXEZeYvDW2ll3CYD2I+ruiNq0ybxkfFBopq9cxt" + + "a0OvVML4LK/TH+60f/Fqx9wg2yk9APXyaomdLrXfWyfZ91YtNCfj3ElC4XB4qqm0" + + "HRn0wQyYV6UABRG0IVdlcm5lciBLb2NoIDx3ZXJuZXIua29jaEBndXVnLmRlPokA" + + "lQMFEDRfoOmOB31Gi6BmjQEBzwgD/2fHcdDXuRRY+SHvIVESweijstB+2/sVRp+F" + + "CDjR74Kg576sJHfTJCxtSSmzpaVpelb5z4URGJ/Byi5L9AU7hC75S1ZnJ+MjBT6V" + + "ePyk/r0uBrMkU/lMG7lk/y2By3Hll+edjzJsdwn6aoNPiyen4Ch4UGTEguxYsLq0" + + "HES/UvojiQEVAwUTNECE2gnp+QqKck5FAQH+1Af/QMlYPlLG+5E19qP6AilKQUzN" + + "kd1TWMenXTS66hGIVwkLVQDi6RCimhnLMq/F7ENA8bSbyyMuncaBz5dH4kjfiDp1" + + "o64LULcTmN1LW9ctpTAIeLLJZnwxoJLkUbLUYKADKqIBXHMt2B0zRmhFOqEjRN+P" + + "hI7XCcHeHWHiDeUB58QKMyeoJ/QG/7zLwnNgDN2PVqq2E72C3ye5FOkYLcHfWKyB" + + "Rrn6BdUphAB0LxZujSGk8ohZFbia+zxpWdE8xSBhZbjVGlwLurmS2UTjjxByBNih" + + "eUD6IC3u5P6psld0OfqnpriZofP0CBP2oTk65r529f/1lsy2kfWrVPYIFJXEnIkA" + + "lQMFEDQyneGkWMS9SnJfMQEBMBMD/1ADuhhuY9kyN7Oj6DPrDt5SpPQDGS0Jtw3y" + + "uIPoed+xyzlrEuL2HeaOj1O9urpn8XLN7V21ajkzlqsxnGkOuifbE9UT67o2b2vC" + + "ldCcY4nV5n+U1snMDwNv+RkcEgNa8ANiWkm03UItd7/FpHDQP0FIgbPEPwRoBN87" + + "I4gaebfRiQCVAwUQNDUSwxRNm5Suj3z1AQGMTAP/UaXXMhPzcjjLxBW0AccTdHUt" + + "Li+K+rS5PNxxef2nnasEhCdK4GkM9nwJgsP0EZxCG3ZSAIlWIgQ3MK3ZAV1Au5pL" + + "KolRjFyEZF420wAtiE7V+4lw3FCqNoXDJEFC3BW431kx1wAhDk9VaIHHadYcof4d" + + "dmMLQOW2cJ7LDEEBW/WJAJUDBRA0M/VQImbGhU33abUBARcoA/9eerDBZGPCuGyE" + + "mQBcr24KPJHWv/EZIKl5DM/Ynz1YZZbzLcvEFww34mvY0jCfoVcCKIeFFBMKiSKr" + + "OMtoVC6cQMKpmhE9hYRStw4E0bcf0BD/stepdVtpwRnG8SDP2ZbmtgyjYT/7T4Yt" + + "6/0f6N/0NC7E9qfq4ZlpU3uCGGu/44kAlQMFEDQz8kp2sPVxuCQEdQEBc5YD/Rix" + + "vFcLTO1HznbblrO0WMzQc+R4qQ50CmCpWcFMwvVeQHo/bxoxGggNMmuVT0bqf7Mo" + + "lZDSJNS96IAN32uf25tYHgERnQaMhmi1aSHvRDh4jxFu8gGVgL6lWit/vBDW/BiF" + + "BCH6sZJJrGSuSdpecTtaWC8OJGDoKTO9PqAA/HQRiQB1AwUQNDJSx011eFs7VOAZ" + + "AQGdKQL/ea3qD2OP3wVTzXvfjQL1CosX4wyKusBBhdt9u2vOT+KWkiRk1o35nIOG" + + "uZLHtSFQDY8CVDOkqg6g4sVbOcTl8QUwHA+A4AVDInwTm1m4Bk4oeCIwk4Bp6mDd" + + "W11g28k/iQEVAgUSNDIWPm/Y4wPDeaMxAQGvBQgAqGhzA/21K7oL/L5S5Xz//eO7" + + "J8hgvqqGXWd13drNy3bHbKPn7TxilkA3ca24st+6YPZDdSUHLMCqg16YOMyQF8gE" + + "kX7ZHWPacVoUpCmSz1uQ3p6W3+u5UCkRpgQN8wBbJx5ZpBBqeq5q/31okaoNjzA2" + + "ghEWyR5Ll+U0C87MY7pc7PlNHGCr0ZNOhhtf1jU+H9ag5UyT6exIYim3QqWYruiC" + + "LSUcim0l3wK7LMW1w/7Q6cWfAFQvl3rGjt3rg6OWg9J4H2h5ukf5JNiRybkupmat" + + "UM+OVMRkf93jzU62kbyZpJBHiQZuxxJaLkhpv2RgWib9pbkftwEy/ZnmjkxlIIkA" + + "lQMFEDQvWjh4313xYR8/NQEB37QEAIi9vR9h9ennz8Vi7RNU413h1ZoZjxfEbOpk" + + "QAjE/LrZ/L5WiWdoStSiyqCLPoyPpQafiU8nTOr1KmY4RgceJNgxIW4OiSMoSvrh" + + "c2kqP+skb8A2B4+47Aqjr5fSAVfVfrDMqDGireOguhQ/hf9BOYsM0gs+ROdtyLWP" + + "tMjRnFlviD8DBRAz8qQSj6lRT5YOKXIRAntSAJ9StSEMBoFvk8iRWpXb6+LDNLUW" + + "zACfT8iY3IxwvMF6jjCHrbuxQkL7chSJARUDBRA0MMO7569NIyeqD3EBATIAB/4t" + + "CPZ1sLWO07g2ZCpiP1HlYpf5PENaXtaasFvhWch7eUe3DksuMEPzB5GnauoQZAku" + + "hEGkoEfrfL3AXtXH+WMm2t7dIcTBD4p3XkeZ+PgJpKiASXDyul9rumXXvMxSL4KV" + + "7ar+F1ZJ0ycCx2r2au0prPao70hDAzLTy16hrWgvdHSK7+wwaYO5TPCL5JDmcB+d" + + "HKW72qNUOD0pxbe0uCkkb+gDxeVX28pZEkIIOMMV/eAs5bs/smV+eJqWT/EyfVBD" + + "o7heF2aeyJj5ecxNOODr88xKF7qEpqazCQ4xhvFY+Yn6+vNCcYfkoZbOn0XQAvqf" + + "a2Vab9woVIVSaDji/mlPiQB1AwUQNDC233FfeD4HYGBJAQFh6QL/XCgm5O3q9kWp" + + "gts1MHKoHoh7vxSSQGSP2k7flNP1UB2nv4sKvyGM8eJKApuROIodcTkccM4qXaBu" + + "XunMr5kJlvDJPm+NLzKyhtQP2fWI7xGYwiCiB29gm1GFMjdur4amiQEVAwUQNDBR" + + "9fjDdqGixRdJAQE+mAf+JyqJZEVFwNwZ2hSIMewekC1r7N97p924nqfZKnzn6weF" + + "pE80KIJSWtEVzI0XvHlVCOnS+WRxn7zxwrOTbrcEOy0goVbNgUsP5ypZa2/EM546" + + "uyyJTvgD0nwA45Q4bP5sGhjh0G63r9Vwov7itFe4RDBGM8ibGnZTr9hHo469jpom" + + "HSNeavcaUYyEqcr4GbpQmdpJTnn/H0A+fMl7ZHRoaclNx9ZksxihuCRrkQvUOb3u" + + "RD9lFIhCvNwEardN62dKOKJXmn1TOtyanZvnmWigU5AmGuk6FpsClm3p5vvlid64" + + "i49fZt9vW5krs2XfUevR4oL0IyUl+qW2HN0DIlDiAYkAlQMFEDQvbv2wcgJwUPMh" + + "JQEBVBID/iOtS8CQfMxtG0EmrfaeVUU8R/pegBmVWDBULAp8CLTtdfxjVzs/6DXw" + + "0RogXMRRl2aFfu1Yp0xhBYjII6Kque/FzAFXY9VNF1peqnPt7ADdeptYMppZa8sG" + + "n9BBRu9Fsw69z6JkyqvMiVxGcKy3XEpVGr0JHx8Xt6BYdrULiKr2iQB1AwUQNC68" + + "n6jZR/ntlUftAQFaYgL+NUYEj/sX9M5xq1ORX0SsVPMpNamHO3JBSmZSIzjiox5M" + + "AqoFOCigAkonuzk5aBy/bRHy1cmDBOxf4mNhzrH8N6IkGvPE70cimDnbFvr+hoZS" + + "jIqxtELNZsLuLVavLPAXiQCVAwUQNC6vWocCuHlnLQXBAQHb1gQAugp62aVzDCuz" + + "4ntfXsmlGbLY7o5oZXYIKdPP4riOj4imcJh6cSgYFL6OMzeIp9VW/PHo2mk8kkdk" + + "z5uif5LqOkEuIxgra7p1Yq/LL4YVhWGQeD8hwpmu+ulYoPOw40dVYS36PwrHIH9a" + + "fNhl8Or5O2VIHIWnoQ++9r6gwngFQOyJAJUDBRAzHnkh1sNKtX1rroUBAWphBACd" + + "huqm7GHoiXptQ/Y5F6BivCjxr9ch+gPSjaLMhq0kBHVO+TbXyVefVVGVgCYvFPjo" + + "zM8PEVykQAtY//eJ475aGXjF+BOAhl2z0IMkQKCJMExoEDHbcj0jIIMZ2/+ptgtb" + + "FSyJ2DQ3vvCdbw/1kyPHTPfP+L2u40GWMIYVBbyouokAlQMFEDMe7+UZsymln7HG" + + "2QEBzMED/3L0DyPK/u6PyAd1AdpjUODTkWTZjZ6XA2ubc6IXXsZWpmCgB/24v8js" + + "J3DIsvUD3Ke55kTr6xV+au+mAkwOQqWUTUWfQCkSrSDlbUJ1VPBzhyTpuzjBopte" + + "7o3R6XXfcLiC5jY6eCX0QtLGhKpLjTr5uRhf1fYODGsAGXmCByDviQB1AgUQMy6U" + + "MB0Z9MEMmFelAQHV4AMAjdFUIyFtpTr5jkyZSd3y//0JGO0z9U9hLVxeBBCwvdEQ" + + "xsrpeTtVdqpeKZxHN1GhPCYvgLFZAQlcPh/Gc8u9uO7wVSgJc3zYKFThKpQevdF/" + + "rzjTCHfgigf5Iui0qiqBiQCVAwUQMx22bAtzgG/ED06dAQFi0gQAkosqTMWy+1eU" + + "Xbi2azFK3RX5ERf9wlN7mqh7TvwcPXvVWzUARnwRv+4kk3uOWI18q5UPis7KH3KY" + + "OVeRrPd8bbp6SjhBh82ourTEQUXLBDQiI1V1cZZmwwEdlnAnhFnkXgMBNM2q7oBe" + + "fRHADfYDfGo90wXyrVVL+GihDNpzUwOJAJUDBRAzHUFnOWvfULwOR3EBAbOYA/90" + + "JIrKmxhwP6quaheFOjjPoxDGEZpGJEOwejEByYj+AgONCRmQS3BydtubA+nm/32D" + + "FeG8pe/dnFvGc+QgNW560hK21C2KJj72mhjRlg/na7jz4/MmBAv5k61Q7roWi0rw" + + "x+R9NSHxpshC8A92zmvo8w/XzVSogC8pJ04jcnY6YokAlQMFEDMdPtta9LwlvuSC" + + "3QEBvPMD/3TJGroHhHYjHhiEpDZZVszeRQ0cvVI/uLLi5yq3W4F6Jy47DF8VckA7" + + "mw0bXrOMNACN7Je7uyaU85qvJC2wgoQpFGdFlkjmkAwDAjR+koEysiE8FomiOHhv" + + "EpEY/SjSS4jj4IPmgV8Vq66XjPw+i7Z0RsPLOIf67yZHxypNiBiYiQCVAwUQMxxw" + + "pKrq6G7/78D5AQHo2QQAjnp6KxOl6Vvv5rLQ/4rj3OemvF7IUUq34xb25i/BSvGB" + + "UpDQVUmhv/qIfWvDqWGZedyM+AlNSfUWPWnP41S8OH+lcERH2g2dGKGl7kH1F2Bx" + + "ByZlqREHm2q624wPPA35RLXtXIx06yYjLtJ7b+FCAX6PUgZktZYk5gwjdoAGrC2J" + + "AJUDBRAzGvcCKC6c7f53PGUBAUozA/9l/qKmcqbi8RtLsKQSh3vHds9d22zcbkuJ" + + "PBSoOv2D7i2VLshaQFjq+62uYZGE6nU1WP5sZcBDuWjoX4t4NrffnOG/1R9D0t1t" + + "9F47D77HJzjvo+J52SN520YHcbT8VoHdPRoEOXPN4tzhvn2GapVVdaAlWM0MLloh" + + "NH3I9jap9okAdQMFEDMZlUAnyXglSykrxQEBnuwC/jXbFL+jzs2HQCuo4gyVrPlU" + + "ksQCLYZjNnZtw1ca697GV3NhBhSXR9WHLQH+ZWnpTzg2iL3WYSdi9tbPs78iY1FS" + + "d4EG8H9V700oQG8dlICF5W2VjzR7fByNosKM70WSXYkBFQMFEDMWBsGCy1t9eckW" + + "HQEBHzMH/jmrsHwSPrA5R055VCTuDzdS0AJ+tuWkqIyqQQpqbost89Hxper3MmjL" + + "Jas/VJv8EheuU3vQ9a8sG2SnlWKLtzFqpk7TCkyq/H3blub0agREbNnYhHHTGQFC" + + "YJb4lWjWvMjfP+N5jvlLcnDqQPloXfAOgy7W90POoqFrsvhxdpnXgoLrzyNNja1O" + + "1NRj+Cdv/GmJYNi6sQe43zmXWeA7syLKMw6058joDqEJFKndgSp3Zy/yXmObOZ/H" + + "C2OJwA3gzEaAu8Pqd1svwGIGznqtTNCn9k1+rMvJPaxglg7PXIJS282hmBl9AcJl" + + "wmh2GUCswl9/sj+REWTb8SgJUbkFcp6JAJUDBRAwdboVMPfsgxioXMEBAQ/LA/9B" + + "FTZ9T95P/TtsxeC7lm9imk2mpNQCBEvXk286FQnGFtDodGfBfcH5SeKHaUNxFaXr" + + "39rDGUtoTE98iAX3qgCElf4V2rzgoHLpuQzCg3U35dfs1rIxlpcSDk5ivaHpPV3S" + + "v+mlqWL049y+3bGaZeAnwM6kvGMP2uccS9U6cbhpw4hGBBARAgAGBQI3GtRfAAoJ" + + "EF3iSZZbA1iikWUAoIpSuXzuN/CI63dZtT7RL7c/KtWUAJ929SAtTr9SlpSgxMC8" + + "Vk1T1i5/SYkBFQMFEzccnFnSJilEzmrGwQEBJxwH/2oauG+JlUC3zBUsoWhRQwqo" + + "7DdqaPl7sH5oCGDKS4x4CRA23U15NicDI7ox6EizkwCjk0dRr1EeRK+RqL1b/2T4" + + "2B6nynOLhRG2A0BPHRRJLcoL4nKfoPSo/6dIC+3iVliGEl90KZZD5bnONrVJQkRj" + + "ZL8Ao+9IpmoYh8XjS5xMLEF9oAQqAkA93nVBm56lKmaL1kl+M3dJFtNKtVB8de1Z" + + "XifDs8HykD42qYVtcseCKxZXhC3UTG5YLNhPvgZKH8WBCr3zcR13hFDxuecUmu0M" + + "VhvEzoKyBYYt0rrqnyWrxwbv4gSTUWH5ZbgsTjc1SYKZxz6hrPQnfYWzNkznlFWJ" + + "ARUDBRM0xL43CdxwOTnzf10BATOCB/0Q6WrpzwPMofjHj54MiGLKVP++Yfwzdvns" + + "HxVpTZLZ5Ux8ErDsnLmvUGphnLVELZwEkEGRjln7a19h9oL8UYZaV+IcR6tQ06Fb" + + "1ldR+q+3nXtBYzGhleXdgJQSKLJkzPF72tvY0DHUB//GUV9IBLQMvfG8If/AFsih" + + "4iXi96DOtUAbeuIhnMlWwLJFeGjLLsX1u6HSX33xy4bGX6v/UcHbTSSYaxzb92GR" + + "/xpP2Xt332hOFRkDZL52g27HS0UrEJWdAVZbh25KbZEl7C6zX/82OZ5nTEziHo20" + + "eOS6Nrt2+gLSeA9X5h/+qUx30kTPz2LUPBQyIqLCJkHM8+0q5j9ciQCiAwUTNMS+" + + "HZFeTizbCJMJAQFrGgRlEAkG1FYU4ufTxsaxhFZy7xv18527Yxpls6mSCi1HL55n" + + "Joce6TI+Z34MrLOaiZljeQP3EUgzA+cs1sFRago4qz2wS8McmQ9w0FNQQMz4vVg9" + + "CVi1JUVd4EWYvJpA8swDd5b9+AodYFEsfxt9Z3aP+AcWFb10RlVVsNw9EhObc6IM" + + "nwAOHCEI9vp5FzzFiQCVAwUQNxyr6UyjTSyISdw9AQHf+wP+K+q6hIQ09tkgaYaD" + + "LlWKLbuxePXqM4oO72qi70Gkg0PV5nU4l368R6W5xgR8ZkxlQlg85sJ0bL6wW/Sj" + + "Mz7pP9hkhNwk0x3IFkGMTYG8i6Gt8Nm7x70dzJoiC+A496PryYC0rvGVf+Om8j5u" + + "TexBBjb/jpJhAQ/SGqeDeCHheOC0Lldlcm5lciBLb2NoIChtZWluIGFsdGVyIGtl" + + "eSkgPHdrQGNvbXB1dGVyLm9yZz6JAHUDBRM2G2MyHRn0wQyYV6UBASKKAv4wzmK7" + + "a9Z+g0KH+6W8ffIhzrQo8wDAU9X1WJKzJjS205tx4mmdnAt58yReBc/+5HXTI8IK" + + "R8IgF+LVXKWAGv5P5AqGhnPMeQSCs1JYdf9MPvbe34jD8wA1LTWFXn9e/cWIRgQQ" + + "EQIABgUCNxrUaQAKCRBd4kmWWwNYovRiAJ9dJBVfjx9lGARoFXmAieYrMGDrmwCZ" + + "AQyO4Wo0ntQ+iq4do9M3/FTFjiCZAaIENu1I6REEAJRGEqcYgXJch5frUYBj2EkD" + + "kWAbhRqVXnmiF3PjCEGAPMMYsTddiU7wcKfiCAqKWWXow7BjTJl6Do8RT1jdKpPO" + + "lBJXqqPYzsyBxLzE6mLps0K7SLJlSKTQqSVRcx0jx78JWYGlAlP0Kh9sPV2w/rPh" + + "0LrPeOKXT7lZt/DrIhfPAKDL/sVqCrmY3QfvrT8kSKJcgtLWfQP/cfbqVNrGjW8a" + + "m631N3UVA3tWfpgM/T9OjmKmw44NE5XfPJTAXlCV5j7zNMUkDeoPkrFF8DvbpYQs" + + "4XWYHozDjhR2Q+eI6gZ0wfmhLHqqc2eVVkEG7dT57Wp9DAtCMe7RZfhnarTQMqlY" + + "tOEa/suiHk0qLo59NsyF8eh68IDNCeYD/Apzonwaq2EQ1OEpfFlp6LcSnS34+UGZ" + + "tTO4BgJdmEjr/QrIPp6bJDstgho+/2oR8yQwuHGJwbS/8ADA4IFEpLduSpzrABho" + + "7RuNQcm96bceRY+7Hza3zf7pg/JGdWOb+bC3S4TIpK+3sx3YNWs7eURwpGREeJi5" + + "/Seic+GXlGzltBpXZXJuZXIgS29jaCA8d2tAZ251cGcub3JnPohjBBMRAgAbBQI3" + + "Gs+QBQkMyXyAAwsKAwMVAwIDFgIBAheAABIJEF3iSZZbA1iiB2VHUEcAAQFdwgCe" + + "O/s43kCLDMIsHCb2H3LC59clC5UAn1EyrqWk+qcOXLpQIrP6Qa3QSmXIiEYEEBEC" + + "AAYFAjca0T0ACgkQbH7huGIcwBOF9ACeNwO8G2G0ei03z0g/n3QZIpjbzvEAnRaE" + + "qX2PuBbClWoIP6h9yrRlAEbUiQB1AwUQNxrRYx0Z9MEMmFelAQHRrgL/QDNKPV5J" + + "gWziyzbHvEKfTIw/Ewv6El2MadVvQI8kbPN4qkPr2mZWwPzuc9rneCPQ1eL8AOdC" + + "8+ZyxWzx2vsrk/FcU5donMObva2ct4kqJN6xl8xjsxDTJhBSFRaiBJjxiEYEEBEC" + + "AAYFAjca0aMACgkQaLeriVdUjc0t+ACghK37H2vTYeXXieNJ8aZkiPJSte4An0WH" + + "FOotQdTW4NmZJK+Uqk5wbWlgiEYEEBECAAYFAjdPH10ACgkQ9u7fIBhLxNktvgCe" + + "LnQ5eOxAJz+Cvkb7FnL/Ko6qc5YAnjhWWW5c1o3onvKEH2Je2wQa8T6iiEYEEBEC" + + "AAYFAjenJv4ACgkQmDRl2yFDlCJ+yQCfSy1zLftEfLuIHZsUHis9U0MlqLMAn2EI" + + "f7TI1M5OKysQcuFLRC58CfcfiEUEEBECAAYFAjfhQTMACgkQNmdg8X0u14h55wCf" + + "d5OZCV3L8Ahi4QW/JoXUU+ZB0M0AmPe2uw7WYDLOzv48H76tm6cy956IRgQQEQIA" + + "BgUCOCpiDwAKCRDj8lhUEo8OeRsdAJ9FHupRibBPG2t/4XDqF+xiMLL/8ACfV5F2" + + "SR0ITE4k/C+scS1nJ1KZUDW0C1dlcm5lciBLb2NoiGMEExECABsFAjbtSOoFCQzJ" + + "fIADCwoDAxUDAgMWAgECF4AAEgkQXeJJllsDWKIHZUdQRwABAbXWAJ9SCW0ieOpL" + + "7AY6vF+OIaMmw2ZW1gCgkto0eWfgpjAuVg6jXqR1wHt2pQOJAh4EEBQDAAYFAjcv" + + "WdQACgkQbEwxpbHVFWcNxQf/bg14WGJ0GWMNSuuOOR0WYzUaNtzYpiLSVyLrreXt" + + "o8LBNwzbgzj2ramW7Ri+tYJAHLhtua8ZgSeibmgBuZasF8db1m5NN1ZcHBXGTysA" + + "jp+KnicTZ9Orj75D9o3oSmMyRcisEhr+gkj0tVhGfOAOC6eKbufVuyYFDVIyOyUB" + + "GlW7ApemzAzYemfs3DdjHn87lkjHMVESO4fM5rtLuSc7cBfL/e6ljaWQc5W8S0gI" + + "Dv0VtL39pMW4BlpKa25r14oJywuUpvWCZusvDm7ZJnqZ/WmgOHQUsyYudTROpGIb" + + "lsNg8iqC6huWpGSBRdu3oRQRhkqpfVdszz6BB/nAx01q2wf/Q+U9XId1jyzxUL1S" + + "GgaYMf6QdyjHQ1oxuFLNxzM6C/M069twbNgXJ71RsDDXVxFZfSTjSiH100AP9+9h" + + "b5mycaXLUOXYDvOSFzHBd/LsjFNVrrFbDs5Xw+cLGVHOIgR5IWAfgu5d1PAZU9uQ" + + "VgdGnQfmZg383RSPxvR3fnZz1rHNUGmS6w7x6FVbxa1QU2t38gNacIwHATAPcBpy" + + "JLfXoznbpg3ADbgCGyDjBwnuPQEQkYwRakbczRrge8IaPZbt2HYPoUsduXMZyJI8" + + "z5tvu7pUDws51nV1EX15BcN3++aY5pUyA1ItaaDymQVmoFbQC0BNMzMO53dMnFko" + + "4i42kohGBBARAgAGBQI3OvmjAAoJEHUPZJXInZM+hosAnRntCkj/70shGTPxgpUF" + + "74zA+EbzAKCcMkyHXIz2W0Isw3gDt27Z9ggsE4hGBBARAgAGBQI3NyPFAAoJEPbu" + + "3yAYS8TZh2UAoJVmzw85yHJzsXQ1vpO2IAPfv59NAJ9WY0oiYqb3q1MSxBRwG0gV" + + "iNCJ7YkBFQMFEDdD3tNSgFdEdlNAHQEByHEH/2JMfg71GgiyGJTKxCAymdyf2j2y" + + "fH6wI782JK4BWV4c0E/V38q+jpIYslihV9t8s8w1XK5niMaLwlCOyBWOkDP3ech6" + + "+GPPtfB3cmlL2hS896PWZ1adQHgCeQpB837n56yj0aTs4L1xarbSVT22lUwMiU6P" + + "wYdH2Rh8nh8FvN0IZsbln2nOj73qANQzNflmseUKF1Xh4ck8yLrRd4r6amhxAVAf" + + "cYFRJN4zdLL3cmhgkt0ADZlzAwXnEjwdHHy7SvAJk1ecNOA9pFsOJbvnzufd1afs" + + "/CbG78I+0JDhg75Z2Nwq8eKjsKqiO0zz/vG5yWSndZvWkTWz3D3b1xr1Id2IRgQQ" + + "EQIABgUCOCpiHgAKCRDj8lhUEo8OeQ+QAKCbOTscyUnWHSrDo4fIy0MThEjhOgCe" + + "L4Kb7TWkd/OHQScVBO8sTUz0+2g="); + + byte[] pub6check = Base64.decode("62O9"); + + // + // revoked master key + // + byte[] pub7 = Base64.decode( + "mQGiBFKQDEMRBACtcEzu15gGDrZKLuO2zgDJ9qFkweOxKyeO45LKIfUGBful" + + "lheoFHbsJIeNGjWbSOfWWtphTaSu9//BJt4xxg2pqVLYqzR+hEPpDy9kXxnZ" + + "LwwxjAP2TcOvuZKWe+JzoYQxDunOH4Zu9CPJhZhF3RNPw+tbv0jHfTV/chtb" + + "23Dj5wCg7eoM8bL9NYXacsAfkS//m+AB1MkD/jEZJqJSQHW8WVP7wKRrAZse" + + "N4l9b8+yY4RwLIodhD8wGsMYjkCF4yb/SQ5QlmLlvrHDLBofRzG+8oxldX4o" + + "GLZWvqPmW+BlS4QNSr+ZBu+OwnpClXG2pR+ExumXNoeArREyylrmOgD+0cUa" + + "8K2UbOxbJ8EioyOKxa7wjUVxmHmhBACAGQGLT/lpHA5zcU0g8AlSk8fsd+bB" + + "nwa/+9xdLqVsCTZdOWULtPOw9hbAdjjAy0L4M/MDAJYYtCEl9rB7aOc9PVdT" + + "h7CT9Ma6ltiSMKDlqWbDmogNEGx9Gz3GjiSGxAy/SN6JR1On4c60TAiTv6eE" + + "uEHszE6CH4qceK5W8HLLB4hJBCARAgAJBQJSkA0OAh0CAAoJEBCIvJhXZzdI" + + "X8wAn0qUP/jqAuPEX9g2XCr5jN3RKvKjAKDpx4NP7P1/yLN2ycFIgxKZ1plK" + + "CLACAAO0J3Jldm9rZSAoUmV2b2tlIFRlc3QpIDxyZXZva2VAdGVzdC50ZXN0" + + "PohiBBMRAgAiBQJSkAxDAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK" + + "CRAQiLyYV2c3SKw0AJ9kufxvnorVOv6a+WM+I/bNP+mjLQCgtPKuwTyeZU2k" + + "Sec1fJZUssDL1hGwAgADuQENBFKQDEMQBACruJ54GuhUaXgqGzu/HsCrgGQA" + + "n86PZW1qPCX28E9sayEmVOgzSDA/OT5c05P0PVLhMNEguSnUGC249MpZfPK/" + + "9LVKMXATZLzEB6lFX1YJdfrrb9KrQ5kdDhOcFXm1GIGBwLzjUmXYRVPH+TsT" + + "4QFvDpfIANQZfKK4UV5BJzJV5wADBQP/ew75dy1x58KWpPqfeH1OVln/Ui6e" + + "EDyyISic147+FIfVDuLtWoxMFE0ZPg47+rEQrhWC96izaSKPW97y5bkWz5PG" + + "CMChnLcg+3M91x/QCGzNhzVMiVpY5VhBDFP+7iiOaKYRiN/x7oasf2482Ny8" + + "1oiykOZUm8FCUQnRmJzIlbiISQQYEQIACQUCUpAMQwIbDAAKCRAQiLyYV2c3" + + "SL04AJ9VceD1DtcEDaWPDzFPgpe3ZfiXiQCfe5azYl26JpHSJvNKZRLi0I8H" + + "shCwAgAD"); + + byte[] pub7sub = Base64.decode( + "mQGiBFKQFFURBAD7CTE4RYPD7O+ki7pl/vXSZsSR0kQhCD9BR4lwE/Iffzmr" + + "vK8tmr2yLKWoXyoc3VF0Gdg/VATDcawBnKSjuCIsFZ58Edacb7uVRl4+ACiu" + + "OsvCKl9JuZ54SQ/tbD+NFS+HWNyVlWn7vDv8l+37DWNxuQRIYtQR+drAnIwQ" + + "g0O4owCg5a9cGAaN0zNVssUo6GFEoAI8nE0EAJMxQMcHTlLQQN1c549Ub0+E" + + "LV4dRIxjO7O6yi6Bg5udwS9Un1XeHF4GM7fj95WHi7o9sgErr2evhuGWl337" + + "ySytE1npk2F/jqevhAJazQTuilEuyjMbCShV39qJlEKtU9uHQYxN8oqGT9Ot" + + "lOoXXtrgfHbsrouCVwm4Jk14kzCaA/4okwrQwGkPlXRpVFyLn4GwrGivG7eh" + + "enRbAd2SQBiNVKmMsKLxHT1avZ11qcx6OU3ixdw5wYmq7TNR+5FXiz/e2MIq" + + "m7VhKONN21F7WC7siHxXfqqI/uz2tTPrFoLbnr/j/RZZRUMh6qUQrWpv58ci" + + "Bh+xkWCRantLCL9khuvRSrQncmV2b2tlIChSZXZva2UgVGVzdCkgPHJldm9r" + + "ZUB0ZXN0LnRlc3Q+iGIEExECACIFAlKQFFUCGwMGCwkIBwMCBhUIAgkKCwQW" + + "AgMBAh4BAheAAAoJEDKzvtpHqpp2DN4AoNS9M634KdvZT25DclGpb2bCFjv0" + + "AKDYXl5fIRGi583vFJ9C/q8hNGyNc7ACAAO5AQ0EUpAUVRAEALusV5UIL4gB" + + "6qQk++h+czV9KS0yxwgZyR+dJza+duEG88aNv28Wmjpfr3ZkvIiUaOcxFoct" + + "LgVGtPJM1HhWJtoA94CRBFTGzLfUIfXHcyXSdAw8Qh96svRl2w2KM+/pJl1r" + + "A3CWIy48jQei0mLwElRELLG7HJKYJxjCbg4+ihYTAAMGA/42PgHTV5VpF7YC" + + "XodlLOyGDVOoRjsvu0Gu/P88QnVP2jN57MJcla224aN3pGprtcbTwyjt+dtf" + + "5IJlB+3RZLczyqvT5hw7j9h81mr3RDbg3cn57xdYwQNP+6b6Wf9QRmaE813s" + + "g3kF0IJ0oFvwZdHnjndQ0JCrKaPflGSO6msjIYhTBCgRAgATBQJSkBXdDB0B" + + "U3VwZXJzZWRlZAAKCRAys77aR6qadmZPAJ0eJzmgBLTWK9RIbVtRUFzm736I" + + "hACgsPGHdZmLUFhV80fvYnUtB7TYGeKwAgADiEkEGBECAAkFAlKQFFUCGwwA" + + "CgkQMrO+2keqmnZGIACfRTkdqi6b7fjqkWxx7DysKBedgS8An1TJrhhkeJVd" + + "smkOCYLILgjrBHq4sAIAAw=="); + + byte[] pub8 = Base64.decode( + "mQGiBEEcraYRBADFYj+uFOhHz5SdECvJ3Z03P47gzmWLQ5HH8fPYC9rrv7AgqFFX" + + "aWlJJVMLua9e6xoCiDWJs/n4BbZ/weL/11ELg6XqUnzFhYyz0H2KFsPgQ/b9lWLY" + + "MtcPMFy5jE33hv/ixHgYLFqoNaAIbg0lzYEW/otQ9IhRl16fO1Q/CQZZrQCg/9M2" + + "V2BTmm9RYog86CXJtjawRBcD/RIqU0zulxZ2Zt4javKVxrGIwW3iBU935ebmJEIK" + + "Y5EVkGKBOCvsApZ+RGzpYeR2uMsTnQi8RJgiAnjaoVPCdsVJE7uQ0h8XuJ5n5mJ2" + + "kLCFlF2hj5ViicZzse+crC12CGtgRe8z23ubLRcd6IUGhVutK8/b5knZ22vE14JD" + + "ykKdA/96ObzJQdiuuPsEWN799nUUCaYWPAoLAmiXuICSP4GEnxLbYHWo8zhMrVMT" + + "9Q5x3h8cszUz7Acu2BXjP1m96msUNoxPOZtt88NlaFz1Q/JSbQTsVOMd9b/IRN6S" + + "A/uU0BiKEMHXuT8HUHVPK49oCKhZrGFP3RT8HZxDKLmR/qrgZ7ABh7QhSmlhIFlp" + + "eXUgPHl5amlhQG5vd21lZGlhdGVjaC5jb20+sAMD//+JAF0EEBECAB0FAkEcraYH" + + "CwkIBwMCCgIZAQUbAwAAAAUeAQAAAAAKCRD0/lb4K/9iFJlhAKCRMifQewiX5o8F" + + "U099FG3QnLVUZgCfWpMOsHulGHfNrxdBSkE5Urqh1ymwAWe5Ag0EQRytphAIAPZC" + + "V7cIfwgXcqK61qlC8wXo+VMROU+28W65Szgg2gGnVqMU6Y9AVfPQB8bLQ6mUrfdM" + + "ZIZJ+AyDvWXpF9Sh01D49Vlf3HZSTz09jdvOmeFXklnN/biudE/F/Ha8g8VHMGHO" + + "fMlm/xX5u/2RXscBqtNbno2gpXI61Brwv0YAWCvl9Ij9WE5J280gtJ3kkQc2azNs" + + "OA1FHQ98iLMcfFstjvbzySPAQ/ClWxiNjrtVjLhdONM0/XwXV0OjHRhs3jMhLLUq" + + "/zzhsSlAGBGNfISnCnLWhsQDGcgHKXrKlQzZlp+r0ApQmwJG0wg9ZqRdQZ+cfL2J" + + "SyIZJrqrol7DVekyCzsAAgIH/3K2wKRSzkIpDfZR25+tnQ8brv3TYoDZo3/wN3F/" + + "r6PGjx0150Q8g8EAC0bqm4rXWzOqdSxYxvIPOAGm5P4y+884yS6j3vKcXitT7vj+" + + "ODc2pVwGDLDjrMRrosSK89ycPCK6R/5pD7Rv4l9DWi2fgLvXqJHS2/ujUf2uda9q" + + "i9xNMnBXIietR82Sih4undFUOwh6Mws/o3eed9DIdaqv2Y2Aw43z/rJ6cjSGV3C7" + + "Rkf9x85AajYA3LwpS8d99tgFig2u6V/A16oi6/M51oT0aR/ZAk50qUc4WBk9uRUX" + + "L3Y+P6v6FCBE/06fgVltwcQHO1oKYKhH532tDL+9mW5/dYGwAYeJAEwEGBECAAwF" + + "AkEcraYFGwwAAAAACgkQ9P5W+Cv/YhShrgCg+JW8m5nF3R/oZGuG87bXQBszkjMA" + + "oLhGPncuGKowJXMRVc70/8qwXQJLsAFnmQGiBD2K5rYRBADD6kznWZA9nH/pMlk0" + + "bsG4nI3ELgyI7KpgRSS+Dr17+CCNExxCetT+fRFpiEvUcSxeW4pOe55h0bQWSqLo" + + "MNErXVJEXrm1VPkC08W8D/gZuPIsdtKJu4nowvdoA+WrI473pbeONGjaEDbuIJak" + + "yeKM1VMSGhsImdKtxqhndq2/6QCg/xARUIzPRvKr2TJ52K393895X1kEAMCdjSs+" + + "vABnhaeNNR5+NNkkIOCCjCS8qZRZ4ZnIayvn9ueG3KrhZeBIHoajUHrlTXBVj7XO" + + "wXVfGpW17jCDiqhU8Pu6VwEwX1iFbuUwqBffiRLXKg0zfcN+MyFKToi+VsJi4jiZ" + + "zcwUFMb8jE8tvR/muXti7zKPRPCbNBExoCt4A/0TgkzAosG/W4dUkkbc6XoHrjob" + + "iYuy6Xbs/JYlV0vf2CyuKCZC6UoznO5x2GkvOyVtAgyG4HSh1WybdrutZ8k0ysks" + + "mOthE7n7iczdj9Uwg2h+TfgDUnxcCAwxnOsX5UaBqGdkX1PjCWs+O3ZhUDg6UsZc" + + "7O5a3kstf16lHpf4q7ABAIkAYQQfEQIAIQUCPYrmtgIHABcMgBHRi/xlIgI+Q6LT" + + "kNJ7zKvTd87NHAAKCRDJM3gHb/sRj7bxAJ9f6mdlXQH7gMaYiY5tBe/FRtPr1gCf" + + "UhDJQG0ARvORFWHjwhhBMLxW7j2wAWC0KkRlc21vbmQgS2VlIDxkZXNtb25kLmtl" + + "ZUBub3dtZWRpYXRlY2guY29tPrADAQD9iQBYBBARAgAYBQI9iua2CAsDCQgHAgEK" + + "AhkBBRsDAAAAAAoJEMkzeAdv+xGP7v4An19iqadBCCgDIe2DTpspOMidwQYPAJ4/" + + "5QXbcn4ClhOKTO3ZEZefQvvL27ABYLkCDQQ9iua2EAgA9kJXtwh/CBdyorrWqULz" + + "Bej5UxE5T7bxbrlLOCDaAadWoxTpj0BV89AHxstDqZSt90xkhkn4DIO9ZekX1KHT" + + "UPj1WV/cdlJPPT2N286Z4VeSWc39uK50T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq" + + "01uejaClcjrUGvC/RgBYK+X0iP1YTknbzSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O" + + "9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdXQ6MdGGzeMyEstSr/POGxKUAYEY18hKcK" + + "ctaGxAMZyAcpesqVDNmWn6vQClCbAkbTCD1mpF1Bn5x8vYlLIhkmuquiXsNV6TIL" + + "OwACAgf/SO+bbg+owbFKVN5HgOjOElQZVnCsegwCLqTeQzPPzsWmkGX2qZJPDIRN" + + "RZfJzti6+oLJwaRA/3krjviUty4VKhZ3lKg8fd9U0jEdnw+ePA7yJ6gZmBHL15U5" + + "OKH4Zo+OVgDhO0c+oetFpend+eKcvtoUcRoQoi8VqzYUNG0b/nmZGDlxQe1/ZNbP" + + "HpNf1BAtJXivCEKMD6PVzsLPg2L4tFIvD9faeeuKYQ4jcWtTkBLuIaZba3i3a4wG" + + "xTN20j9HpISVuLW/EfZAK1ef4DNjLmHEU9dMzDqfi+hPmMbGlFqcKr+VjcYIDuje" + + "o+92xm/EWAmlti88r2hZ3MySamHDrLABAIkATAQYEQIADAUCPYrmtgUbDAAAAAAK" + + "CRDJM3gHb/sRjzVTAKDVS+OJLMeS9VLAmT8atVCB42MwIQCgoh1j3ccWnhc/h6B7" + + "9Uqz3fUvGoewAWA="); + + byte[] sec8 = Base64.decode( + "lQHpBEEcraYRBADFYj+uFOhHz5SdECvJ3Z03P47gzmWLQ5HH8fPYC9rrv7AgqFFX" + + "aWlJJVMLua9e6xoCiDWJs/n4BbZ/weL/11ELg6XqUnzFhYyz0H2KFsPgQ/b9lWLY" + + "MtcPMFy5jE33hv/ixHgYLFqoNaAIbg0lzYEW/otQ9IhRl16fO1Q/CQZZrQCg/9M2" + + "V2BTmm9RYog86CXJtjawRBcD/RIqU0zulxZ2Zt4javKVxrGIwW3iBU935ebmJEIK" + + "Y5EVkGKBOCvsApZ+RGzpYeR2uMsTnQi8RJgiAnjaoVPCdsVJE7uQ0h8XuJ5n5mJ2" + + "kLCFlF2hj5ViicZzse+crC12CGtgRe8z23ubLRcd6IUGhVutK8/b5knZ22vE14JD" + + "ykKdA/96ObzJQdiuuPsEWN799nUUCaYWPAoLAmiXuICSP4GEnxLbYHWo8zhMrVMT" + + "9Q5x3h8cszUz7Acu2BXjP1m96msUNoxPOZtt88NlaFz1Q/JSbQTsVOMd9b/IRN6S" + + "A/uU0BiKEMHXuT8HUHVPK49oCKhZrGFP3RT8HZxDKLmR/qrgZ/4JAwLXyWhb4pf4" + + "nmCmD0lDwoYvatLiR7UQVM2MamxClIiT0lCPN9C2AYIFgRWAJNS215Tjx7P/dh7e" + + "8sYfh5XEHErT3dMbsAGHtCFKaWEgWWl5dSA8eXlqaWFAbm93bWVkaWF0ZWNoLmNv" + + "bT6wAwP//4kAXQQQEQIAHQUCQRytpgcLCQgHAwIKAhkBBRsDAAAABR4BAAAAAAoJ" + + "EPT+Vvgr/2IUmWEAoJEyJ9B7CJfmjwVTT30UbdCctVRmAJ9akw6we6UYd82vF0FK" + + "QTlSuqHXKbABZ50CawRBHK2mEAgA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlL" + + "OCDaAadWoxTpj0BV89AHxstDqZSt90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N" + + "286Z4VeSWc39uK50T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq01uejaClcjrUGvC/" + + "RgBYK+X0iP1YTknbzSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2O" + + "u1WMuF040zT9fBdXQ6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqV" + + "DNmWn6vQClCbAkbTCD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwACAgf/crbApFLO" + + "QikN9lHbn62dDxuu/dNigNmjf/A3cX+vo8aPHTXnRDyDwQALRuqbitdbM6p1LFjG" + + "8g84Aabk/jL7zzjJLqPe8pxeK1Pu+P44NzalXAYMsOOsxGuixIrz3Jw8IrpH/mkP" + + "tG/iX0NaLZ+Au9eokdLb+6NR/a51r2qL3E0ycFciJ61HzZKKHi6d0VQ7CHozCz+j" + + "d5530Mh1qq/ZjYDDjfP+snpyNIZXcLtGR/3HzkBqNgDcvClLx3322AWKDa7pX8DX" + + "qiLr8znWhPRpH9kCTnSpRzhYGT25FRcvdj4/q/oUIET/Tp+BWW3BxAc7WgpgqEfn" + + "fa0Mv72Zbn91gf4JAwITijME9IlFBGAwH6YmBtWIlnDiRbsq/Pxozuhbnes831il" + + "KmdpUKXkiIfHY0MqrEWl3Dfn6PMJGTnhgqXMrDxx3uHrq0Jl2swRnAWIIO8gID7j" + + "uPetUqEviPiwAYeJAEwEGBECAAwFAkEcraYFGwwAAAAACgkQ9P5W+Cv/YhShrgCg" + + "+JW8m5nF3R/oZGuG87bXQBszkjMAoLhGPncuGKowJXMRVc70/8qwXQJLsAFn"); + + char[] sec8pass = "qwertyui".toCharArray(); + + byte[] sec9 = Base64.decode( + "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" + + "6neEEX/i1Q=="); + + public char[] sec9pass = "foo".toCharArray(); + + // version 4 keys with expiry dates + byte[] pub10 = Base64.decode( + "mQGiBEKqia0RBACc3hkufmscRSC4UvPZqMDsHm4+d/GXIr+3iNMSSEySJu8yk+k0" + + "Xs11C/K+n+v1rnn2jGGknv+1lDY6w75TIcTE6o6HGKeIDxsAm8P3MhoGU1GNPamA" + + "eTDeNybtrN/g6C65fCY9uI11hsUboYgQZ8ND22PB0VtvdOgq9D85qNUzxwCg1BbJ" + + "ycAKd4VqEvQ2Zglp3dCSrFMD/Ambq1kZqYa69sp3b9BPKuAgUgUPoytOArEej3Bk" + + "easAgAxNhWJy4GxigES3vk50rVi7w8XBuqbD1mQCzldF0HX0/A7PxLBv6od5uqqF" + + "HFxIyxg/KBZLd9ZOrsSaoUWH58jZq98X/sFtJtRi5VuJagMxCIJD4mLgtMv7Unlb" + + "/GrsA/9DEnObA/fNTgK70T+ZmPIS5tSt+bio30Aw4YGpPCGqpnm1u73b5kqX3U3B" + + "P+vGDvFuqZYpqQA8byAueH0MbaDHI4CFugvShXvgysJxN7ov7/8qsZZUMfK1t2Nr" + + "SAsPuKRbcY4gNKXIElKeXbyaET7vX7uAEKuxEwdYGFp/lNTkHLQgdGVzdCBrZXkg" + + "KHRlc3QpIDx0ZXN0QHRlc3QudGVzdD6IZAQTEQIAJAUCQqqJrQIbAwUJACTqAAYL" + + "CQgHAwIDFQIDAxYCAQIeAQIXgAAKCRDjDROQZRqIzDzLAJ42AeCRIBBjv8r8qw9y" + + "laNj2GZ1sACgiWYHVXMA6B1H9I1kS3YsCd3Oq7qwAgAAuM0EQqqJrhADAKWkix8l" + + "pJN7MMTXob4xFF1TvGll0UD1bDGOMMbes6aeXSbT9QXee/fH3GnijLY7wB+qTPv9" + + "ohubrSpnv3yen3CEBW6Q2YK+NlCskma42Py8YMV2idmYjtJi1ckvHFWt5wADBQL/" + + "fkB5Q5xSGgspMaTZmtmX3zG7ZDeZ0avP8e8mRL8UszCTpqs6vMZrXwyQLZPbtMYv" + + "PQpuRGEeKj0ysimwYRA5rrLQjnRER3nyuuEUUgc4j+aeRxPf9WVsJ/a1FCHtaAP1" + + "iE8EGBECAA8FAkKqia4CGwwFCQAk6gAACgkQ4w0TkGUaiMzdqgCfd66H7DL7kFGd" + + "IoS+NIp8JO+noxAAn25si4QAF7og8+4T5YQUuhIhx/NesAIAAA=="); + + byte[] sec10 = Base64.decode( + "lQHhBEKqia0RBACc3hkufmscRSC4UvPZqMDsHm4+d/GXIr+3iNMSSEySJu8yk+k0" + + "Xs11C/K+n+v1rnn2jGGknv+1lDY6w75TIcTE6o6HGKeIDxsAm8P3MhoGU1GNPamA" + + "eTDeNybtrN/g6C65fCY9uI11hsUboYgQZ8ND22PB0VtvdOgq9D85qNUzxwCg1BbJ" + + "ycAKd4VqEvQ2Zglp3dCSrFMD/Ambq1kZqYa69sp3b9BPKuAgUgUPoytOArEej3Bk" + + "easAgAxNhWJy4GxigES3vk50rVi7w8XBuqbD1mQCzldF0HX0/A7PxLBv6od5uqqF" + + "HFxIyxg/KBZLd9ZOrsSaoUWH58jZq98X/sFtJtRi5VuJagMxCIJD4mLgtMv7Unlb" + + "/GrsA/9DEnObA/fNTgK70T+ZmPIS5tSt+bio30Aw4YGpPCGqpnm1u73b5kqX3U3B" + + "P+vGDvFuqZYpqQA8byAueH0MbaDHI4CFugvShXvgysJxN7ov7/8qsZZUMfK1t2Nr" + + "SAsPuKRbcY4gNKXIElKeXbyaET7vX7uAEKuxEwdYGFp/lNTkHP4DAwLssmOjVC+d" + + "mWB783Lpzjb9evKzsxisTdx8/jHpUSS+r//6/Guyx3aA/zUw5bbftItW57mhuNNb" + + "JTu7WrQgdGVzdCBrZXkgKHRlc3QpIDx0ZXN0QHRlc3QudGVzdD6IZAQTEQIAJAUC" + + "QqqJrQIbAwUJACTqAAYLCQgHAwIDFQIDAxYCAQIeAQIXgAAKCRDjDROQZRqIzDzL" + + "AJ0cYPwKeoSReY14LqJtAjnkX7URHACgsRZWfpbalrSyDnq3TtZeGPUqGX+wAgAA" + + "nQEUBEKqia4QAwClpIsfJaSTezDE16G+MRRdU7xpZdFA9WwxjjDG3rOmnl0m0/UF" + + "3nv3x9xp4oy2O8Afqkz7/aIbm60qZ798np9whAVukNmCvjZQrJJmuNj8vGDFdonZ" + + "mI7SYtXJLxxVrecAAwUC/35AeUOcUhoLKTGk2ZrZl98xu2Q3mdGrz/HvJkS/FLMw" + + "k6arOrzGa18MkC2T27TGLz0KbkRhHio9MrIpsGEQOa6y0I50REd58rrhFFIHOI/m" + + "nkcT3/VlbCf2tRQh7WgD9f4DAwLssmOjVC+dmWDXVLRopzxbBGOvodp/LZoSDb56" + + "gNJjDMJ1aXqWW9qTAg1CFjBq73J3oFpVzInXZ8+Q8inxv7bnWiHbiE8EGBECAA8F" + + "AkKqia4CGwwFCQAk6gAACgkQ4w0TkGUaiMzdqgCgl2jw5hfk/JsyjulQqe1Nps1q" + + "Lx0AoMdnFMZmTMLHn8scUW2j9XO312tmsAIAAA=="); + + public char[] sec10pass = "test".toCharArray(); + + public byte[] subKeyBindingKey = Base64.decode( + "mQGiBDWagYwRBAD7UcH4TAIp7tmUoHBNxVxCVz2ZrNo79M6fV63riOiH2uDxfIpr" + + "IrL0cM4ehEKoqlhngjDhX60eJrOw1nC5BpYZRnDnyDYT4wTWRguxObzGq9pqA1dM" + + "oPTJhkFZVIBgFY99/ULRqaUYIhFGgBtnwS70J8/L/PGVc3DmWRLMkTDjSQCg/5Nh" + + "MCjMK++MdYMcMl/ziaKRT6EEAOtw6PnU9afdohbpx9CK4UvCCEagfbnUtkSCQKSk" + + "6cUp6VsqyzY0pai/BwJ3h4apFMMMpVrtBAtchVgqo4xTr0Sve2j0k+ase6FSImiB" + + "g+AR7hvTUTcBjwtIExBc8TuCTqmn4GG8F7UMdl5Z0AZYj/FfAQYaRVZYP/pRVFNx" + + "Lw65BAC/Fi3qgiGCJFvXnHIckTfcAmZnKSEXWY9NJ4YQb4+/nH7Vsw0wR/ZObUHR" + + "bWgTc9Vw1uZIMe0XVj6Yk1dhGRehUnrm3mE7UJxu7pgkBCbFECFSlSSqP4MEJwZV" + + "09YP/msu50kjoxyoTpt+16uX/8B4at24GF1aTHBxwDLd8X0QWrQsTWVycmlsbCBM" + + "eW5jaCBDTEVBUiBzeXN0ZW0gREggPGNsZWFyQG1sLmNvbT6JAEsEEBECAAsFAjWa" + + "gYwECwMBAgAKCRDyAGjiP47/XanfAKCs6BPURWVQlGh635VgL+pdkUVNUwCdFcNa" + + "1isw+eAcopXPMj6ACOapepu5Ag0ENZqBlBAIAPZCV7cIfwgXcqK61qlC8wXo+VMR" + + "OU+28W65Szgg2gGnVqMU6Y9AVfPQB8bLQ6mUrfdMZIZJ+AyDvWXpF9Sh01D49Vlf" + + "3HZSTz09jdvOmeFXklnN/biudE/F/Ha8g8VHMGHOfMlm/xX5u/2RXscBqtNbno2g" + + "pXI61Brwv0YAWCvl9Ij9WE5J280gtJ3kkQc2azNsOA1FHQ98iLMcfFstjvbzySPA" + + "Q/ClWxiNjrtVjLhdONM0/XwXV0OjHRhs3jMhLLUq/zzhsSlAGBGNfISnCnLWhsQD" + + "GcgHKXrKlQzZlp+r0ApQmwJG0wg9ZqRdQZ+cfL2JSyIZJrqrol7DVekyCzsAAgIH" + + "/RYtVo+HROZ6jrNjrATEwQm1fUQrk6n5+2dniN881lF0CNkB4NkHw1Xxz4Ejnu/0" + + "iLg8fkOAsmanOsKpOkRtqUnVpsVL5mLJpFEyCY5jbcfj+KY9/25bs0ga7kLHNZia" + + "zbCxJdF+W179z3nudQxRaXG/0XISIH7ziZbSVni69sKc1osk1+OoOMbSuZ86z535" + + "Pln4fXclkFE927HxfbWoO+60hkOLKh7x+8fC82b3x9vCETujEaxrscO2xS7/MYXP" + + "8t1ffriTDmhuIuQS2q4fLgeWdqrODrMhrD8Dq7e558gzp30ZCqpiS7EmKGczL7B8" + + "gXxbBCVSTxYMJheXt2xMXsuJAD8DBRg1moGU8gBo4j+O/10RAgWdAKCPhaFIXuC8" + + "/cdiNMxTDw9ug3De5QCfYXmDzRSFUu/nrCi8yz/l09wsnxo="); + + public byte[] subKeyBindingCheckSum = Base64.decode("3HU+"); + + // + // PGP8 with SHA1 checksum. + // + public byte[] rewrapKey = Base64.decode( + "lQOWBEUPOQgBCADdjPTtl8oOwqJFA5WU8p7oDK5KRWfmXeXUZr+ZJipemY5RSvAM" + + "rxqsM47LKYbmXOJznXCQ8+PPa+VxXAsI1CXFHIFqrXSwvB/DUmb4Ec9EuvNd18Zl" + + "hJAybzmV2KMkaUp9oG/DUvxZJqkpUddNfwqZu0KKKZWF5gwW5Oy05VCpaJxQVXFS" + + "whdbRfwEENJiNx4RB3OlWhIjY2p+TgZfgQjiGB9i15R+37sV7TqzBUZF4WWcnIRQ" + + "DnpUfxHgxQ0wO/h/aooyRHSpIx5i4oNpMYq9FNIyakEx/Bomdbs5hW9dFxhrE8Es" + + "UViAYITgTsyROxmgGatGG09dcmVDJVYF4i7JAAYpAAf/VnVyUDs8HrxYTOIt4rYY" + + "jIHToBsV0IiLpA8fEA7k078L1MwSwERVVe6oHVTjeR4A9OxE52Vroh2eOLnF3ftf" + + "6QThVVZr+gr5qeG3yvQ36N7PXNEVOlkyBzGmFQNe4oCA+NR2iqnAIspnekVmwJV6" + + "xVvPCjWw/A7ZArDARpfthspwNcJAp4SWfoa2eKzvUTznTyqFu2PSS5fwQZUgOB0P" + + "Y2FNaKeqV8vEZu4SUWwLOqXBQIZXiaLvdKNgwFvUe3kSHdCNsrVzW7SYxFwaEog2" + + "o6YLKPVPqjlGX1cMOponGp+7n9nDYkQjtEsGSSMQkQRDAcBdSVJmLO07kFOQSOhL" + + "WQQA49BcgTZyhyH6TnDBMBHsGCYj43FnBigypGT9FrQHoWybfX47yZaZFROAaaMa" + + "U6man50YcYZPwzDzXHrK2MoGALY+DzB3mGeXVB45D/KYtlMHPLgntV9T5b14Scbc" + + "w1ES2OUtsSIUs0zelkoXqjLuKnSIYK3mMb67Au7AEp6LXM8EAPj2NypvC86VEnn+" + + "FH0QHvUwBpmDw0EZe25xQs0brvAG00uIbiZnTH66qsIfRhXV/gbKK9J5DTGIqQ15" + + "DuPpz7lcxg/n2+SmjQLNfXCnG8hmtBjhTe+udXAUrmIcfafXyu68SAtebgm1ga56" + + "zUfqsgN3FFuMUffLl3myjyGsg5DnA/oCFWL4WCNClOgL6A5VkNIUait8QtSdCACT" + + "Y7jdSOguSNXfln0QT5lTv+q1AjU7zjRl/LsFNmIJ5g2qdDyK937FOXM44FEEjZty" + + "/4P2dzYpThUI4QUohIj8Qi9f2pZQueC5ztH6rpqANv9geZKcciAeAbZ8Md0K2TEU" + + "RD3Lh+RSBzILtBtUZXN0IEtleSA8dGVzdEBleGFtcGxlLmNvbT6JATYEEwECACAF" + + "AkUPOQgCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRDYpknHeQaskD9NB/9W" + + "EbFuLaqZAl3yjLU5+vb75BdvcfL1lUs44LZVwobNp3/0XbZdY76xVPNZURtU4u3L" + + "sJfGlaF+EqZDE0Mqc+vs5SIb0OnCzNJ00KaUFraUtkByRV32T5ECHK0gMBjCs5RT" + + "I0vVv+Qmzl4+X1Y2bJ2mlpBejHIrOzrBD5NTJimTAzyfnNfipmbqL8p/cxXKKzS+" + + "OM++ZFNACj6lRM1W9GioXnivBRC88gFSQ4/GXc8yjcrMlKA27JxV+SZ9kRWwKH2f" + + "6o6mojUQxnHr+ZFKUpo6ocvTgBDlC57d8IpwJeZ2TvqD6EdA8rZ0YriVjxGMDrX1" + + "8esfw+iLchfEwXtBIRwS"); + + char[] rewrapPass = "voltage123".toCharArray(); + + byte[] pubWithX509 = Base64.decode( + "mQENBERabjABCACtmfyo6Nph9MQjv4nmCWjZrRYnhXbivomAdIwYkLZUj1bjqE+j"+ + "uaLzjZV8xSI59odZvrmOiqlzOc4txitQ1OX7nRgbOJ7qku0dvwjtIn46+HQ+cAFn"+ + "2mTi81RyXEpO2uiZXfsNTxUtMi+ZuFLufiMc2kdk27GZYWEuasdAPOaPJnA+wW6i"+ + "ZHlt0NfXIGNz864gRwhD07fmBIr1dMFfATWxCbgMd/rH7Z/j4rvceHD2n9yrhPze"+ + "YN7W4Nuhsr2w/Ft5Cm9xO7vXT/cpto45uxn8f7jERep6bnUwNOhH8G+6xLQgTLD0"+ + "qFBGVSIneK3lobs6+xn6VaGN8W0tH3UOaxA1ABEBAAG0D0NOPXFhLWRlZXBzaWdo"+ + "dIkFDgQQZAIFAQUCRFpuMAUDCWdU0gMF/3gCGwPELGQBAQQwggTkMIIDzKADAgEC"+ + "AhBVUMV/M6rIiE+IzmnPheQWMA0GCSqGSIb3DQEBBQUAMG4xEzARBgoJkiaJk/Is"+ + "ZAEZFgNjb20xEjAQBgoJkiaJk/IsZAEZFgJxYTEVMBMGCgmSJomT8ixkARkWBXRt"+ + "czAxMRUwEwYKCZImiZPyLGQBGRYFV2ViZmUxFTATBgNVBAMTDHFhLWRlZXBzaWdo"+ + "dDAeFw0wNjA1MDQyMTEyMTZaFw0xMTA1MDQyMTIwMDJaMG4xEzARBgoJkiaJk/Is"+ + "ZAEZFgNjb20xEjAQBgoJkiaJk/IsZAEZFgJxYTEVMBMGCgmSJomT8ixkARkWBXRt"+ + "czAxMRUwEwYKCZImiZPyLGQBGRYFV2ViZmUxFTATBgNVBAMTDHFhLWRlZXBzaWdo"+ + "dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK2Z/Kjo2mH0xCO/ieYJ"+ + "aNmtFieFduK+iYB0jBiQtlSPVuOoT6O5ovONlXzFIjn2h1m+uY6KqXM5zi3GK1DU"+ + "5fudGBs4nuqS7R2/CO0ifjr4dD5wAWfaZOLzVHJcSk7a6Jld+w1PFS0yL5m4Uu5+"+ + "IxzaR2TbsZlhYS5qx0A85o8mcD7BbqJkeW3Q19cgY3PzriBHCEPTt+YEivV0wV8B"+ + "NbEJuAx3+sftn+Piu9x4cPaf3KuE/N5g3tbg26GyvbD8W3kKb3E7u9dP9ym2jjm7"+ + "Gfx/uMRF6npudTA06Efwb7rEtCBMsPSoUEZVIid4reWhuzr7GfpVoY3xbS0fdQ5r"+ + "EDUCAwEAAaOCAXwwggF4MAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0G"+ + "A1UdDgQWBBSmFTRv5y65DHtTYae48zl0ExNWZzCCASUGA1UdHwSCARwwggEYMIIB"+ + "FKCCARCgggEMhoHFbGRhcDovLy9DTj1xYS1kZWVwc2lnaHQsQ049cWEtd3VtYW4x"+ + "LWRjLENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNl"+ + "cyxDTj1Db25maWd1cmF0aW9uLERDPVdlYmZlLERDPXRtczAxLERDPXFhLERDPWNv"+ + "bT9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JM"+ + "RGlzdHJpYnV0aW9uUG9pbnSGQmh0dHA6Ly9xYS13dW1hbjEtZGMud2ViZmUudG1z"+ + "MDEucWEuY29tL0NlcnRFbnJvbGwvcWEtZGVlcHNpZ2h0LmNybDAQBgkrBgEEAYI3"+ + "FQEEAwIBADANBgkqhkiG9w0BAQUFAAOCAQEAfuZCW3XlB7Eok35zQbvYt9rhAndT"+ + "DNw3wPNI4ZzD1nXoYWnwhNNvWRpsOt4ExOSNdaHErfgDXAMyyg66Sro0TkAx8eAj"+ + "fPQsyRAh0nm0glzFmJN6TdOZbj7hqGZjc4opQ6nZo8h/ULnaEwMIUW4gcSkZt0ww"+ + "CuErl5NUrN3DpkREeCG/fVvQZ8ays3ibQ5ZCZnYBkLYq/i0r3NLW34WfYhjDY48J"+ + "oQWtvFSAxvRfz2NGmqnrCHPQZxqlfdta97kDa4VQ0zSeBaC70gZkLmD1GJMxWoXW"+ + "6tmEcgPY5SghInUf+L2u52V55MjyAFzVp7kTK2KY+p7qw35vzckrWkwu8AAAAAAA"+ + "AQE="); + + private static byte[] secWithPersonalCertificate = Base64.decode( + "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" + + "cGdwbWltZQULBwgJAgIZAQUbAQAAAAUeAQAAAAIVAgAKCRDlTa3BE84gWVKW" + + "BACcoCFKvph9r9QiHT1Z3N4wZH36Uxqu/059EFALnBkEdVudX/p6S9mynGRk" + + "EfhmWFC1O6dMpnt+ZBEed/4XyFWVSLPwirML+6dxfXogdUsdFF1NCRHc3QGc" + + "txnNUT/zcZ9IRIQjUhp6RkIvJPHcyfTXKSbLviI+PxzHU2Padq8pV7ABZ7kA" + + "jQRIfg8tAQQAutJR/aRnfZYwlVv+KlUDYjG8YQUfHpTxpnmVu7W6N0tNg/Xr" + + "5dg50wq3I4HOamRxUwHpdPkXyNF1szpDSRZmlM+VmiIvJDBnyH5YVlxT6+zO" + + "8LUJ2VTbfPxoLFp539SQ0oJOm7IGMAGO7c0n/QV0N3hKUfWgCyJ+sENDa0Ft" + + "JycAEQEAAbABj4kEzQQYAQIENwUCSMYtnAUJAeEzgMLFFAAAAAAAFwNleDUw" + + "OWNlcnRpZmljYXRlQHBncC5jb20wggNhMIICyqADAgECAgkA1AoCoRKJCgsw" + + "DQYJKoZIhvcNAQEFBQAwgakxCzAJBgNVBAYTAkNaMRcwFQYDVQQIEw5DemVj" + + "aCBSZXB1YmxpYzESMBAGA1UEChQJQSYmTCBzb2Z0MSAwHgYDVQQLExdJbnRl" + + "cm5hbCBEZXZlbG9wbWVudCBDQTEqMCgGA1UEAxQhQSYmTCBzb2Z0IEludGVy" + + "bmFsIERldmVsb3BtZW50IENBMR8wHQYJKoZIhvcNAQkBFhBrYWRsZWNAYWxz" + + "b2Z0LmN6MB4XDTA4MDcxNjE1MDkzM1oXDTA5MDcxNjE1MDkzM1owaTELMAkG" + + "A1UEBhMCQ1oxFzAVBgNVBAgTDkN6ZWNoIFJlcHVibGljMRIwEAYDVQQKFAlB" + + "JiZMIHNvZnQxFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5IeW5l" + + "ay1JbnRyYW5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAutJR/aRn" + + "fZYwlVv+KlUDYjG8YQUfHpTxpnmVu7W6N0tNg/Xr5dg50wq3I4HOamRxUwHp" + + "dPkXyNF1szpDSRZmlM+VmiIvJDBnyH5YVlxT6+zO8LUJ2VTbfPxoLFp539SQ" + + "0oJOm7IGMAGO7c0n/QV0N3hKUfWgCyJ+sENDa0FtJycCAwEAAaOBzzCBzDAJ" + + "BgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBD" + + "ZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUNaw7A6r10PtYZzAvr9CrSKeRYJgwHwYD" + + "VR0jBBgwFoAUmqSRM8rN3+T1+tkGiqef8S5suYgwGgYDVR0RBBMwEYEPaHlu" + + "ZWtAYWxzb2Z0LmN6MCgGA1UdHwQhMB8wHaAboBmGF2h0dHA6Ly9wZXRyazIv" + + "Y2EvY2EuY3JsMAsGA1UdDwQEAwIF4DANBgkqhkiG9w0BAQUFAAOBgQCUdOWd" + + "7mBLWj1/GSiYgfwgdTrgk/VZOJvMKBiiFyy1iFEzldz6Xx+mAexnFJKfZXZb" + + "EMEGWHfWPmgJzAtuTT0Jz6tUwDmeLH3MP4m8uOZtmyUJ2aq41kciV3rGxF0G" + + "BVlZ/bWTaOzHdm6cjylt6xxLt6MJzpPBA/9ZfybSBh1DaAUbDgAAAJ0gBBkB" + + "AgAGBQJIxi2bAAoJEAdYkEWLb2R2fJED/RK+JErZ98uGo3Z81cHkdP3rk8is" + + "DUL/PR3odBPFH2SIA5wrzklteLK/ZXmBUzcvxqHEgI1F7goXbsBgeTuGgZdx" + + "pINErxkNpcMl9FTldWKGiapKrhkZ+G8knDizF/Y7Lg6uGd2nKVxzutLXdHJZ" + + "pU89Q5nzq6aJFAZo5TBIcchQAAoJEOVNrcETziBZXvQD/1mvFqBfWqwXxoj3" + + "8fHUuFrE2pcp32y3ciO2i+uNVEkNDoaVVNw5eHQaXXWpllI/Pe6LnBl4vkyc" + + "n3pjONa4PKrePkEsCUhRbIySqXIHuNwZumDOlKzZHDpCUw72LaC6S6zwuoEf" + + "ucOcxTeGIUViANWXyTIKkHfo7HfigixJIL8nsAFn"); + + private static final byte[] umlautKeySig = Base64.decode( + "mI0ETdvOgQEEALoI2a39TRk1HReEB6DP9Bu3ShZUce+/Oeg9RIL9aUFuCsNdhu02" + + "REEHjO29Jz8daPgrnJDfFepNLD6iKKru2m9P30qnhsHMIAshO2Ozfh6wKwuHRqR3" + + "L4gBDu7cCB6SLwPoD8AYG0yQSM+Do10Td87RlStxCgxpMK6R3TsRkxcFABEBAAG0" + + "OlVNTEFVVFNUQVJUOsOEw6TDlsO2w5zDvMOfOlVNTEFURU5ERSA8YXNkbGFrc2Rs" + + "QGFrc2RqLmNvbT6IuAQTAQIAIgUCTdvOgQIbAwYLCQgHAwIGFQgCCQoLBBYCAwEC" + + "HgECF4AACgkQP8kDwm8AOFiArAP/ZXrlZJB1jFEjyBb04ckpE6F/aJuSYIXf0Yx5" + + "T2eS+lA69vYuqKRC1qNROBrAn/WGNOQBFNEgGoy3F3gV5NgpIphnyIEZdZWGY2rv" + + "yjunKWlioZjWc/xbSbvpvJ3Q8RyfDXBOkDEB6uF1ksimw2eJSOUTkF9AQfS5f4rT" + + "5gs013G4jQRN286BAQQApVbjd8UhsQLB4TpeKn9+dDXAfikGgxDOb19XisjRiWxA" + + "+bKFxu5tRt6fxXl6BGSGT7DhoVbNkcJGVQFYcbR31UGKCVYcWSL3yfz+PiVuf1UB" + + "Rp44cXxxqxrLqKp1rk3dGvV4Ayy8lkk3ncDGPez6lIKvj3832yVtAzUOX1QOg9EA" + + "EQEAAYifBBgBAgAJBQJN286BAhsMAAoJED/JA8JvADhYQ80D/R3TX0FBMHs/xqEh" + + "tiS86XP/8pW6eMm2eaAYINxoDY3jmDMv2HFQ+YgrYXgqGr6eVGqDMNPj4W8VBoOt" + + "iYW7+SWY76AAl+gmWIMm2jbN8bZXFk4jmIxpycHCrtoXX8rUk/0+se8NvbmAdMGK" + + "POOoD7oxdRmJSU5hSspOCHrCwCa3"); + + + // Key from http://www.angelfire.com/pr/pgpf/pgpoddities.html + private static final char[] v3KeyPass = "test@key.test".toCharArray(); + + private static final byte[] pubv3 = Base64.decode( + "mQENAzroPPgAAAEIANnTx/gHfag7qRMG6cVUnYZJjLcsdF6JSaVs+PUDCZ8l2+Z2" + + "V9tgxByp26bymIlq5qFFeoA5vCiKc8qzYiEVLJVVIIDjw/id2gq/TgmxoLAwiDQM" + + "TUKdCFa6pmR/uaxyrnJxfUA7+Qh0R0OjoCxNlrmyO3eiKstsJGqSUFIQq7GhcHc4" + + "nbV59zHhEWnH7DX7sDa9CgF11WxM3sjWp15iOoP1nixhmchDtQ7foUxLsCF36G/4" + + "ijcbN2NjiCDYMFburN8fXgrQzYHAIIiVFE0J+fbXNfPRmnbhQdaC8rIdiQ3tExBb" + + "N0qWhGPT9M4JOZd1yPdFMb9gbntd8VZkiPd6/3sABRG0FHRlc3QgPHRlc3RAa2V5" + + "LnRlc3Q+iQEVAwUQOug8+PFWZIj3ev97AQH7NQgAo3sH+KcsPtAbyp5U02J9h3Ro" + + "aiKpAYxg3rfUVo/RH6hmCWT/AlPHLPZZC/tKiPkuIm2V3Xqyum530N0sBYxNzgNp" + + "us8mK9QurYj2omKzf1ltN+uNHR8vjB8s7jEd/CDCARu81PqNoVq2b9JRFGpGbAde" + + "7kQ/a0r2/IsJ8fz0iSpCH0geoHt3sBk9MyEem4uG0e2NzlH2wBz4H8l8BNHRHBq0" + + "6tGH4h11ZhH3FiNzJWibT2AvzLCqar2qK+6pohKSvIp8zEP7Y/iQzCvkuOfHsUOH" + + "4Utgg85k09hRDZ3pRRL/4R+Z+/1uXb+n6yKbOmpmi7U7wc9IwZxtTlGXsNIf+Q==" + ); + + private static final byte[] privv3 = Base64.decode( + "lQOgAzroPPgAAAEIANnTx/gHfag7qRMG6cVUnYZJjLcsdF6JSaVs+PUDCZ8l2+Z2" + + "V9tgxByp26bymIlq5qFFeoA5vCiKc8qzYiEVLJVVIIDjw/id2gq/TgmxoLAwiDQM" + + "TUKdCFa6pmR/uaxyrnJxfUA7+Qh0R0OjoCxNlrmyO3eiKstsJGqSUFIQq7GhcHc4" + + "nbV59zHhEWnH7DX7sDa9CgF11WxM3sjWp15iOoP1nixhmchDtQ7foUxLsCF36G/4" + + "ijcbN2NjiCDYMFburN8fXgrQzYHAIIiVFE0J+fbXNfPRmnbhQdaC8rIdiQ3tExBb" + + "N0qWhGPT9M4JOZd1yPdFMb9gbntd8VZkiPd6/3sABREDXB5zk3GNdSkH/+/447Kq" + + "hR9uM+UnZz7wDkzmt+7xbNg9F2pr/tghVCM7D0PO1YjH4DBpU1ZRO+v1t/eBB/Jd" + + "3lJYdlWYHOefJkBi44gNAafZ8ysPOJk6OGOjas/sr+JRFiX9Mgzrs2IDiejmuA98" + + "DLuSuNtzFKbE2/DDdOBEizYUjqPLlCdn5sVEt+0WKWJiAv7YonCGguWS3RKfTaYk" + + "9IE9SbI+qph9JsuyTD22GLv+gTMvwCkC1DVaHIVgzURpdnlyYyz4DBh3pAgg0nh6" + + "gpUTsjnUmrvdh+r8qj3oXH7WBMhs6qKYvU1Go5iV3S1Cu4H/Z/+s6XUFgQShevVe" + + "VCy0QtmWSFeySekEACHLJIdBDa8K4dcM2wvccz587D4PtKvMG5j71raOcgVY+r1k" + + "e6au/fa0ACqLNvn6+vFHG+Rurn8RSKV31YmTpx7J5ixTOsB+wVcwTYbrw8uNlBWc" + + "+IkqPwHrtdK95GIYQykfPW95PRudsOBdxwQW4Ax/WCst3fbjo0SZww0Os+3WBADJ" + + "/Nv0mjikXRmqJIzfuI2yxxX4Wm6vqXJkPF7LGtSMB3VEJ3qPsysoai5TYboxA8C1" + + "4rQjIoQjA+87gxZ44PUVxrxBonITCLXJ3GsvDQ2PNhS6WQ9Cf89vtYW1vLW65Nex" + + "+7AuVRepKhx6Heqdf7S03m6UYliIglrEzgEWM1XrOwP/gLMsme4h0LjLgKfd0LBk" + + "qSMdu21VSl60TMTjxav149AdutzuCVa/yPBM/zLQdlvQoGYg2IbN4+7gDHKURcSx" + + "DgOAzCcEZxdMvRk2kaOI5RRf5gV9e+ErvEMzJ/xT8xWsi+aLOhaDMbwq2LLiK2L+" + + "tXV/Z3H/Ot4u3E7H+6fHPElFYbQUdGVzdCA8dGVzdEBrZXkudGVzdD4=" + ); + + private static final byte[] problemUserID = Base64.decode( + "mQGiBDfzC2IRBADjnqYxAM1LPqFZCpF9ULb4G7L88E/p4sNo4k1LkzGtNOiroEHcacEAcTeP" + + "ljhgTA06l9jpnwx/dE0MEAiEtYexvkBv3LR2qXvuF67TKKlvanB32g0AmxNijHDdN2d+79ZA" + + "heZ4rY702W6DZh6FuKMAsTBfAFW5jLCWyJ4FwsLILwCg/3mjYePND5l0UcxaV0RKRBGnhqsE" + + "AIb9PJyWxSa8uzYQ+/APMg16Rrbti21zEQorFoc6yrC2hWbS7ro5yEVJxJa14s7VKlR+IAhg" + + "vR2+Q6jF6uvE1NZXzX6bvGaK3IpWMZdYcUY63EsHnutV+xON6Xd9C06xjAssvRQnxSuLXCg4" + + "md1Cr2kiKWaBExzxniKeql5lrqXKBACPcHbwZ8Efgt1TLG4yUf8nIQZwDeAhUPqJVWXurpWx" + + "r36ET4oQWb5HhO9GEe+2dttyJgV+stZJbZrPVmxmY1hUTZxIZ1ygGcMvrsVZZO0C9QsvMCyy" + + "xx4RzmTqomkC6Gtl3KtrZ4X28FQFDZi7MQaSXKEu2yS/NKJu2iT2BNKnE7QjTGFzc2UgTb5y" + + "a2VkYWhsIExhcnNlbiA8bG1sQGdyMy5kaz6ISwQQEQIACwUCN/MLYgQLAwIBAAoJEKg2SsWJ" + + "xEiGFbcAnA/ka/KE0Mnli7ybUhSrbESR/fZlAJ9SxU2foiRHMF8pF7I8KIJ9AQKSZLkCDQQ3" + + "8wtiEAgA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadWoxTpj0BV89AHxstDqZSt" + + "90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeSWc39uK50T8X8dryDxUcwYc58yWb/" + + "Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0iP1YTknbzSC0neSRBzZrM2w4DUUdD3yIsxx8" + + "Wy2O9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdXQ6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaG" + + "xAMZyAcpesqVDNmWn6vQClCbAkbTCD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwACAgf/cugy" + + "0nyWpA6GxoNqpdky1oCEbgII/lFKkGfQb/sHLgHURjmiaDXSuRJDRXC6YVC0HWqA+bfknR5m" + + "o1cvohu4GL/oul1eD85UfU29vg5Hr6f601o6xWVCiHF14B24JvO7jhYMd1MQRl7PVzH0a1Gp" + + "4hSoEvsUjU1HhGUhmMpUxwGJyIFt4RTkqKWK15omuJf4TLT47T58n9uClTNyxpx+oJGaiD0O" + + "SiEn9d4w5XFewhyXFQhisr99979dLq+buvH1QueMkVDExF4D8LN5gid8JPy/RqFxnHE8AcSF" + + "XHz9ou8m936pkyKYIMQkCwdw7/Wv7MK64ZED2zOnXnSb/JWY2YhGBBgRAgAGBQI38wtiAAoJ" + + "EKg2SsWJxEiGJdcAoIQOLuHGGS01Gz5WUpiQZYRtRMIYAKDuYx6bfQngRMs3/gEG0zoSGohY" + + "lQ==" + ); + + public void test1() + throws Exception + { + JcaPGPPublicKeyRingCollection pubRings = new JcaPGPPublicKeyRingCollection(pub1); + + int count = 0; + + Iterator rIt = pubRings.getKeyRings(); + + while (rIt.hasNext()) + { + PGPPublicKeyRing pgpPub = (PGPPublicKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpPub.getEncoded(); + + pgpPub = new PGPPublicKeyRing(bytes, new JcaKeyFingerprintCalculator()); + + Iterator it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPPublicKey pubKey = (PGPPublicKey)it.next(); + + Iterator sIt = pubKey.getSignatures(); + while (sIt.hasNext()) + { + ((PGPSignature)sIt.next()).getSignatureType(); + } + } + + if (keyCount != 2) + { + fail("wrong number of public keys"); + } + } + + if (count != 1) + { + fail("wrong number of public keyrings"); + } + + // + // exact match + // + rIt = pubRings.getKeyRings("test (Test key) <test@ubicall.com>"); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 1) + { + fail("wrong number of public keyrings on exact match"); + } + + // + // partial match 1 expected + // + rIt = pubRings.getKeyRings("test", true); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 1) + { + fail("wrong number of public keyrings on partial match 1"); + } + + // + // partial match 0 expected + // + rIt = pubRings.getKeyRings("XXX", true); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 0) + { + fail("wrong number of public keyrings on partial match 0"); + } + + // + // case-insensitive partial match + // + rIt = pubRings.getKeyRings("TEST@ubicall.com", true, true); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 1) + { + fail("wrong number of public keyrings on case-insensitive partial match"); + } + + JcaPGPSecretKeyRingCollection secretRings = new JcaPGPSecretKeyRingCollection(sec1); + + rIt = secretRings.getKeyRings(); + count = 0; + + while (rIt.hasNext()) + { + PGPSecretKeyRing pgpSec = (PGPSecretKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpSec.getEncoded(); + + pgpSec = new PGPSecretKeyRing(bytes, new JcaKeyFingerprintCalculator()); + + Iterator it = pgpSec.getSecretKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPSecretKey k = (PGPSecretKey)it.next(); + PGPPublicKey pk = k.getPublicKey(); + + pk.getSignatures(); + + byte[] pkBytes = pk.getEncoded(); + + PGPPublicKeyRing pkR = new PGPPublicKeyRing(pkBytes, new JcaKeyFingerprintCalculator()); + } + + if (keyCount != 2) + { + fail("wrong number of secret keys"); + } + } + + if (count != 1) + { + fail("wrong number of secret keyrings"); + } + + // + // exact match + // + rIt = secretRings.getKeyRings("test (Test key) <test@ubicall.com>"); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 1) + { + fail("wrong number of secret keyrings on exact match"); + } + + // + // partial match 1 expected + // + rIt = secretRings.getKeyRings("test", true); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 1) + { + fail("wrong number of secret keyrings on partial match 1"); + } + + // + // exact match 0 expected + // + rIt = secretRings.getKeyRings("test", false); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 0) + { + fail("wrong number of secret keyrings on partial match 0"); + } + + // + // case-insensitive partial match + // + rIt = secretRings.getKeyRings("TEST@ubicall.com", true, true); + count = 0; + while (rIt.hasNext()) + { + count++; + rIt.next(); + } + + if (count != 1) + { + fail("wrong number of secret keyrings on case-insensitive partial match"); + } + } + + public void test2() + throws Exception + { + JcaPGPPublicKeyRingCollection pubRings = new JcaPGPPublicKeyRingCollection(pub2); + + int count = 0; + + byte[] encRing = pubRings.getEncoded(); + + pubRings = new JcaPGPPublicKeyRingCollection(encRing); + + Iterator rIt = pubRings.getKeyRings(); + + while (rIt.hasNext()) + { + PGPPublicKeyRing pgpPub = (PGPPublicKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpPub.getEncoded(); + + pgpPub = new PGPPublicKeyRing(bytes, new JcaKeyFingerprintCalculator()); + + Iterator it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + PGPPublicKey pk = (PGPPublicKey)it.next(); + + byte[] pkBytes = pk.getEncoded(); + + PGPPublicKeyRing pkR = new PGPPublicKeyRing(pkBytes, new JcaKeyFingerprintCalculator()); + + keyCount++; + } + + if (keyCount != 2) + { + fail("wrong number of public keys"); + } + } + + if (count != 2) + { + fail("wrong number of public keyrings"); + } + + JcaPGPSecretKeyRingCollection secretRings = new JcaPGPSecretKeyRingCollection(sec2); + + rIt = secretRings.getKeyRings(); + count = 0; + + encRing = secretRings.getEncoded(); + + secretRings = new JcaPGPSecretKeyRingCollection(encRing); + + while (rIt.hasNext()) + { + PGPSecretKeyRing pgpSec = (PGPSecretKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpSec.getEncoded(); + + pgpSec = new PGPSecretKeyRing(bytes, new JcaKeyFingerprintCalculator()); + + Iterator it = pgpSec.getSecretKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPSecretKey k = (PGPSecretKey)it.next(); + PGPPublicKey pk = k.getPublicKey(); + + if (pk.getKeyID() == -1413891222336124627L) + { + int sCount = 0; + Iterator sIt = pk.getSignaturesOfType(PGPSignature.SUBKEY_BINDING); + while (sIt.hasNext()) + { + int type = ((PGPSignature)sIt.next()).getSignatureType(); + if (type != PGPSignature.SUBKEY_BINDING) + { + fail("failed to return correct signature type"); + } + sCount++; + } + + if (sCount != 1) + { + fail("failed to find binding signature"); + } + } + + pk.getSignatures(); + + if (k.getKeyID() == -4049084404703773049L + || k.getKeyID() == -1413891222336124627L) + { + k.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("SC").build(sec2pass1)); + } + else if (k.getKeyID() == -6498553574938125416L + || k.getKeyID() == 59034765524361024L) + { + k.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("SC").build(sec2pass2)); + } + } + + if (keyCount != 2) + { + fail("wrong number of secret keys"); + } + } + + if (count != 2) + { + fail("wrong number of secret keyrings"); + } + } + + public void test3() + throws Exception + { + JcaPGPPublicKeyRingCollection pubRings = new JcaPGPPublicKeyRingCollection(pub3); + + int count = 0; + + byte[] encRing = pubRings.getEncoded(); + + pubRings = new JcaPGPPublicKeyRingCollection(encRing); + + Iterator rIt = pubRings.getKeyRings(); + + while (rIt.hasNext()) + { + PGPPublicKeyRing pgpPub = (PGPPublicKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpPub.getEncoded(); + + pgpPub = new PGPPublicKeyRing(bytes, new JcaKeyFingerprintCalculator()); + + Iterator it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPPublicKey pubK = (PGPPublicKey)it.next(); + + pubK.getSignatures(); + } + + if (keyCount != 2) + { + fail("wrong number of public keys"); + } + } + + if (count != 1) + { + fail("wrong number of public keyrings"); + } + + JcaPGPSecretKeyRingCollection secretRings = new JcaPGPSecretKeyRingCollection(sec3); + + rIt = secretRings.getKeyRings(); + count = 0; + + encRing = secretRings.getEncoded(); + + secretRings = new JcaPGPSecretKeyRingCollection(encRing); + + while (rIt.hasNext()) + { + PGPSecretKeyRing pgpSec = (PGPSecretKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpSec.getEncoded(); + + pgpSec = new PGPSecretKeyRing(bytes, new JcaKeyFingerprintCalculator()); + + Iterator it = pgpSec.getSecretKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPSecretKey k = (PGPSecretKey)it.next(); + + k.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(sec3pass1)); + } + + if (keyCount != 2) + { + fail("wrong number of secret keys"); + } + } + + if (count != 1) + { + fail("wrong number of secret keyrings"); + } + } + + public void test4() + throws Exception + { + JcaPGPSecretKeyRingCollection secretRings = new JcaPGPSecretKeyRingCollection(sec4); + + Iterator rIt = secretRings.getKeyRings(); + int count = 0; + + byte[] encRing = secretRings.getEncoded(); + + secretRings = new JcaPGPSecretKeyRingCollection(encRing); + + while (rIt.hasNext()) + { + PGPSecretKeyRing pgpSec = (PGPSecretKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpSec.getEncoded(); + + pgpSec = new PGPSecretKeyRing(bytes, new JcaKeyFingerprintCalculator()); + + Iterator it = pgpSec.getSecretKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPSecretKey k = (PGPSecretKey)it.next(); + + k.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(sec3pass1)); + } + + if (keyCount != 2) + { + fail("test4 - wrong number of secret keys"); + } + + keyCount = 0; + it = pgpSec.getPublicKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPPublicKey k = (PGPPublicKey)it.next(); // make sure it's what we think it is! + } + + if (keyCount != 2) + { + fail("test4 - wrong number of public keys"); + } + } + + if (count != 1) + { + fail("wrong number of secret keyrings"); + } + } + + public void test5() + throws Exception + { + JcaPGPPublicKeyRingCollection pubRings = new JcaPGPPublicKeyRingCollection(pub5); + + int count = 0; + + byte[] encRing = pubRings.getEncoded(); + + pubRings = new JcaPGPPublicKeyRingCollection(encRing); + + Iterator rIt = pubRings.getKeyRings(); + + while (rIt.hasNext()) + { + PGPPublicKeyRing pgpPub = (PGPPublicKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpPub.getEncoded(); + + pgpPub = new PGPPublicKeyRing(bytes, new JcaKeyFingerprintCalculator()); + + Iterator it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + keyCount++; + + it.next(); + } + + if (keyCount != 2) + { + fail("wrong number of public keys"); + } + } + + if (count != 1) + { + fail("wrong number of public keyrings"); + } + + if (noIDEA()) + { + return; + } + + JcaPGPSecretKeyRingCollection secretRings = new JcaPGPSecretKeyRingCollection(sec5); + + rIt = secretRings.getKeyRings(); + count = 0; + + encRing = secretRings.getEncoded(); + + secretRings = new JcaPGPSecretKeyRingCollection(encRing); + + while (rIt.hasNext()) + { + PGPSecretKeyRing pgpSec = (PGPSecretKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpSec.getEncoded(); + + pgpSec = new PGPSecretKeyRing(bytes, new JcaKeyFingerprintCalculator()); + + Iterator it = pgpSec.getSecretKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPSecretKey k = (PGPSecretKey)it.next(); + + k.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("SC").build(sec5pass1)); + } + + if (keyCount != 2) + { + fail("wrong number of secret keys"); + } + } + + if (count != 1) + { + fail("wrong number of secret keyrings"); + } + } + + private boolean noIDEA() + { + try + { + Cipher.getInstance("IDEA", "SC"); + + return false; + } + catch (Exception e) + { + return true; + } + } + + public void test6() + throws Exception + { + JcaPGPPublicKeyRingCollection pubRings = new JcaPGPPublicKeyRingCollection(pub6); + Iterator rIt = pubRings.getKeyRings(); + + while (rIt.hasNext()) + { + PGPPublicKeyRing pgpPub = (PGPPublicKeyRing)rIt.next(); + Iterator it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + PGPPublicKey k = (PGPPublicKey)it.next(); + + if (k.getKeyID() == 0x5ce086b5b5a18ff4L) + { + int count = 0; + Iterator sIt = k.getSignaturesOfType(PGPSignature.SUBKEY_REVOCATION); + while (sIt.hasNext()) + { + PGPSignature sig = (PGPSignature)sIt.next(); + count++; + } + + if (count != 1) + { + fail("wrong number of revocations in test6."); + } + } + } + } + + byte[] encRing = pubRings.getEncoded(); + } + + public void revocationTest() + throws Exception + { + PGPPublicKeyRing pgpPub = new PGPPublicKeyRing(pub7, new JcaKeyFingerprintCalculator()); + Iterator it = pgpPub.getPublicKeys(); + PGPPublicKey masterKey = null; + + while (it.hasNext()) + { + PGPPublicKey k = (PGPPublicKey)it.next(); + + if (k.isMasterKey()) + { + masterKey = k; + continue; + } + } + + int count = 0; + PGPSignature sig = null; + Iterator sIt = masterKey.getSignaturesOfType(PGPSignature.KEY_REVOCATION); + + while (sIt.hasNext()) + { + sig = (PGPSignature)sIt.next(); + count++; + } + + if (count != 1) + { + fail("wrong number of revocations in test7."); + } + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), masterKey); + + if (!sig.verifyCertification(masterKey)) + { + fail("failed to verify revocation certification"); + } + + pgpPub = new PGPPublicKeyRing(pub7sub, new JcaKeyFingerprintCalculator()); + it = pgpPub.getPublicKeys(); + masterKey = null; + + while (it.hasNext()) + { + PGPPublicKey k = (PGPPublicKey)it.next(); + + if (k.isMasterKey()) + { + masterKey = k; + continue; + } + + count = 0; + sig = null; + sIt = k.getSignaturesOfType(PGPSignature.SUBKEY_REVOCATION); + + while (sIt.hasNext()) + { + sig = (PGPSignature)sIt.next(); + count++; + } + + if (count != 1) + { + fail("wrong number of revocations in test7 subkey."); + } + + if (sig.getSignatureType() != PGPSignature.SUBKEY_REVOCATION) + { + fail("wrong signature found"); + } + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), masterKey); + + if (!sig.verifyCertification(masterKey, k)) + { + fail("failed to verify revocation certification of subkey"); + } + } + } + + public void test8() + throws Exception + { + JcaPGPPublicKeyRingCollection pubRings = new JcaPGPPublicKeyRingCollection(pub8); + + int count = 0; + + byte[] encRing = pubRings.getEncoded(); + + pubRings = new JcaPGPPublicKeyRingCollection(encRing); + + Iterator rIt = pubRings.getKeyRings(); + + while (rIt.hasNext()) + { + PGPPublicKeyRing pgpPub = (PGPPublicKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpPub.getEncoded(); + + pgpPub = new PGPPublicKeyRing(bytes, new JcaKeyFingerprintCalculator()); + + Iterator it = pgpPub.getPublicKeys(); + while (it.hasNext()) + { + keyCount++; + + it.next(); + } + + if (keyCount != 2) + { + fail("wrong number of public keys"); + } + } + + if (count != 2) + { + fail("wrong number of public keyrings"); + } + + JcaPGPSecretKeyRingCollection secretRings = new JcaPGPSecretKeyRingCollection(sec8); + + rIt = secretRings.getKeyRings(); + count = 0; + + encRing = secretRings.getEncoded(); + + secretRings = new JcaPGPSecretKeyRingCollection(encRing); + + while (rIt.hasNext()) + { + PGPSecretKeyRing pgpSec = (PGPSecretKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpSec.getEncoded(); + + pgpSec = new PGPSecretKeyRing(bytes, new JcaKeyFingerprintCalculator()); + + Iterator it = pgpSec.getSecretKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPSecretKey k = (PGPSecretKey)it.next(); + + k.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("SC").build(sec8pass)); + } + + if (keyCount != 2) + { + fail("wrong number of secret keys"); + } + } + + if (count != 1) + { + fail("wrong number of secret keyrings"); + } + } + + public void test9() + throws Exception + { + JcaPGPSecretKeyRingCollection secretRings = new JcaPGPSecretKeyRingCollection(sec9); + + Iterator rIt = secretRings.getKeyRings(); + int count = 0; + + byte[] encRing = secretRings.getEncoded(); + + secretRings = new JcaPGPSecretKeyRingCollection(encRing); + + while (rIt.hasNext()) + { + PGPSecretKeyRing pgpSec = (PGPSecretKeyRing)rIt.next(); + + count++; + + int keyCount = 0; + + byte[] bytes = pgpSec.getEncoded(); + + pgpSec = new PGPSecretKeyRing(bytes, new JcaKeyFingerprintCalculator()); + + Iterator it = pgpSec.getSecretKeys(); + while (it.hasNext()) + { + keyCount++; + + PGPSecretKey k = (PGPSecretKey)it.next(); + + PGPPrivateKey pKey = k.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("SC").build(sec9pass)); + if (keyCount == 1 && pKey != null) + { + fail("primary secret key found, null expected"); + } + } + + if (keyCount != 3) + { + fail("wrong number of secret keys"); + } + } + + if (count != 1) + { + fail("wrong number of secret keyrings"); + } + } + + public void test10() + throws Exception + { + PGPSecretKeyRing secretRing = new PGPSecretKeyRing(sec10, new JcaKeyFingerprintCalculator()); + Iterator secretKeys = secretRing.getSecretKeys(); + + while (secretKeys.hasNext()) + { + PGPPublicKey pubKey = ((PGPSecretKey)secretKeys.next()).getPublicKey(); + + if (pubKey.getValidDays() != 28) + { + fail("days wrong on secret key ring"); + } + + if (pubKey.getValidSeconds() != 28 * 24 * 60 * 60) + { + fail("seconds wrong on secret key ring"); + } + } + + PGPPublicKeyRing publicRing = new PGPPublicKeyRing(pub10, new JcaKeyFingerprintCalculator()); + Iterator publicKeys = publicRing.getPublicKeys(); + + while (publicKeys.hasNext()) + { + PGPPublicKey pubKey = (PGPPublicKey)publicKeys.next(); + + if (pubKey.getValidDays() != 28) + { + fail("days wrong on public key ring"); + } + + if (pubKey.getValidSeconds() != 28 * 24 * 60 * 60) + { + fail("seconds wrong on public key ring"); + } + } + } + + public void generateTest() + throws Exception + { + char[] passPhrase = "hello".toCharArray(); + KeyPairGenerator dsaKpg = KeyPairGenerator.getInstance("DSA", "SC"); + + dsaKpg.initialize(512); + + // + // this takes a while as the key generator has to generate some DSA params + // before it generates the key. + // + KeyPair dsaKp = dsaKpg.generateKeyPair(); + + KeyPairGenerator elgKpg = KeyPairGenerator.getInstance("ELGAMAL", "SC"); + BigInteger g = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + BigInteger p = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g); + + elgKpg.initialize(elParams); + + // + // this is quicker because we are using pregenerated parameters. + // + KeyPair elgKp = elgKpg.generateKeyPair(); + PGPKeyPair dsaKeyPair = new JcaPGPKeyPair(PGPPublicKey.DSA, dsaKp, new Date()); + PGPKeyPair elgKeyPair = new JcaPGPKeyPair(PGPPublicKey.ELGAMAL_ENCRYPT, elgKp, new Date()); + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, dsaKeyPair, + "test", sha1Calc, null, null, new JcaPGPContentSignerBuilder(PGPPublicKey.DSA, HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256).setProvider("SC").build(passPhrase)); + + + keyRingGen.addSubKey(elgKeyPair); + + PGPSecretKeyRing keyRing = keyRingGen.generateSecretKeyRing(); + + keyRing.getSecretKey().extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("SC").build(passPhrase)); + + PGPPublicKeyRing pubRing = keyRingGen.generatePublicKeyRing(); + + PGPPublicKey vKey = null; + PGPPublicKey sKey = null; + + Iterator it = pubRing.getPublicKeys(); + while (it.hasNext()) + { + PGPPublicKey pk = (PGPPublicKey)it.next(); + if (pk.isMasterKey()) + { + vKey = pk; + } + else + { + sKey = pk; + } + } + + Iterator sIt = sKey.getSignatures(); + while (sIt.hasNext()) + { + PGPSignature sig = (PGPSignature)sIt.next(); + + if (sig.getKeyID() == vKey.getKeyID() + && sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) + { + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), vKey); + + if (!sig.verifyCertification(vKey, sKey)) + { + fail("failed to verify sub-key signature."); + } + } + } + } + + private void insertMasterTest() + throws Exception + { + char[] passPhrase = "hello".toCharArray(); + KeyPairGenerator rsaKpg = KeyPairGenerator.getInstance("RSA", "SC"); + + rsaKpg.initialize(512); + + // + // this is quicker because we are using pregenerated parameters. + // + KeyPair rsaKp = rsaKpg.generateKeyPair(); + PGPKeyPair rsaKeyPair1 = new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, rsaKp, new Date()); + rsaKp = rsaKpg.generateKeyPair(); + PGPKeyPair rsaKeyPair2 = new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, rsaKp, new Date()); + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, rsaKeyPair1, + "test", sha1Calc, null, null, new JcaPGPContentSignerBuilder(PGPPublicKey.RSA_SIGN, HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256).setProvider("SC").build(passPhrase)); + PGPSecretKeyRing secRing1 = keyRingGen.generateSecretKeyRing(); + PGPPublicKeyRing pubRing1 = keyRingGen.generatePublicKeyRing(); + keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, rsaKeyPair2, + "test", sha1Calc, null, null, new JcaPGPContentSignerBuilder(PGPPublicKey.RSA_SIGN, HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256).setProvider("SC").build(passPhrase)); + PGPSecretKeyRing secRing2 = keyRingGen.generateSecretKeyRing(); + PGPPublicKeyRing pubRing2 = keyRingGen.generatePublicKeyRing(); + + try + { + PGPPublicKeyRing.insertPublicKey(pubRing1, pubRing2.getPublicKey()); + fail("adding second master key (public) should throw an IllegalArgumentException"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("cannot add a master key to a ring that already has one")) + { + fail("wrong message in public test"); + } + } + + try + { + PGPSecretKeyRing.insertSecretKey(secRing1, secRing2.getSecretKey()); + fail("adding second master key (secret) should throw an IllegalArgumentException"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("cannot add a master key to a ring that already has one")) + { + fail("wrong message in secret test"); + } + } + } + + public void generateSha1Test() + throws Exception + { + char[] passPhrase = "hello".toCharArray(); + KeyPairGenerator dsaKpg = KeyPairGenerator.getInstance("DSA", "SC"); + + dsaKpg.initialize(512); + + // + // this takes a while as the key generator has to generate some DSA params + // before it generates the key. + // + KeyPair dsaKp = dsaKpg.generateKeyPair(); + + KeyPairGenerator elgKpg = KeyPairGenerator.getInstance("ELGAMAL", "SC"); + BigInteger g = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + BigInteger p = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g); + + elgKpg.initialize(elParams); + + // + // this is quicker because we are using pregenerated parameters. + // + KeyPair elgKp = elgKpg.generateKeyPair(); + PGPKeyPair dsaKeyPair = new JcaPGPKeyPair(PGPPublicKey.DSA, dsaKp, new Date()); + PGPKeyPair elgKeyPair = new JcaPGPKeyPair(PGPPublicKey.ELGAMAL_ENCRYPT, elgKp, new Date()); + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, dsaKeyPair, + "test", sha1Calc, null, null, new JcaPGPContentSignerBuilder(PGPPublicKey.DSA, HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256).setProvider("SC").build(passPhrase)); + + + keyRingGen.addSubKey(elgKeyPair); + + PGPSecretKeyRing keyRing = keyRingGen.generateSecretKeyRing(); + + keyRing.getSecretKey().extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("SC").build(passPhrase)); + + if (!keyRing.getSecretKey().getPublicKey().equals(keyRing.getPublicKey())) + { + fail("secret key public key mismatch"); + } + + PGPPublicKeyRing pubRing = keyRingGen.generatePublicKeyRing(); + + PGPPublicKey vKey = null; + PGPPublicKey sKey = null; + + Iterator it = pubRing.getPublicKeys(); + while (it.hasNext()) + { + PGPPublicKey pk = (PGPPublicKey)it.next(); + if (pk.isMasterKey()) + { + vKey = pk; + } + else + { + sKey = pk; + } + } + + // check key id fetch + if (keyRing.getPublicKey(vKey.getKeyID()).getKeyID() != vKey.getKeyID()) + { + fail("secret key public key mismatch - vKey"); + } + + if (keyRing.getPublicKey(sKey.getKeyID()).getKeyID() != sKey.getKeyID()) + { + fail("secret key public key mismatch - sKey"); + } + + Iterator sIt = sKey.getSignatures(); + while (sIt.hasNext()) + { + PGPSignature sig = (PGPSignature)sIt.next(); + + if (sig.getKeyID() == vKey.getKeyID() + && sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) + { + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), vKey); + + if (!sig.verifyCertification(vKey, sKey)) + { + fail("failed to verify sub-key signature."); + } + } + } + } + + private void test11() + throws Exception + { + PGPPublicKeyRing pubRing = new PGPPublicKeyRing(subKeyBindingKey, new JcaKeyFingerprintCalculator()); + Iterator it = pubRing.getPublicKeys(); + + while (it.hasNext()) + { + PGPPublicKey key = (PGPPublicKey)it.next(); + + if (key.getValidSeconds() != 0) + { + fail("expiration time non-zero"); + } + } + } + + private void rewrapTest() + throws Exception + { + // Read the secret key rings + JcaPGPSecretKeyRingCollection privRings = new JcaPGPSecretKeyRingCollection( + new ByteArrayInputStream(rewrapKey)); + char[] newPass = "fred".toCharArray(); + + Iterator rIt = privRings.getKeyRings(); + + if (rIt.hasNext()) + { + PGPSecretKeyRing pgpPriv= (PGPSecretKeyRing)rIt.next(); + + Iterator it = pgpPriv.getSecretKeys(); + + while (it.hasNext()) + { + PGPSecretKey pgpKey = (PGPSecretKey)it.next(); + long oldKeyID = pgpKey.getKeyID(); + + // re-encrypt the key with an empty password + pgpPriv = PGPSecretKeyRing.removeSecretKey(pgpPriv, pgpKey); + pgpKey = PGPSecretKey.copyWithNewPassword( + pgpKey, + new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(rewrapPass), + null); + pgpPriv = PGPSecretKeyRing.insertSecretKey(pgpPriv, pgpKey); + + // this should succeed + PGPPrivateKey privTmp = pgpKey.extractPrivateKey(null); + + if (pgpKey.getKeyID() != oldKeyID) + { + fail("key ID mismatch"); + } + } + + it = pgpPriv.getSecretKeys(); + + while (it.hasNext()) + { + PGPSecretKey pgpKey = (PGPSecretKey)it.next(); + long oldKeyID = pgpKey.getKeyID(); + + // re-encrypt the key with an empty password + pgpPriv = PGPSecretKeyRing.removeSecretKey(pgpPriv, pgpKey); + pgpKey = PGPSecretKey.copyWithNewPassword( + pgpKey, + null, + new JcePBESecretKeyEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5).setProvider("SC").build(newPass)); + pgpPriv = PGPSecretKeyRing.insertSecretKey(pgpPriv, pgpKey); + + // this should succeed + PGPPrivateKey privTmp = pgpKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(newPass)); + + if (pgpKey.getKeyID() != oldKeyID) + { + fail("key ID mismatch"); + } + } + } + } + + private void rewrapTestV3() + throws Exception + { + // Read the secret key rings + JcaPGPSecretKeyRingCollection privRings = new JcaPGPSecretKeyRingCollection( + new ByteArrayInputStream(privv3)); + char[] newPass = "fred".toCharArray(); + + Iterator rIt = privRings.getKeyRings(); + + if (rIt.hasNext()) + { + PGPSecretKeyRing pgpPriv = (PGPSecretKeyRing)rIt.next(); + + Iterator it = pgpPriv.getSecretKeys(); + + while (it.hasNext()) + { + PGPSecretKey pgpKey = (PGPSecretKey)it.next(); + long oldKeyID = pgpKey.getKeyID(); + + // re-encrypt the key with an empty password + pgpPriv = PGPSecretKeyRing.removeSecretKey(pgpPriv, pgpKey); + + pgpKey = PGPSecretKey.copyWithNewPassword( + pgpKey, + new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(v3KeyPass), + null); + pgpPriv = PGPSecretKeyRing.insertSecretKey(pgpPriv, pgpKey); + + // this should succeed + PGPPrivateKey privTmp = pgpKey.extractPrivateKey(null); + + if (pgpKey.getKeyID() != oldKeyID) + { + fail("key ID mismatch"); + } + } + + it = pgpPriv.getSecretKeys(); + + while (it.hasNext()) + { + PGPSecretKey pgpKey = (PGPSecretKey)it.next(); + long oldKeyID = pgpKey.getKeyID(); + + // re-encrypt the key with an empty password + pgpPriv = PGPSecretKeyRing.removeSecretKey(pgpPriv, pgpKey); + pgpKey = PGPSecretKey.copyWithNewPassword( + pgpKey, + null, + new JcePBESecretKeyEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5, new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build().get(HashAlgorithmTags.MD5)).setProvider("SC").build(newPass)); + pgpPriv = PGPSecretKeyRing.insertSecretKey(pgpPriv, pgpKey); + + // this should succeed + PGPPrivateKey privTmp = pgpKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(newPass)); + + if (pgpKey.getKeyID() != oldKeyID) + { + fail("key ID mismatch"); + } + } + } + } + + private void rewrapTestMD5() + throws Exception + { + // Read the secret key rings + JcaPGPSecretKeyRingCollection privRings = new JcaPGPSecretKeyRingCollection( + new ByteArrayInputStream(rewrapKey)); + char[] newPass = "fred".toCharArray(); + + Iterator rIt = privRings.getKeyRings(); + + if (rIt.hasNext()) + { + PGPSecretKeyRing pgpPriv= (PGPSecretKeyRing)rIt.next(); + + Iterator it = pgpPriv.getSecretKeys(); + + PGPDigestCalculatorProvider calcProvider = new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build(); + + while (it.hasNext()) + { + PGPSecretKey pgpKey = (PGPSecretKey)it.next(); + long oldKeyID = pgpKey.getKeyID(); + + // re-encrypt the key with an empty password + pgpPriv = PGPSecretKeyRing.removeSecretKey(pgpPriv, pgpKey); + pgpKey = PGPSecretKey.copyWithNewPassword( + pgpKey, + new JcePBESecretKeyDecryptorBuilder(calcProvider).setProvider("SC").build(rewrapPass), + null); + pgpPriv = PGPSecretKeyRing.insertSecretKey(pgpPriv, pgpKey); + + // this should succeed + PGPPrivateKey privTmp = pgpKey.extractPrivateKey(null); + + if (pgpKey.getKeyID() != oldKeyID) + { + fail("key ID mismatch"); + } + } + + it = pgpPriv.getSecretKeys(); + + while (it.hasNext()) + { + PGPSecretKey pgpKey = (PGPSecretKey)it.next(); + long oldKeyID = pgpKey.getKeyID(); + + // re-encrypt the key with an empty password + pgpPriv = PGPSecretKeyRing.removeSecretKey(pgpPriv, pgpKey); + pgpKey = PGPSecretKey.copyWithNewPassword( + pgpKey, + null, + new JcePBESecretKeyEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5, calcProvider.get(HashAlgorithmTags.MD5)).setProvider("SC").build(newPass)); + pgpPriv = PGPSecretKeyRing.insertSecretKey(pgpPriv, pgpKey); + + // this should succeed + PGPPrivateKey privTmp = pgpKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(calcProvider).setProvider("SC").build(newPass)); + + if (pgpKey.getKeyID() != oldKeyID) + { + fail("key ID mismatch"); + } + } + } + } + + private void testPublicKeyRingWithX509() + throws Exception + { + checkPublicKeyRingWithX509(pubWithX509); + + PGPPublicKeyRing pubRing = new PGPPublicKeyRing(pubWithX509, new JcaKeyFingerprintCalculator()); + + checkPublicKeyRingWithX509(pubRing.getEncoded()); + } + + private void testSecretKeyRingWithPersonalCertificate() + throws Exception + { + checkSecretKeyRingWithPersonalCertificate(secWithPersonalCertificate); + JcaPGPSecretKeyRingCollection secRing = new JcaPGPSecretKeyRingCollection(secWithPersonalCertificate); + checkSecretKeyRingWithPersonalCertificate(secRing.getEncoded()); + } + + private void testUmlaut() + throws Exception + { + PGPPublicKeyRing pubRing = new PGPPublicKeyRing(umlautKeySig, new JcaKeyFingerprintCalculator()); + + PGPPublicKey pub = pubRing.getPublicKey(); + String userID = (String)pub.getUserIDs().next(); + + for (Iterator it = pub.getSignatures(); it.hasNext();) + { + PGPSignature sig = (PGPSignature)it.next(); + + if (sig.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION) + { + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pub); + + if (!sig.verifyCertification(userID, pub)) + { + fail("failed UTF8 userID test"); + } + } + } + + // + // this is quicker because we are using pregenerated parameters. + // + KeyPairGenerator rsaKpg = KeyPairGenerator.getInstance("RSA", "SC"); + KeyPair rsaKp = rsaKpg.generateKeyPair(); + PGPKeyPair rsaKeyPair1 = new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, rsaKp, new Date()); + rsaKp = rsaKpg.generateKeyPair(); + PGPKeyPair rsaKeyPair2 = new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, rsaKp, new Date()); + char[] passPhrase = "passwd".toCharArray(); + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, rsaKeyPair1, + userID, sha1Calc, null, null, new JcaPGPContentSignerBuilder(PGPPublicKey.RSA_SIGN, HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256).setProvider("SC").build(passPhrase)); + + + PGPPublicKeyRing pubRing1 = keyRingGen.generatePublicKeyRing(); + + pub = pubRing1.getPublicKey(); + + for (Iterator it = pub.getSignatures(); it.hasNext();) + { + PGPSignature sig = (PGPSignature)it.next(); + + if (sig.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION) + { + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pub); + + if (!sig.verifyCertification(userID, pub)) + { + fail("failed UTF8 userID creation test"); + } + } + } + } + + private void checkSecretKeyRingWithPersonalCertificate(byte[] keyRing) + throws Exception + { + JcaPGPSecretKeyRingCollection secCol = new JcaPGPSecretKeyRingCollection(keyRing); + + + int count = 0; + + for (Iterator rIt = secCol.getKeyRings(); rIt.hasNext();) + { + PGPSecretKeyRing ring = (PGPSecretKeyRing)rIt.next(); + + for (Iterator it = ring.getExtraPublicKeys(); it.hasNext();) + { + it.next(); + count++; + } + } + + if (count != 1) + { + fail("personal certificate data subkey not found - count = " + count); + } + } + + private void checkPublicKeyRingWithX509(byte[] keyRing) + throws Exception + { + PGPPublicKeyRing pubRing = new PGPPublicKeyRing(keyRing, new JcaKeyFingerprintCalculator()); + Iterator it = pubRing.getPublicKeys(); + + if (it.hasNext()) + { + PGPPublicKey key = (PGPPublicKey)it.next(); + + Iterator sIt = key.getSignatures(); + + if (sIt.hasNext()) + { + PGPSignature sig = (PGPSignature)sIt.next(); + if (sig.getKeyAlgorithm() != 100) + { + fail("experimental signature not found"); + } + if (!areEqual(sig.getSignature(), Hex.decode("000101"))) + { + fail("experimental encoding check failed"); + } + } + else + { + fail("no signature found"); + } + } + else + { + fail("no key found"); + } + } + + // test for key ring with non-UTF8 User ID. + private void testBadUserID() + throws Exception + { + PGPPublicKeyRing pgpRing = new JcaPGPPublicKeyRing(problemUserID); + + byte[] enc = pgpRing.getEncoded(); + + if (!Arrays.areEqual(problemUserID, enc)) + { + fail("encoded key does not match original"); + } + + PGPPublicKey pubKey = pgpRing.getPublicKey(); + + Iterator it = pubKey.getRawUserIDs(); + + byte[] rawID = (byte[])it.next(); + + it = pubKey.getSignaturesForID(rawID); + + PGPSignature sig = (PGPSignature)it.next(); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pubKey); + + if (!sig.verifyCertification(rawID, pubKey)) + { + fail("Certification not validated for rawID"); + } + } + + public void testNoExportPrivateKey() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "SC"); + + kpGen.initialize(1024); + + KeyPair kp = kpGen.generateKeyPair(); + + JcaPGPKeyConverter converter = new JcaPGPKeyConverter(); + PGPPublicKey pubKey = converter.getPGPPublicKey(PGPPublicKey.RSA_GENERAL, kp.getPublic(), new Date()); + PGPPrivateKey privKey = new JcaPGPPrivateKey(pubKey, kp.getPrivate()); + + doTestNoExportPrivateKey(new PGPKeyPair(pubKey, privKey)); + } + + private void doTestNoExportPrivateKey(PGPKeyPair keyPair) + throws Exception + { + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, keyPair, + "test", sha1Calc, null, null, new JcaPGPContentSignerBuilder(PGPPublicKey.RSA_SIGN, HashAlgorithmTags.SHA1), null); + + PGPPublicKey pubKey = keyPair.getPublicKey(); + PGPPublicKeyRing pubRing = keyRingGen.generatePublicKeyRing(); + if (pubRing.getPublicKey(pubKey.getKeyID()) == null) + { + fail("no public key found"); + } + + for (Iterator it = pubRing.getPublicKey().getSignatures(); it.hasNext();) + { + PGPSignature sig = (PGPSignature)it.next(); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pubKey); + + if (!sig.verifyCertification("test", pubKey)) + { + fail("certification failed"); + } + } + + pubRing.getEncoded(); + + PGPSecretKeyRing secRing = keyRingGen.generateSecretKeyRing(); + + secRing.getEncoded(); + } + + public void performTest() + throws Exception + { + try + { + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + revocationTest(); + test8(); + test9(); + test10(); + test11(); + generateTest(); + generateSha1Test(); + rewrapTest(); + rewrapTestV3(); + rewrapTestMD5(); + testPublicKeyRingWithX509(); + testSecretKeyRingWithPersonalCertificate(); + insertMasterTest(); + testUmlaut(); + testBadUserID(); + testNoExportPrivateKey(); + } + catch (PGPException e) + { + if (((PGPException)e).getUnderlyingException() != null) + { + Exception ex = ((PGPException)e).getUnderlyingException(); + fail("exception: " + ex, ex); + } + else + { + fail("exception: " + e, e); + } + } + } + + public String getName() + { + return "PGPKeyRingTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PGPKeyRingTest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPMarkerTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPMarkerTest.java new file mode 100644 index 00000000..1f638f44 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPMarkerTest.java @@ -0,0 +1,105 @@ +package org.spongycastle.openpgp.test; + +import org.spongycastle.openpgp.PGPEncryptedDataList; +import org.spongycastle.openpgp.PGPMarker; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +public class PGPMarkerTest + implements Test +{ + private byte[] message1 = Base64.decode( + "qANQR1DBwU4DdrlXatQSHgoQCADWlhY3bWWaOTm4t2espRWPFQmETeinnieHce64" + + "lmEIFzaryEWeSdQc8XGfDzcb7sxq7b5b9Hm6OrACcCbSp2KGEJNG5kJmo2A16UPq" + + "JdK4xNelpJRh3KcJPv+N/9VJrMdj4C+DRnGNFg1hTQf3RKsX+ms2V0OBC5vGlOZY" + + "zX+XZz/7hl1PXVLN23u4npZI/1xETI2VtRoM76S6oykGXxMtT3+sGU1fAVEKVS45" + + "pyQHWbBqApkWrURq0xBqpVfDwOgGw09dJxt2igW9hjvNAd9tJiMGrMF5o2OLlub7" + + "c7FiK+dWLLcw+nx7Hl6FQmo9E8qyW8x1Cb78HjR/JXMgH/ngB/4gba6xX+s5TJkW" + + "H2Wpp5ePTw39EqHosUMrm05R+C0ha3EyyaJIvKj2WWmImKu5PWo1t37Pi6KHFNC3" + + "wsYJMRKnnNtd34luMTOgLpDcdgClzfp2p6EqHMoB7Uj3etlLmbN+vpGgz9qkLBRV" + + "7MpR1yE9qrZNeGgbkry6N31w5E7HoAHu5JNcwxgzbJoj2lI8uvs6Gf7fEoQOuAPE" + + "W/SGlfR2BdBPiJ1yErMElc2O8LVS0wTwwifHpEsMV+1ntl1EC5d052lo+6q7zNqD" + + "uYt1/2if6h9W9fe+S9mzr0ZAtxIN2ZGOFJJRnqzjDQ4siB9nnwr6YgvUVRSr/lQB" + + "hDTd0bmjyWacCt0PPMJWchO6A5tzqKUpTWSYibpdks80kLQogQHsJTZd/kpS0I6f" + + "gD0HYYlMssZwhg2J2TWwXDpDTgQ6mzFKbGSdOSk/deTJj2+EubzxaZcxZEocCJA8" + + "bppCj4kLBnCj1LjYx7A="); + + private byte[] message2 = Base64.decode( + "qANQR1DBwU4DZlTzKj+E4aMQCADruFAojUIlHGcnswLIekvhbVnaHnbCt6Kp" + + "IL2zppmEIYJ9n1xCO1k+3Y5j9vNATbqCVWs1HD0aAL3PRI1eZ1l8GkIBCd2z" + + "tcZpSI/uyI/JCzVW2stCH0gpP2V7zcjk8HaIuBz4ZsyU9m7v6LwCDPB4CTrb" + + "Z5nn5Jm3eowonQsRL/3TpJtG+IjTaw29NbCBNNX8quM5LwfIsfWovqNv28r1" + + "aX8FsqoTRsWEfQ7dMV/swVGqv0PgKxqErdnZVJ2yOJqjLk+lBJT6zhqPijGV" + + "10pc68hdZxxLU1KZq25DAjS12xcAgagjRkOmYE/H1oEjGZlXfS4y/xQ7skHa" + + "HI+b04vECACTpQPwCXhxYiNWnf4XhJPONIGyrsXVtsTNwzOShFPmeUvpipP4" + + "HknakBkBuUY49xcffQogW/NlGCZnQOulDLE6fCH/krkSmI8WVP5Vhf6bM1Qm" + + "92dHZFoTrrcQ9NVGaCNHHWf7KXkNfKdTkE23LdggoVrVAzO4WcdqVc6s/or7" + + "jQYP9zXLeu8+GGFMxe/9FCtoIWbujGQHsdDEkCK4h+D44EVDPzbvWj39ZB4w" + + "hHoab8RLHd7njcrPeoCPdYkFVCKOSuLdxxYZDbbmgpISaafrafwefkkESeGu" + + "JzbNhmyS8zfOiejWzndaLYWUSE/sqISK9Pg+xKundnFPk04+AhIRyYEoUjG3" + + "LgGVyM49mrM8E7QwAGU0m/VCJLoOu+N74Z1rp1wFdA5yCllFlONNM4Czhd1D" + + "ZMyLFqGXiKlyVCPlUTN2uVisYQGr6iNGYSPxpKjwiAzdeeQBPOETG0vd3nTO" + + "MN4BMKcG+kRJd5FU72SRfmbGwPPjd1gts9xFvtj4Tvpkam8="); + + public TestResult perform() + { + try + { + // + // test encrypted message + // + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(message1); + + Object o; + + if (pgpFact.nextObject() instanceof PGPMarker) + { + if (pgpFact.nextObject() instanceof PGPEncryptedDataList) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": error processing after marker."); + } + } + + pgpFact = new JcaPGPObjectFactory(message2); + + if (pgpFact.nextObject() instanceof PGPMarker) + { + if (pgpFact.nextObject() instanceof PGPEncryptedDataList) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": error processing after marker."); + } + } + + return new SimpleTestResult(false, getName() + ": marker not found"); + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": exception - " + e.toString()); + } + } + + public String getName() + { + return "PGPMarkerTest"; + } + + public static void main( + String[] args) + { + Test test = new PGPMarkerTest(); + TestResult result = test.perform(); + + System.out.println(result.toString()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPNoPrivateKeyTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPNoPrivateKeyTest.java new file mode 100644 index 00000000..e4761fa4 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPNoPrivateKeyTest.java @@ -0,0 +1,167 @@ +package org.spongycastle.openpgp.test; + +import java.security.Security; + +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.test.SimpleTest; + +public class PGPNoPrivateKeyTest + extends SimpleTest +{ + String pgpOldPass = "test"; + String pgpNewPass = "newtest"; + String BOUNCY_CASTLE_PROVIDER_NAME = "SC"; + + byte[] pgpPrivateEmpty = Base64.decode( + "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" + + "+b3JLdM="); + + byte[] pgpPrivateFull = Base64.decode( + "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"); + + public void performTest() + throws Exception + { + PGPSecretKeyRing pgpSecRing = new PGPSecretKeyRing(pgpPrivateFull, new JcaKeyFingerprintCalculator()); + PGPSecretKey pgpSecKey = pgpSecRing.getSecretKey(); + boolean isFullEmpty = pgpSecKey.isPrivateKeyEmpty(); + + pgpSecRing = new PGPSecretKeyRing(pgpPrivateEmpty, new JcaKeyFingerprintCalculator()); + pgpSecKey = pgpSecRing.getSecretKey(); + boolean isEmptyEmpty = pgpSecKey.isPrivateKeyEmpty(); + + // + // Check isPrivateKeyEmpty() is public + // + + if (isFullEmpty || !isEmptyEmpty) + { + fail("Empty private keys not detected correctly."); + } + + // + // Check copyWithNewPassword doesn't throw an exception for secret + // keys without private keys (PGPException: unknown S2K type: 101). + // + + try + { + PGPSecretKey pgpChangedKey = PGPSecretKey.copyWithNewPassword(pgpSecKey, + new JcePBESecretKeyDecryptorBuilder( + new JcaPGPDigestCalculatorProviderBuilder().setProvider(BOUNCY_CASTLE_PROVIDER_NAME).build()).setProvider(BOUNCY_CASTLE_PROVIDER_NAME).build(pgpOldPass.toCharArray()), + new JcePBESecretKeyEncryptorBuilder(pgpSecKey.getKeyEncryptionAlgorithm()).build(pgpNewPass.toCharArray())); + } + catch (PGPException e) + { + if (!e.getMessage().equals("no private key in this SecretKey - public key present only.")) + { + fail("wrong exception."); + } + } + } + + public String getName() + { + return "PGPNoPrivateKeyTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PGPNoPrivateKeyTest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPPBETest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPPBETest.java new file mode 100644 index 00000000..f35f4fca --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPPBETest.java @@ -0,0 +1,400 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Date; + +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPCompressedData; +import org.spongycastle.openpgp.PGPCompressedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedData; +import org.spongycastle.openpgp.PGPEncryptedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedDataList; +import org.spongycastle.openpgp.PGPLiteralData; +import org.spongycastle.openpgp.PGPLiteralDataGenerator; +import org.spongycastle.openpgp.PGPPBEEncryptedData; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator; +import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; +import org.spongycastle.util.test.UncloseableOutputStream; + +public class PGPPBETest + extends SimpleTest +{ + private static final Date TEST_DATE = new Date(1062200111000L); + + byte[] enc1 = Base64.decode( + "jA0EAwMC5M5wWBP2HBZgySvUwWFAmMRLn7dWiZN6AkQMvpE3b6qwN3SSun7zInw2" + + "hxxdgFzVGfbjuB8w"); + + byte[] enc1crc = Base64.decode("H66L"); + + char[] pass = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' }; + + /** + * Message with both PBE and symmetric + */ + byte[] testPBEAsym = Base64.decode( + "hQIOA/ZlQEFWB5vuEAf/covEUaBve7NlWWdiO5NZubdtTHGElEXzG9hyBycp9At8" + + "nZGi27xOZtEGFQo7pfz4JySRc3O0s6w7PpjJSonFJyNSxuze2LuqRwFWBYYcbS8/" + + "7YcjB6PqutrT939OWsozfNqivI9/QyZCjBvFU89pp7dtUngiZ6MVv81ds2I+vcvk" + + "GlIFcxcE1XoCIB3EvbqWNaoOotgEPT60unnB2BeDV1KD3lDRouMIYHfZ3SzBwOOI" + + "6aK39sWnY5sAK7JjFvnDAMBdueOiI0Fy+gxbFD/zFDt4cWAVSAGTC4w371iqppmT" + + "25TM7zAtCgpiq5IsELPlUZZnXKmnYQ7OCeysF0eeVwf+OFB9fyvCEv/zVQocJCg8" + + "fWxfCBlIVFNeNQpeGygn/ZmRaILvB7IXDWP0oOw7/F2Ym66IdYYIp2HeEZv+jFwa" + + "l41w5W4BH/gtbwGjFQ6CvF/m+lfUv6ZZdzsMIeEOwhP5g7rXBxrbcnGBaU+PXbho" + + "gjDqaYzAWGlrmAd6aPSj51AGeYXkb2T1T/yoJ++M3GvhH4C4hvitamDkksh/qRnM" + + "M/s8Nku6z1+RXO3M6p5QC1nlAVqieU8esT43945eSoC77K8WyujDNbysDyUCUTzt" + + "p/aoQwe/HgkeOTJNelKR9y2W3xinZLFzep0SqpNI/e468yB/2/LGsykIyQa7JX6r" + + "BYwuBAIDAkOKfv5rK8v0YDfnN+eFqwhTcrfBj5rDH7hER6nW3lNWcMataUiHEaMg" + + "o6Q0OO1vptIGxW8jClTD4N1sCNwNu9vKny8dKYDDHbCjE06DNTv7XYVW3+JqTL5E" + + "BnidvGgOmA=="); + + /** + * decrypt the passed in message stream + */ + private byte[] decryptMessage( + byte[] message, + Date date) + throws Exception + { + JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(message); + PGPEncryptedDataList enc = (PGPEncryptedDataList)pgpF.nextObject(); + PGPPBEEncryptedData pbe = (PGPPBEEncryptedData)enc.get(0); + + InputStream clear = pbe.getDataStream(new JcePBEDataDecryptorFactoryBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(pass)); + + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(clear); + PGPCompressedData cData = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(cData.getDataStream()); + + PGPLiteralData ld = (PGPLiteralData)pgpFact.nextObject(); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + if (!ld.getFileName().equals("test.txt") + && !ld.getFileName().equals("_CONSOLE")) + { + fail("wrong filename in packet"); + } + if (!ld.getModificationTime().equals(date)) + { + fail("wrong modification time in packet: " + ld.getModificationTime().getTime() + " " + date.getTime()); + } + + InputStream unc = ld.getInputStream(); + int ch; + + while ((ch = unc.read()) >= 0) + { + bOut.write(ch); + } + + if (pbe.isIntegrityProtected() && !pbe.verify()) + { + fail("integrity check failed"); + } + + return bOut.toByteArray(); + } + + private byte[] decryptMessageBuffered( + byte[] message, + Date date) + throws Exception + { + JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(message); + PGPEncryptedDataList enc = (PGPEncryptedDataList)pgpF.nextObject(); + PGPPBEEncryptedData pbe = (PGPPBEEncryptedData)enc.get(0); + + InputStream clear = pbe.getDataStream(new JcePBEDataDecryptorFactoryBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(pass)); + + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(clear); + PGPCompressedData cData = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(cData.getDataStream()); + + PGPLiteralData ld = (PGPLiteralData)pgpFact.nextObject(); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + if (!ld.getFileName().equals("test.txt") + && !ld.getFileName().equals("_CONSOLE")) + { + fail("wrong filename in packet"); + } + if (!ld.getModificationTime().equals(date)) + { + fail("wrong modification time in packet: " + ld.getModificationTime().getTime() + " " + date.getTime()); + } + + InputStream unc = ld.getInputStream(); + byte[] buf = new byte[1024]; + int len; + + while ((len = unc.read(buf)) >= 0) + { + bOut.write(buf, 0, len); + } + + if (pbe.isIntegrityProtected() && !pbe.verify()) + { + fail("integrity check failed"); + } + + return bOut.toByteArray(); + } + + public void performTest() + throws Exception + { + byte[] out = decryptMessage(enc1, TEST_DATE); + + if (out[0] != 'h' || out[1] != 'e' || out[2] != 'l') + { + fail("wrong plain text in packet"); + } + + // + // create a PBE encrypted message and read it back. + // + byte[] text = { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)' ', (byte)'w', (byte)'o', (byte)'r', (byte)'l', (byte)'d', (byte)'!', (byte)'\n' }; + + // + // encryption step - convert to literal data, compress, encode. + // + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + Date cDate = new Date((System.currentTimeMillis() / 1000) * 1000); + PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator(); + OutputStream comOut = comData.open(new UncloseableOutputStream(bOut)); + OutputStream ldOut = lData.open( + new UncloseableOutputStream(comOut), + PGPLiteralData.BINARY, + PGPLiteralData.CONSOLE, + text.length, + cDate); + + ldOut.write(text); + + ldOut.close(); + + comOut.close(); + + // + // encrypt - with stream close + // + ByteArrayOutputStream cbOut = new ByteArrayOutputStream(); + PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setSecureRandom(new SecureRandom()).setProvider("SC")); + + cPk.addMethod(new JcePBEKeyEncryptionMethodGenerator(pass).setProvider("SC")); + + OutputStream cOut = cPk.open(new UncloseableOutputStream(cbOut), bOut.toByteArray().length); + + cOut.write(bOut.toByteArray()); + + cOut.close(); + + out = decryptMessage(cbOut.toByteArray(), cDate); + + if (!areEqual(out, text)) + { + fail("wrong plain text in generated packet"); + } + + // + // encrypt - with generator close + // + cbOut = new ByteArrayOutputStream(); + cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setSecureRandom(new SecureRandom()).setProvider("SC")); + + cPk.addMethod(new JcePBEKeyEncryptionMethodGenerator(pass).setProvider("SC")); + + cOut = cPk.open(new UncloseableOutputStream(cbOut), bOut.toByteArray().length); + + cOut.write(bOut.toByteArray()); + + cPk.close(); + + out = decryptMessage(cbOut.toByteArray(), cDate); + + if (!areEqual(out, text)) + { + fail("wrong plain text in generated packet"); + } + + // + // encrypt - partial packet style. + // + SecureRandom rand = new SecureRandom(); + byte[] test = new byte[1233]; + + rand.nextBytes(test); + + bOut = new ByteArrayOutputStream(); + + comData = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + comOut = comData.open(bOut); + lData = new PGPLiteralDataGenerator(); + + ldOut = lData.open(new UncloseableOutputStream(comOut), + PGPLiteralData.BINARY, PGPLiteralData.CONSOLE, TEST_DATE, + new byte[16]); + + + ldOut.write(test); + + ldOut.close(); + + comOut.close(); + + cbOut = new ByteArrayOutputStream(); + cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setSecureRandom(rand).setProvider("SC")); + + cPk.addMethod(new JcePBEKeyEncryptionMethodGenerator(pass).setProvider("SC")); + + cOut = cPk.open(new UncloseableOutputStream(cbOut), new byte[16]); + + cOut.write(bOut.toByteArray()); + + cOut.close(); + + out = decryptMessage(cbOut.toByteArray(), TEST_DATE); + if (!areEqual(out, test)) + { + fail("wrong plain text in generated packet"); + } + + // + // with integrity packet + // + cbOut = new ByteArrayOutputStream(); + cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(true).setSecureRandom(rand).setProvider("SC")); + + cPk.addMethod(new JcePBEKeyEncryptionMethodGenerator(pass).setProvider("SC")); + + cOut = cPk.open(new UncloseableOutputStream(cbOut), new byte[16]); + + cOut.write(bOut.toByteArray()); + + cOut.close(); + + out = decryptMessage(cbOut.toByteArray(), TEST_DATE); + if (!areEqual(out, test)) + { + fail("wrong plain text in generated packet"); + } + + // + // decrypt with buffering + // + out = decryptMessageBuffered(cbOut.toByteArray(), TEST_DATE); + if (!areEqual(out, test)) + { + fail("wrong plain text in buffer generated packet"); + } + + // + // sample message + // + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(testPBEAsym); + + PGPEncryptedDataList enc = (PGPEncryptedDataList)pgpFact.nextObject(); + + PGPPBEEncryptedData pbe = (PGPPBEEncryptedData)enc.get(1); + + InputStream clear = pbe.getDataStream(new JcePBEDataDecryptorFactoryBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build("password".toCharArray())); + + pgpFact = new JcaPGPObjectFactory(clear); + + PGPLiteralData ld = (PGPLiteralData)pgpFact.nextObject(); + + bOut = new ByteArrayOutputStream(); + InputStream unc = ld.getInputStream(); + int ch; + + while ((ch = unc.read()) >= 0) + { + bOut.write(ch); + } + + if (!areEqual(bOut.toByteArray(), Hex.decode("5361742031302e30322e30370d0a"))) + { + fail("data mismatch on combined PBE"); + } + + // + // with integrity packet - one byte message + // + byte[] msg = new byte[1]; + bOut = new ByteArrayOutputStream(); + + comData = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + lData = new PGPLiteralDataGenerator(); + comOut = comData.open(new UncloseableOutputStream(bOut)); + ldOut = lData.open( + new UncloseableOutputStream(comOut), + PGPLiteralData.BINARY, + PGPLiteralData.CONSOLE, + msg.length, + cDate); + + ldOut.write(msg); + + ldOut.close(); + + comOut.close(); + + cbOut = new ByteArrayOutputStream(); + cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(true).setSecureRandom(rand).setProvider("SC")); + + cPk.addMethod(new JcePBEKeyEncryptionMethodGenerator(pass).setProvider("SC")); + + cOut = cPk.open(new UncloseableOutputStream(cbOut), new byte[16]); + + cOut.write(bOut.toByteArray()); + + cOut.close(); + + out = decryptMessage(cbOut.toByteArray(), cDate); + if (!areEqual(out, msg)) + { + fail("wrong plain text in generated packet"); + } + + // + // decrypt with buffering + // + out = decryptMessageBuffered(cbOut.toByteArray(), cDate); + if (!areEqual(out, msg)) + { + fail("wrong plain text in buffer generated packet"); + } + } + + public String getName() + { + return "PGPPBETest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PGPPBETest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPPacketTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPPacketTest.java new file mode 100644 index 00000000..e7087942 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPPacketTest.java @@ -0,0 +1,103 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.Security; +import java.util.Date; +import java.util.Random; + +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPLiteralData; +import org.spongycastle.openpgp.PGPLiteralDataGenerator; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.util.test.SimpleTest; +import org.spongycastle.util.test.UncloseableOutputStream; + +public class PGPPacketTest + extends SimpleTest +{ + private static int MAX = 32000; + + private void readBackTest( + PGPLiteralDataGenerator generator) + throws IOException + { + Random rand = new Random(); + byte[] buf = new byte[MAX]; + + rand.nextBytes(buf); + + for (int i = 1; i <= 200; i++) + { + bufferTest(generator, buf, i); + } + + bufferTest(generator, buf, 8382); + bufferTest(generator, buf, 8383); + bufferTest(generator, buf, 8384); + bufferTest(generator, buf, 8385); + + for (int i = 200; i < MAX; i += 100) + { + bufferTest(generator, buf, i); + } + } + + private void bufferTest( + PGPLiteralDataGenerator generator, + byte[] buf, + int i) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream out = generator.open( + new UncloseableOutputStream(bOut), + PGPLiteralData.BINARY, + PGPLiteralData.CONSOLE, + i, + new Date()); + + out.write(buf, 0, i); + + generator.close(); + + JcaPGPObjectFactory fact = new JcaPGPObjectFactory(bOut.toByteArray()); + PGPLiteralData data = (PGPLiteralData)fact.nextObject(); + InputStream in = data.getInputStream(); + + for (int count = 0; count != i; count++) + { + if (in.read() != (buf[count] & 0xff)) + { + fail("failed readback test - length = " + i); + } + } + } + + public void performTest() + throws IOException + { + PGPLiteralDataGenerator oldGenerator = new PGPLiteralDataGenerator(true); + + readBackTest(oldGenerator); + + PGPLiteralDataGenerator newGenerator = new PGPLiteralDataGenerator(false); + + readBackTest(newGenerator); + } + + public String getName() + { + return "PGPPacketTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PGPPacketTest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPParsingTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPParsingTest.java new file mode 100644 index 00000000..764321c8 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPParsingTest.java @@ -0,0 +1,32 @@ +package org.spongycastle.openpgp.test; + +import java.security.Security; + +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPPublicKeyRingCollection; +import org.spongycastle.openpgp.PGPUtil; +import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; +import org.spongycastle.util.test.SimpleTest; + +public class PGPParsingTest + extends SimpleTest +{ + public void performTest() + throws Exception + { + PGPPublicKeyRingCollection pubRingCollection = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(this.getClass().getResourceAsStream("bigpub.asc")), new JcaKeyFingerprintCalculator()); + } + + public String getName() + { + return "PGPParsingTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PGPParsingTest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPRSATest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPRSATest.java new file mode 100644 index 00000000..ba5f88ba --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPRSATest.java @@ -0,0 +1,1489 @@ +package org.spongycastle.openpgp.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Date; +import java.util.Iterator; + +import javax.crypto.Cipher; + +import org.spongycastle.bcpg.BCPGOutputStream; +import org.spongycastle.bcpg.CompressionAlgorithmTags; +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.bcpg.PublicKeyAlgorithmTags; +import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.spongycastle.bcpg.attr.ImageAttribute; +import org.spongycastle.bcpg.sig.Features; +import org.spongycastle.bcpg.sig.KeyFlags; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPCompressedData; +import org.spongycastle.openpgp.PGPCompressedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedData; +import org.spongycastle.openpgp.PGPEncryptedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedDataList; +import org.spongycastle.openpgp.PGPKeyPair; +import org.spongycastle.openpgp.PGPKeyRingGenerator; +import org.spongycastle.openpgp.PGPLiteralData; +import org.spongycastle.openpgp.PGPLiteralDataGenerator; +import org.spongycastle.openpgp.PGPOnePassSignature; +import org.spongycastle.openpgp.PGPOnePassSignatureList; +import org.spongycastle.openpgp.PGPPBEEncryptedData; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVectorGenerator; +import org.spongycastle.openpgp.PGPUtil; +import org.spongycastle.openpgp.PGPV3SignatureGenerator; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.openpgp.operator.PGPDigestCalculator; +import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory; +import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyConverter; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair; +import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; +import org.spongycastle.util.test.UncloseableOutputStream; + +public class PGPRSATest + extends SimpleTest +{ + byte[] testPubKey = Base64.decode( + "mIsEPz2nJAEEAOTVqWMvqYE693qTgzKv/TJpIj3hI8LlYPC6m1dk0z3bDLwVVk9F" + + "FAB+CWS8RdFOWt/FG3tEv2nzcoNdRvjv9WALyIGNawtae4Ml6oAT06/511yUzXHO" + + "k+9xK3wkXN5jdzUhf4cA2oGpLSV/pZlocsIDL+jCUQtumUPwFodmSHhzAAYptC9F" + + "cmljIEVjaGlkbmEgKHRlc3Qga2V5KSA8ZXJpY0Bib3VuY3ljYXN0bGUub3JnPoi4" + + "BBMBAgAiBQI/PackAhsDBQkAg9YABAsHAwIDFQIDAxYCAQIeAQIXgAAKCRA1WGFG" + + "/fPzc8WMA/9BbjuB8E48QAlxoiVf9U8SfNelrz/ONJA/bMvWr/JnOGA9PPmFD5Uc" + + "+kV/q+i94dEMjsC5CQ1moUHWSP2xlQhbOzBP2+oPXw3z2fBs9XJgnTH6QWMAAvLs" + + "3ug9po0loNHLobT/D/XdXvcrb3wvwvPT2FptZqrtonH/OdzT9JdfrA=="); + + byte[] testPrivKey = Base64.decode( + "lQH8BD89pyQBBADk1aljL6mBOvd6k4Myr/0yaSI94SPC5WDwuptXZNM92wy8FVZP" + + "RRQAfglkvEXRTlrfxRt7RL9p83KDXUb47/VgC8iBjWsLWnuDJeqAE9Ov+ddclM1x" + + "zpPvcSt8JFzeY3c1IX+HANqBqS0lf6WZaHLCAy/owlELbplD8BaHZkh4cwAGKf4D" + + "AwKbLeIOVYTEdWD5v/YgW8ERs0pDsSIfBTvsJp2qA798KeFuED6jGsHUzdi1M990" + + "6PRtplQgnoYmYQrzEc6DXAiAtBR4Kuxi4XHx0ZR2wpVlVxm2Ypgz7pbBNWcWqzvw" + + "33inl7tR4IDsRdJOY8cFlN+1tSCf16sDidtKXUVjRjZNYJytH18VfSPlGXMeYgtw" + + "3cSGNTERwKaq5E/SozT2MKTiORO0g0Mtyz+9MEB6XVXFavMun/mXURqbZN/k9BFb" + + "z+TadpkihrLD1xw3Hp+tpe4CwPQ2GdWKI9KNo5gEnbkJgLrSMGgWalPhknlNHRyY" + + "bSq6lbIMJEE3LoOwvYWwweR1+GrV9farJESdunl1mDr5/d6rKru+FFDwZM3na1IF" + + "4Ei4FpqhivZ4zG6pN5XqLy+AK85EiW4XH0yAKX1O4YlbmDU4BjxhiwTdwuVMCjLO" + + "5++jkz5BBQWdFX8CCMA4FJl36G70IbGzuFfOj07ly7QvRXJpYyBFY2hpZG5hICh0" + + "ZXN0IGtleSkgPGVyaWNAYm91bmN5Y2FzdGxlLm9yZz6IuAQTAQIAIgUCPz2nJAIb" + + "AwUJAIPWAAQLBwMCAxUCAwMWAgECHgECF4AACgkQNVhhRv3z83PFjAP/QW47gfBO" + + "PEAJcaIlX/VPEnzXpa8/zjSQP2zL1q/yZzhgPTz5hQ+VHPpFf6voveHRDI7AuQkN" + + "ZqFB1kj9sZUIWzswT9vqD18N89nwbPVyYJ0x+kFjAALy7N7oPaaNJaDRy6G0/w/1" + + "3V73K298L8Lz09habWaq7aJx/znc0/SXX6w="); + + byte[] testPubKeyV3 = Base64.decode( + "mQCNAz+zvlEAAAEEAMS22jgXbOZ/D3xWgM2kauSdzrwlU7Ms5hDW05ObqQyO" + + "FfQoKKMhfupyoa7J3x04VVBKu6Eomvr1es+VImH0esoeWFFahNOYq/I+jRRB" + + "woOhAGZ5UB2/hRd7rFmxqp6sCXi8wmLO2tAorlTzAiNNvl7xF4cQZpc0z56F" + + "wdi2fBUJAAURtApGSVhDSVRZX1FBiQCVAwUQP7O+UZ6Fwdi2fBUJAQFMwwQA" + + "qRnFsdg4xQnB8Y5d4cOpXkIn9AZgYS3cxtuSJB84vG2CgC39nfv4c+nlLkWP" + + "4puG+mZuJNgVoE84cuAF4I//1anKjlU7q1M6rFQnt5S4uxPyG3dFXmgyU1b4" + + "PBOnA0tIxjPzlIhJAMsPCGGA5+5M2JP0ad6RnzqzE3EENMX+GqY="); + + byte[] testPrivKeyV3 = Base64.decode( + "lQHfAz+zvlEAAAEEAMS22jgXbOZ/D3xWgM2kauSdzrwlU7Ms5hDW05ObqQyO" + + "FfQoKKMhfupyoa7J3x04VVBKu6Eomvr1es+VImH0esoeWFFahNOYq/I+jRRB" + + "woOhAGZ5UB2/hRd7rFmxqp6sCXi8wmLO2tAorlTzAiNNvl7xF4cQZpc0z56F" + + "wdi2fBUJAAURAXWwRBZQHNikA/f0ScLLjrXi4s0hgQecg+dkpDow94eu5+AR" + + "0DzZnfurpgfUJCNiDi5W/5c3Zj/xyrfMAgkbCgJ1m6FZqAQh7Mq73l7Kfu4/" + + "XIkyDF3tDgRuZNezB+JuElX10tV03xumHepp6M6CfhXqNJ15F33F99TA5hXY" + + "CPYD7SiSOpIhQkCOAgDAA63imxbpuKE2W7Y4I1BUHB7WQi8ZdkZd04njNTv+" + + "rFUuOPapQVfbWG0Vq8ld3YmJB4QWsa2mmqn+qToXbwufAgBpXkjvqK5yPiHF" + + "Px2QbFc1VqoCJB6PO5JRIqEiUZBFGdDlLxt3VSyqz7IZ/zEnxZq+tPCGGGSm" + + "/sAGiMvENcHVAfy0kTXU42TxEAYJyyNyqjXOobDJpEV1mKhFskRXt7tbMfOS" + + "Yf91oX8f6xw6O2Nal+hU8dS0Bmfmk5/enHmvRLHQocO0CkZJWENJVFlfUUE="); + + byte[] sig1 = Base64.decode( + "owGbwMvMwMRoGpHo9vfz52LGNTJJnBmpOTn5eiUVJfb23JvAHIXy/KKcFEWuToap" + + "zKwMIGG4Bqav0SwMy3yParsEKi2LMGI9xhh65sBxb05n5++ZLcWNJ/eLFKdWbm95" + + "tHbDV7GMwj/tUctUpFUXWPYFCLdNsDiVNuXbQvZtdXV/5xzY+9w1nCnijH9JoNiJ" + + "22n2jo0zo30/TZLo+jDl2vTzIvPeLEsPM3ZUE/1Ytqs4SG2TxIQbH7xf3uzcYXq2" + + "5Fw9AA=="); + + byte[] sig1crc = Base64.decode("+3i0"); + + byte[] subKey = Base64.decode( + "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" + + "CphiUYWnsC0mQ+J15B4="); + + byte[] enc1 = Base64.decode( + "hIwDKwfQexPJboABA/4/7prhYYMORTiQ5avQKx0XYpCLujzGefYjnyuWZnx3Iev8" + + "Pmsguumm+OLLvtXhhkXQmkJRXbIg6Otj2ubPYWflRPgpJSgOrNOreOl5jeABOrtw" + + "bV6TJb9OTtZuB7cTQSCq2gmYiSZkluIiDjNs3R3mEanILbYzOQ3zKSggKpzlv9JQ" + + "AZUqTyDyJ6/OUbJF5fI5uiv76DCsw1zyMWotUIu5/X01q+AVP5Ly3STzI7xkWg/J" + + "APz4zUHism7kSYz2viAQaJx9/bNnH3AM6qm1Fuyikl4="); + + byte[] enc1crc = Base64.decode("lv4o"); + + byte[] enc2 = Base64.decode( + "hIwDKwfQexPJboABBAC62jcJH8xKnKb1neDVmiovYON04+7VQ2v4BmeHwJrdag1g" + + "Ya++6PeBlQ2Q9lSGBwLobVuJmQ7cOnPUJP727JeSGWlMyFtMbBSHekOaTenT5lj7" + + "Zk7oRHxMp/hByzlMacIDzOn8LPSh515RHM57eDLCOwqnAxGQwk67GRl8f5dFH9JQ" + + "Aa7xx8rjCqPbiIQW6t5LqCNvPZOiSCmftll6+se1XJhFEuq8WS4nXtPfTiJ3vib4" + + "3soJdHzGB6AOs+BQ6aKmmNTVAxa5owhtSt1Z/6dfSSk="); + + byte[] subPubKey = Base64.decode( + "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"); + + byte[] subPubCrc = Base64.decode("rikt"); + + byte[] pgp8Key = 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[] pgp8Pass = "2002 Buffalo Sabres".toCharArray(); + + char[] pass = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' }; + + byte[] fingerprintKey = Base64.decode( + "mQEPA0CiJdUAAAEIAMI+znDlPd2kQoEcnxqxLcRz56Z7ttFKHpnYp0UkljZdquVc" + + "By1jMfXGVV64xN1IvMcyenLXUE0IUeUBCQs6tHunFRAPSeCxJ3FdFe1B5MpqQG8A" + + "BnEpAds/hAUfRDZD5y/lolk1hjvFMrRh6WXckaA/QQ2t00NmTrJ1pYUpkw9tnVQb" + + "LUjWJhfZDBBcN0ADtATzgkugxMtcDxR6I5x8Ndn+IilqIm23kxGIcmMd/BHOec4c" + + "jRwJXXDb7u8tl+2knAf9cwhPHp3+Zy4uGSQPdzQnXOhBlA+4WDa0RROOevWgq8uq" + + "8/9Xp/OlTVL+OoIzjsI6mJP1Joa4qmqAnaHAmXcAEQEAAbQoQk9BM1JTS1kgPEJP" + + "QSBNb25pdG9yaW5nIEAgODg4LTI2OS01MjY2PokBFQMFEECiJdWqaoCdocCZdwEB" + + "0RsH/3HPxoUZ3G3K7T3jgOnJUckTSHWU3XspHzMVgqOxjTrcexi5IsAM5M+BulfW" + + "T2aO+Kqf5w8cKTKgW02DNpHUiPjHx0nzDE+Do95zbIErGeK+Twkc4O/aVsvU9GGO" + + "81VFI6WMvDQ4CUAUnAdk03MRrzI2nAuhn4NJ5LQS+uJrnqUJ4HmFAz6CQZQKd/kS" + + "Xgq+A6i7aI1LG80YxWa9ooQgaCrb9dwY/kPQ+yC22zQ3FExtv+Fv3VtAKTilO3vn" + + "BA4Y9uTHuObHfI+1yxUS2PrlRUX0m48ZjpIX+cEN3QblGBJudI/A1QSd6P0LZeBr" + + "7F1Z1aF7ZDo0KzgiAIBvgXkeTpw="); + + byte[] fingerprintCheck = Base64.decode("CTv2"); + + byte[] expiry60and30daysSig13Key = Base64.decode( + "mQGiBENZt/URBAC5JccXiwe4g6MuviEC8NI/x0NaVkGFAOY04d5E4jeIycBP" + + "SrpOPrjETuigqhrj8oqed2+2yUqfnK4nhTsTAjyeJ3PpWC1pGAKzJgYmJk+K" + + "9aTLq0BQWiXDdv5RG6fDmeq1umvOfcXBqGFAguLPZC+U872bSLnfe3lqGNA8" + + "jvmY7wCgjhzVQVm10NN5ST8nemPEcSjnBrED/R494gHL6+r5OgUgXnNCDejA" + + "4InoDImQCF+g7epp5E1MB6CMYSg2WSY2jHFuHpwnUb7AiOO0ZZ3UBqM9rYnK" + + "kDvxkFCxba7Ms+aFj9blRNmy3vG4FewDcTdxzCtjUk6dRfu6UoARpqlTE/q7" + + "Xo6EQP1ncwJ+UTlcHkTBvg/usI/yBACGjBqX8glb5VfNaZgNHMeS/UIiUiuV" + + "SVFojiSDOHcnCe/6y4M2gVm38zz1W9qhoLfLpiAOFeL0yj6wzXvsjjXQiKQ8" + + "nBE4Mf+oeH2qiQ/LfzQrGpI5eNcMXrzK9nigmz2htYO2GjQfupEnu1RHBTH8" + + "NjofD2AShL9IO73plRuExrQgVGVzdCBLZXkgPHRlc3RAYm91bmN5Y2FzdGxl" + + "Lm9yZz6IZAQTEQIAJAIbAwYLCQgHAwIDFQIDAxYCAQIeAQIXgAUCQ1m4DgUJ" + + "AE8aGQAKCRD8QP1QuU7Kqw+eAJ0dZ3ZAqr73X61VmCkbyPoszLQMAQCfdFs2" + + "YMDeUvX34Q/8Ba0KgO5f3RSwAgADuM0EQ1m39hADAIHpVGcLqS9UkmQaWBvH" + + "WP6TnN7Y1Ha0TJOuxpbFjBW+CmVh/FjcsnavFXDXpo2zc742WT+vrHBSa/0D" + + "1QEBsnCaX5SRRVp7Mqs8q+aDhjcHMIP8Sdxf7GozXDORkrRaJwADBQL9HLYm" + + "7Rr5iYWDcvs+Pi6O1zUyb1tjkxEGaV/rcozl2MMmr2mzJ6x/Bz8SuhZEJS0m" + + "bB2CvAA39aQi9jHlV7q0SV73NOkd2L/Vt2UZhzlUdvrJ37PgYDv+Wd9Ufz6g" + + "MzLSiE8EGBECAA8FAkNZt/YCGwwFCQAnjQAACgkQ/ED9ULlOyqsTqQCcDnAZ" + + "7YymCfhm1yJiuFQg3qiX6Z4An19OSEgeSKugVcH49g1sxUB0zNdIsAIAAw=="); + + byte[] jpegImage = Base64.decode( + "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"); + + byte[] embeddedJPEGKey = Base64.decode( + "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" + + "Qvmtc8X7lqK/zLRVkSSBItik2IIhsAIAAw=="); + + + private void fingerPrintTest() + throws Exception + { + // + // version 3 + // + PGPPublicKeyRing pgpPub = new PGPPublicKeyRing(fingerprintKey, new JcaKeyFingerprintCalculator()); + + PGPPublicKey pubKey = pgpPub.getPublicKey(); + + if (!areEqual(pubKey.getFingerprint(), Hex.decode("4FFB9F0884266C715D1CEAC804A3BBFA"))) + { + fail("version 3 fingerprint test failed"); + } + + // + // version 4 + // + pgpPub = new PGPPublicKeyRing(testPubKey, new JcaKeyFingerprintCalculator()); + + pubKey = pgpPub.getPublicKey(); + + if (!areEqual(pubKey.getFingerprint(), Hex.decode("3062363c1046a01a751946bb35586146fdf3f373"))) + { + fail("version 4 fingerprint test failed"); + } + } + + private void mixedTest(PGPPrivateKey pgpPrivKey, PGPPublicKey pgpPubKey) + throws Exception + { + byte[] text = { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)' ', (byte)'w', (byte)'o', (byte)'r', (byte)'l', (byte)'d', (byte)'!', (byte)'\n' }; + + // + // literal data + // + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); + OutputStream lOut = lGen.open(bOut, PGPLiteralData.BINARY, PGPLiteralData.CONSOLE, text.length, new Date()); + + lOut.write(text); + + lGen.close(); + + byte[] bytes = bOut.toByteArray(); + + JcaPGPObjectFactory f = new JcaPGPObjectFactory(bytes); + checkLiteralData((PGPLiteralData)f.nextObject(), text); + + ByteArrayOutputStream bcOut = new ByteArrayOutputStream(); + + PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_128).setWithIntegrityPacket(true).setSecureRandom(new SecureRandom()).setProvider("SC")); + + encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(pgpPubKey).setProvider("SC")); + + encGen.addMethod(new JcePBEKeyEncryptionMethodGenerator("password".toCharArray()).setProvider("SC")); + + OutputStream cOut = encGen.open(bcOut, bytes.length); + + cOut.write(bytes); + + cOut.close(); + + byte[] encData = bcOut.toByteArray(); + + // + // asymmetric + // + JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(encData); + + PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpF.nextObject(); + + PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0); + + InputStream clear = encP.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("SC").build(pgpPrivKey)); + + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(clear); + + checkLiteralData((PGPLiteralData)pgpFact.nextObject(), text); + + // + // PBE + // + pgpF = new JcaPGPObjectFactory(encData); + + encList = (PGPEncryptedDataList)pgpF.nextObject(); + + PGPPBEEncryptedData encPbe = (PGPPBEEncryptedData)encList.get(1); + + clear = encPbe.getDataStream(new JcePBEDataDecryptorFactoryBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build("password".toCharArray())); + + pgpF = new JcaPGPObjectFactory(clear); + + checkLiteralData((PGPLiteralData)pgpF.nextObject(), text); + } + + private void checkLiteralData(PGPLiteralData ld, byte[] data) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + if (!ld.getFileName().equals(PGPLiteralData.CONSOLE)) + { + throw new RuntimeException("wrong filename in packet"); + } + + InputStream inLd = ld.getDataStream(); + int ch; + + while ((ch = inLd.read()) >= 0) + { + bOut.write(ch); + } + + if (!areEqual(bOut.toByteArray(), data)) + { + fail("wrong plain text in decrypted packet"); + } + } + + private void existingEmbeddedJpegTest() + throws Exception + { + PGPPublicKeyRing pgpPub = new PGPPublicKeyRing(embeddedJPEGKey, new JcaKeyFingerprintCalculator()); + + PGPPublicKey pubKey = pgpPub.getPublicKey(); + + Iterator it = pubKey.getUserAttributes(); + int count = 0; + while (it.hasNext()) + { + PGPUserAttributeSubpacketVector attributes = (PGPUserAttributeSubpacketVector)it.next(); + + Iterator sigs = pubKey.getSignaturesForUserAttribute(attributes); + int sigCount = 0; + while (sigs.hasNext()) + { + PGPSignature sig = (PGPSignature)sigs.next(); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pubKey); + + if (!sig.verifyCertification(attributes, pubKey)) + { + fail("signature failed verification"); + } + + sigCount++; + } + + if (sigCount != 1) + { + fail("Failed user attributes signature check"); + } + count++; + } + + if (count != 1) + { + fail("didn't find user attributes"); + } + } + + private void embeddedJpegTest() + throws Exception + { + PGPPublicKeyRing pgpPub = new PGPPublicKeyRing(testPubKey, new JcaKeyFingerprintCalculator()); + PGPSecretKeyRing pgpSec = new PGPSecretKeyRing(testPrivKey, new JcaKeyFingerprintCalculator()); + + PGPPublicKey pubKey = pgpPub.getPublicKey(); + + PGPUserAttributeSubpacketVectorGenerator vGen = new PGPUserAttributeSubpacketVectorGenerator(); + + vGen.setImageAttribute(ImageAttribute.JPEG, jpegImage); + + PGPUserAttributeSubpacketVector uVec = vGen.generate(); + + PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1).setProvider("SC")); + + sGen.init(PGPSignature.POSITIVE_CERTIFICATION, pgpSec.getSecretKey().extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(pass))); + + PGPSignature sig = sGen.generateCertification(uVec, pubKey); + + PGPPublicKey nKey = PGPPublicKey.addCertification(pubKey, uVec, sig); + + Iterator it = nKey.getUserAttributes(); + int count = 0; + while (it.hasNext()) + { + PGPUserAttributeSubpacketVector attributes = (PGPUserAttributeSubpacketVector)it.next(); + + Iterator sigs = nKey.getSignaturesForUserAttribute(attributes); + int sigCount = 0; + while (sigs.hasNext()) + { + PGPSignature s = (PGPSignature)sigs.next(); + + s.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pubKey); + + if (!s.verifyCertification(attributes, pubKey)) + { + fail("added signature failed verification"); + } + + sigCount++; + } + + if (sigCount != 1) + { + fail("Failed added user attributes signature check"); + } + count++; + } + + if (count != 1) + { + fail("didn't find added user attributes"); + } + + nKey = PGPPublicKey.removeCertification(nKey, uVec); + count = 0; + for (it = nKey.getUserAttributes(); it.hasNext();) + { + count++; + } + if (count != 0) + { + fail("found attributes where none expected"); + } + } + + private void sigsubpacketTest() + throws Exception + { + char[] passPhrase = "test".toCharArray(); + String identity = "TEST <test@test.org>"; + Date date = new Date(); + Security.addProvider(new BouncyCastleProvider()); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "SC"); + kpg.initialize(2048); + KeyPair kpSgn = kpg.generateKeyPair(); + KeyPair kpEnc = kpg.generateKeyPair(); + + PGPKeyPair sgnKeyPair = new JcaPGPKeyPair(PGPPublicKey.RSA_SIGN, kpSgn, date); + PGPKeyPair encKeyPair = new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, kpEnc, date); + + PGPSignatureSubpacketVector unhashedPcks = null; + PGPSignatureSubpacketGenerator svg = new PGPSignatureSubpacketGenerator(); + svg.setKeyExpirationTime(true, 86400L * 366 * 2); + svg.setPrimaryUserID(true, true); + int[] encAlgs = {SymmetricKeyAlgorithmTags.AES_256, + SymmetricKeyAlgorithmTags.AES_192, + SymmetricKeyAlgorithmTags.TRIPLE_DES}; + svg.setPreferredSymmetricAlgorithms(true, encAlgs); + int[] hashAlgs = {HashAlgorithmTags.SHA1, + HashAlgorithmTags.SHA512, + HashAlgorithmTags.SHA384, + HashAlgorithmTags.SHA256, + HashAlgorithmTags.RIPEMD160}; + svg.setPreferredHashAlgorithms(true, hashAlgs); + int[] comprAlgs = {CompressionAlgorithmTags.ZLIB, + CompressionAlgorithmTags.BZIP2, + CompressionAlgorithmTags.ZIP}; + svg.setPreferredCompressionAlgorithms(true, comprAlgs); + svg.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION); + svg.setKeyFlags(true, KeyFlags.CERTIFY_OTHER + KeyFlags.SIGN_DATA); + PGPSignatureSubpacketVector hashedPcks = svg.generate(); + + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, sgnKeyPair, + identity, sha1Calc, hashedPcks, unhashedPcks, new JcaPGPContentSignerBuilder(PGPPublicKey.RSA_SIGN, HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256).setProvider("SC").build(passPhrase)); + + svg = new PGPSignatureSubpacketGenerator(); + svg.setKeyExpirationTime(true, 86400L * 366 * 2); + svg.setKeyFlags(true, KeyFlags.ENCRYPT_COMMS + KeyFlags.ENCRYPT_STORAGE); + svg.setPrimaryUserID(true, false); + svg.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION); + hashedPcks = svg.generate(); + + keyRingGen.addSubKey(encKeyPair, hashedPcks, unhashedPcks); + + byte[] encodedKeyRing = keyRingGen.generatePublicKeyRing().getEncoded(); + + PGPPublicKeyRing keyRing = new PGPPublicKeyRing(encodedKeyRing, new JcaKeyFingerprintCalculator()); + + for (Iterator it = keyRing.getPublicKeys(); it.hasNext();) + { + PGPPublicKey pKey = (PGPPublicKey)it.next(); + + if (pKey.isEncryptionKey()) + { + for (Iterator sit = pKey.getSignatures(); sit.hasNext();) + { + PGPSignature sig = (PGPSignature)sit.next(); + PGPSignatureSubpacketVector v = sig.getHashedSubPackets(); + + if (v.getKeyExpirationTime() != 86400L * 366 * 2) + { + fail("key expiration time wrong"); + } + if (!v.getFeatures().supportsFeature(Features.FEATURE_MODIFICATION_DETECTION)) + { + fail("features wrong"); + } + if (v.isPrimaryUserID()) + { + fail("primary userID flag wrong"); + } + if (v.getKeyFlags() != KeyFlags.ENCRYPT_COMMS + KeyFlags.ENCRYPT_STORAGE) + { + fail("keyFlags wrong"); + } + } + } + else + { + for (Iterator sit = pKey.getSignatures(); sit.hasNext();) + { + PGPSignature sig = (PGPSignature)sit.next(); + PGPSignatureSubpacketVector v = sig.getHashedSubPackets(); + + if (!Arrays.areEqual(v.getPreferredSymmetricAlgorithms(), encAlgs)) + { + fail("preferred encryption algs don't match"); + } + if (!Arrays.areEqual(v.getPreferredHashAlgorithms(), hashAlgs)) + { + fail("preferred hash algs don't match"); + } + if (!Arrays.areEqual(v.getPreferredCompressionAlgorithms(), comprAlgs)) + { + fail("preferred compression algs don't match"); + } + if (!v.getFeatures().supportsFeature(Features.FEATURE_MODIFICATION_DETECTION)) + { + fail("features wrong"); + } + if (v.getKeyFlags() != KeyFlags.CERTIFY_OTHER + KeyFlags.SIGN_DATA) + { + fail("keyFlags wrong"); + } + } + } + } + } + + private void multipleExpiryTest() + throws Exception + { + char[] passPhrase = "test".toCharArray(); + String identity = "TEST <test@test.org>"; + Date date = new Date(); + Security.addProvider(new BouncyCastleProvider()); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "SC"); + kpg.initialize(2048); + KeyPair kpSgn = kpg.generateKeyPair(); + KeyPair kpEnc = kpg.generateKeyPair(); + + PGPKeyPair sgnKeyPair = new JcaPGPKeyPair(PGPPublicKey.RSA_SIGN, kpSgn, date); + PGPKeyPair encKeyPair = new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL, kpEnc, date); + + PGPSignatureSubpacketVector unhashedPcks = null; + PGPSignatureSubpacketGenerator svg = new PGPSignatureSubpacketGenerator(); + svg.setKeyExpirationTime(true, 86400L * 366 * 2); + svg.setPrimaryUserID(true, true); + int[] encAlgs = {SymmetricKeyAlgorithmTags.AES_256, + SymmetricKeyAlgorithmTags.AES_192, + SymmetricKeyAlgorithmTags.TRIPLE_DES}; + svg.setPreferredSymmetricAlgorithms(true, encAlgs); + int[] hashAlgs = {HashAlgorithmTags.SHA1, + HashAlgorithmTags.SHA512, + HashAlgorithmTags.SHA384, + HashAlgorithmTags.SHA256, + HashAlgorithmTags.RIPEMD160}; + svg.setPreferredHashAlgorithms(true, hashAlgs); + int[] comprAlgs = {CompressionAlgorithmTags.ZLIB, + CompressionAlgorithmTags.BZIP2, + CompressionAlgorithmTags.ZIP}; + svg.setPreferredCompressionAlgorithms(true, comprAlgs); + svg.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION); + svg.setKeyFlags(true, KeyFlags.CERTIFY_OTHER + KeyFlags.SIGN_DATA); + + PGPSignatureSubpacketVector hashedPcks = svg.generate(); + + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1); + PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, + sgnKeyPair, identity, + sha1Calc, hashedPcks, unhashedPcks, new JcaPGPContentSignerBuilder(sgnKeyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1), new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256).setProvider("SC").build(passPhrase)); + + svg = new PGPSignatureSubpacketGenerator(); + svg.setKeyExpirationTime(true, 86400L * 366 * 2); + svg.setKeyFlags(true, KeyFlags.ENCRYPT_COMMS + KeyFlags.ENCRYPT_STORAGE); + svg.setPrimaryUserID(true, false); + svg.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION); + hashedPcks = svg.generate(); + + keyRingGen.addSubKey(encKeyPair, hashedPcks, unhashedPcks); + + byte[] encodedKeyRing = keyRingGen.generatePublicKeyRing().getEncoded(); + + PGPPublicKeyRing keyRing = new PGPPublicKeyRing(encodedKeyRing, new JcaKeyFingerprintCalculator()); + + for (Iterator it = keyRing.getPublicKeys(); it.hasNext();) + { + PGPPublicKey pKey = (PGPPublicKey)it.next(); + + PGPSignatureGenerator keySigGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(PGPPublicKey.RSA_SIGN, HashAlgorithmTags.SHA1).setProvider("SC")); + + if (pKey.isMasterKey()) + { + keySigGen.init(PGPSignature.POSITIVE_CERTIFICATION, sgnKeyPair.getPrivateKey()); + } + else + { + keySigGen.init(PGPSignature.SUBKEY_BINDING, sgnKeyPair.getPrivateKey()); + } + + svg = new PGPSignatureSubpacketGenerator(); + + svg.setKeyExpirationTime(true, 86400L * 366 * 3); + + keySigGen.setHashedSubpackets(svg.generate()); + + pKey = PGPPublicKey.addCertification(pKey, pKey.isMasterKey() ? keySigGen.generateCertification(pKey) : keySigGen.generateCertification(sgnKeyPair.getPublicKey(), pKey)); + + if (pKey.isEncryptionKey()) + { + if (pKey.getValidSeconds() != 86400L * 366 * 3) + { + fail("key expiration time wrong"); + } + } + else + { + if (pKey.getValidSeconds() != 86400L * 366 * 3) + { + fail("key expiration time wrong"); + } + } + } + } + + public void performTest() + throws Exception + { + PublicKey pubKey = null; + + // + // Read the public key + // + PGPPublicKeyRing pgpPub = new PGPPublicKeyRing(testPubKey, new JcaKeyFingerprintCalculator()); + + pubKey = new JcaPGPKeyConverter().setProvider("SC").getPublicKey(pgpPub.getPublicKey()); + + Iterator it = pgpPub.getPublicKey().getUserIDs(); + + String uid = (String)it.next(); + + it = pgpPub.getPublicKey().getSignaturesForID(uid); + + PGPSignature sig = (PGPSignature)it.next(); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pgpPub.getPublicKey()); + + if (!sig.verifyCertification(uid, pgpPub.getPublicKey())) + { + fail("failed to verify certification"); + } + + // + // write a public key + // + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut); + + pgpPub.encode(pOut); + + if (!areEqual(bOut.toByteArray(), testPubKey)) + { + fail("public key rewrite failed"); + } + + // + // Read the public key + // + PGPPublicKeyRing pgpPubV3 = new PGPPublicKeyRing(testPubKeyV3, new JcaKeyFingerprintCalculator()); + PublicKey pubKeyV3 = new JcaPGPKeyConverter().setProvider("SC").getPublicKey(pgpPub.getPublicKey()); + + // + // write a V3 public key + // + bOut = new ByteArrayOutputStream(); + pOut = new BCPGOutputStream(bOut); + + pgpPubV3.encode(pOut); + + // + // Read a v3 private key + // + char[] passP = "FIXCITY_QA".toCharArray(); + + if (!noIDEA()) + { + PGPSecretKeyRing pgpPriv = new PGPSecretKeyRing(testPrivKeyV3, new JcaKeyFingerprintCalculator()); + PGPPrivateKey pgpPrivKey = pgpPriv.getSecretKey().extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(passP)); + + // + // write a v3 private key + // + bOut = new ByteArrayOutputStream(); + pOut = new BCPGOutputStream(bOut); + + pgpPriv.encode(pOut); + + if (!areEqual(bOut.toByteArray(), testPrivKeyV3)) + { + fail("private key V3 rewrite failed"); + } + } + + // + // Read the private key + // + PGPSecretKeyRing pgpPriv = new PGPSecretKeyRing(testPrivKey, new JcaKeyFingerprintCalculator()); + PGPPrivateKey pgpPrivKey = pgpPriv.getSecretKey().extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(pass)); + + // + // write a private key + // + bOut = new ByteArrayOutputStream(); + pOut = new BCPGOutputStream(bOut); + + pgpPriv.encode(pOut); + + if (!areEqual(bOut.toByteArray(), testPrivKey)) + { + fail("private key rewrite failed"); + } + + + // + // test encryption + // + Cipher c = Cipher.getInstance("RSA", "SC"); + + c.init(Cipher.ENCRYPT_MODE, pubKey); + + byte[] in = "hello world".getBytes(); + + byte[] out = c.doFinal(in); + + c.init(Cipher.DECRYPT_MODE, new JcaPGPKeyConverter().setProvider("SC").getPrivateKey(pgpPrivKey)); + + out = c.doFinal(out); + + if (!areEqual(in, out)) + { + fail("decryption failed."); + } + + // + // test signature message + // + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(sig1); + + PGPCompressedData c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + PGPOnePassSignatureList p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + + PGPOnePassSignature ops = p1.get(0); + + PGPLiteralData p2 = (PGPLiteralData)pgpFact.nextObject(); + + InputStream dIn = p2.getInputStream(); + int ch; + + ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pgpPub.getPublicKey(ops.getKeyID())); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + PGPSignatureList p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed signature check"); + } + + // + // encrypted message - read subkey + // + pgpPriv = new PGPSecretKeyRing(subKey, new JcaKeyFingerprintCalculator()); + + // + // encrypted message + // + byte[] text = { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)' ', (byte)'w', (byte)'o', (byte)'r', (byte)'l', (byte)'d', (byte)'!', (byte)'\n' }; + + JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(enc1); + + PGPEncryptedDataList encList = (PGPEncryptedDataList)pgpF.nextObject(); + + PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0); + + pgpPrivKey = pgpPriv.getSecretKey(encP.getKeyID()).extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(pass)); + + InputStream clear = encP.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("SC").build(pgpPrivKey)); + + pgpFact = new JcaPGPObjectFactory(clear); + + c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + PGPLiteralData ld = (PGPLiteralData)pgpFact.nextObject(); + + bOut = new ByteArrayOutputStream(); + + if (!ld.getFileName().equals("test.txt")) + { + throw new RuntimeException("wrong filename in packet"); + } + + InputStream inLd = ld.getDataStream(); + + while ((ch = inLd.read()) >= 0) + { + bOut.write(ch); + } + + if (!areEqual(bOut.toByteArray(), text)) + { + fail("wrong plain text in decrypted packet"); + } + + // + // encrypt - short message + // + byte[] shortText = { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o' }; + + ByteArrayOutputStream cbOut = new ByteArrayOutputStream(); + PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5).setSecureRandom(new SecureRandom()).setProvider("SC")); + PGPPublicKey puK = pgpPriv.getSecretKey(encP.getKeyID()).getPublicKey(); + + cPk.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(puK).setProvider("SC")); + + OutputStream cOut = cPk.open(new UncloseableOutputStream(cbOut), shortText.length); + + cOut.write(shortText); + + cOut.close(); + + pgpF = new JcaPGPObjectFactory(cbOut.toByteArray()); + + encList = (PGPEncryptedDataList)pgpF.nextObject(); + + encP = (PGPPublicKeyEncryptedData)encList.get(0); + + pgpPrivKey = pgpPriv.getSecretKey(encP.getKeyID()).extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(pass)); + + PublicKeyDataDecryptorFactory dataDecryptorFactory = new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("SC").build(pgpPrivKey); + if (encP.getSymmetricAlgorithm(dataDecryptorFactory) != SymmetricKeyAlgorithmTags.CAST5) + { + fail("symmetric algorithm mismatch"); + } + + clear = encP.getDataStream(dataDecryptorFactory); + + bOut.reset(); + + while ((ch = clear.read()) >= 0) + { + bOut.write(ch); + } + + out = bOut.toByteArray(); + + if (!areEqual(out, shortText)) + { + fail("wrong plain text in generated short text packet"); + } + + // + // encrypt + // + cbOut = new ByteArrayOutputStream(); + cPk = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5).setSecureRandom(new SecureRandom()).setProvider("SC")); + puK = pgpPriv.getSecretKey(encP.getKeyID()).getPublicKey(); + + cPk.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(puK).setProvider("SC")); + + cOut = cPk.open(new UncloseableOutputStream(cbOut), text.length); + + cOut.write(text); + + cOut.close(); + + pgpF = new JcaPGPObjectFactory(cbOut.toByteArray()); + + encList = (PGPEncryptedDataList)pgpF.nextObject(); + + encP = (PGPPublicKeyEncryptedData)encList.get(0); + + pgpPrivKey = pgpPriv.getSecretKey(encP.getKeyID()).extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(pass)); + + clear = encP.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("SC").build(pgpPrivKey)); + + bOut.reset(); + + while ((ch = clear.read()) >= 0) + { + bOut.write(ch); + } + + out = bOut.toByteArray(); + + if (!areEqual(out, text)) + { + fail("wrong plain text in generated packet"); + } + + // + // read public key with sub key. + // + pgpF = new JcaPGPObjectFactory(subPubKey); + Object o; + + while ((o = pgpFact.nextObject()) != null) + { + // System.out.println(o); + } + + // + // key pair generation - CAST5 encryption + // + char[] passPhrase = "hello".toCharArray(); + + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "SC"); + + kpg.initialize(1024); + + KeyPair kp = kpg.generateKeyPair(); + + PGPSecretKey secretKey = new PGPSecretKey( + PGPSignature.DEFAULT_CERTIFICATION, + new JcaPGPKeyPair(PublicKeyAlgorithmTags.RSA_GENERAL, kp, new Date()), "fred", + null, null, new JcaPGPContentSignerBuilder(PublicKeyAlgorithmTags.RSA_SIGN, HashAlgorithmTags.SHA1).setProvider("SC"), + new JcePBESecretKeyEncryptorBuilder(SymmetricKeyAlgorithmTags.CAST5).build(passPhrase)); + + PGPPublicKey key = secretKey.getPublicKey(); + + it = key.getUserIDs(); + + uid = (String)it.next(); + + it = key.getSignaturesForID(uid); + + sig = (PGPSignature)it.next(); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), key); + + if (!sig.verifyCertification(uid, key)) + { + fail("failed to verify certification"); + } + + pgpPrivKey = secretKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(passPhrase)); + + key = PGPPublicKey.removeCertification(key, uid, sig); + + if (key == null) + { + fail("failed certification removal"); + } + + byte[] keyEnc = key.getEncoded(); + + key = PGPPublicKey.addCertification(key, uid, sig); + + keyEnc = key.getEncoded(); + + PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1).setProvider("SC")); + + sGen.init(PGPSignature.KEY_REVOCATION, secretKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(passPhrase))); + + sig = sGen.generateCertification(key); + + key = PGPPublicKey.addCertification(key, sig); + + keyEnc = key.getEncoded(); + + PGPPublicKeyRing tmpRing = new PGPPublicKeyRing(keyEnc, new JcaKeyFingerprintCalculator()); + + key = tmpRing.getPublicKey(); + + Iterator sgIt = key.getSignaturesOfType(PGPSignature.KEY_REVOCATION); + + sig = (PGPSignature)sgIt.next(); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), key); + + if (!sig.verifyCertification(key)) + { + fail("failed to verify revocation certification"); + } + + // + // use of PGPKeyPair + // + PGPKeyPair pgpKp = new JcaPGPKeyPair(PGPPublicKey.RSA_GENERAL , kp, new Date()); + + PGPPublicKey k1 = pgpKp.getPublicKey(); + + PGPPrivateKey k2 = pgpKp.getPrivateKey(); + + k1.getEncoded(); + + mixedTest(k2, k1); + + // + // key pair generation - AES_256 encryption. + // + kp = kpg.generateKeyPair(); + + secretKey = new PGPSecretKey( + PGPSignature.DEFAULT_CERTIFICATION, + new JcaPGPKeyPair(PublicKeyAlgorithmTags.RSA_GENERAL, kp, new Date()), "fred", + null, null, new JcaPGPContentSignerBuilder(PublicKeyAlgorithmTags.RSA_SIGN, HashAlgorithmTags.SHA1).setProvider("SC"), + new JcePBESecretKeyEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256).build(passPhrase)); + + secretKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(passPhrase)); + + secretKey.encode(new ByteArrayOutputStream()); + + // + // secret key password changing. + // + String newPass = "newPass"; + + secretKey = PGPSecretKey.copyWithNewPassword(secretKey, new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(passPhrase), new JcePBESecretKeyEncryptorBuilder(secretKey.getKeyEncryptionAlgorithm()).setProvider("SC").setSecureRandom(new SecureRandom()).build(newPass.toCharArray())); + + secretKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(newPass.toCharArray())); + + secretKey.encode(new ByteArrayOutputStream()); + + key = secretKey.getPublicKey(); + + key.encode(new ByteArrayOutputStream()); + + it = key.getUserIDs(); + + uid = (String)it.next(); + + it = key.getSignaturesForID(uid); + + sig = (PGPSignature)it.next(); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), key); + + if (!sig.verifyCertification(uid, key)) + { + fail("failed to verify certification"); + } + + pgpPrivKey = secretKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(newPass.toCharArray())); + + // + // signature generation + // + String data = "hello world!"; + + bOut = new ByteArrayOutputStream(); + + ByteArrayInputStream testIn = new ByteArrayInputStream(data.getBytes()); + + sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1).setProvider("SC")); + + sGen.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey); + + PGPCompressedDataGenerator cGen = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + BCPGOutputStream bcOut = new BCPGOutputStream( + cGen.open(new UncloseableOutputStream(bOut))); + + sGen.generateOnePassVersion(false).encode(bcOut); + + PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator(); + + Date testDate = new Date((System.currentTimeMillis() / 1000) * 1000); + OutputStream lOut = lGen.open( + new UncloseableOutputStream(bcOut), + PGPLiteralData.BINARY, + "_CONSOLE", + data.getBytes().length, + testDate); + + while ((ch = testIn.read()) >= 0) + { + lOut.write(ch); + sGen.update((byte)ch); + } + + lOut.close(); + + sGen.generate().encode(bcOut); + + bcOut.close(); + + // + // verify generated signature + // + pgpFact = new JcaPGPObjectFactory(bOut.toByteArray()); + + c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + + ops = p1.get(0); + + p2 = (PGPLiteralData)pgpFact.nextObject(); + if (!p2.getModificationTime().equals(testDate)) + { + fail("Modification time not preserved: " + p2.getModificationTime() + " " + testDate); + } + + dIn = p2.getInputStream(); + + ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), secretKey.getPublicKey()); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed generated signature check"); + } + + // + // signature generation - version 3 + // + bOut = new ByteArrayOutputStream(); + + testIn = new ByteArrayInputStream(data.getBytes()); + PGPV3SignatureGenerator sGenV3 = new PGPV3SignatureGenerator(new JcaPGPContentSignerBuilder(PGPPublicKey.RSA_GENERAL, PGPUtil.SHA1).setProvider("SC")); + + sGenV3.init(PGPSignature.BINARY_DOCUMENT, pgpPrivKey); + + cGen = new PGPCompressedDataGenerator( + PGPCompressedData.ZIP); + + bcOut = new BCPGOutputStream(cGen.open(bOut)); + + sGenV3.generateOnePassVersion(false).encode(bcOut); + + lGen = new PGPLiteralDataGenerator(); + lOut = lGen.open( + new UncloseableOutputStream(bcOut), + PGPLiteralData.BINARY, + "_CONSOLE", + data.getBytes().length, + testDate); + + while ((ch = testIn.read()) >= 0) + { + lOut.write(ch); + sGenV3.update((byte)ch); + } + + lOut.close(); + + sGenV3.generate().encode(bcOut); + + bcOut.close(); + + // + // verify generated signature + // + pgpFact = new JcaPGPObjectFactory(bOut.toByteArray()); + + c1 = (PGPCompressedData)pgpFact.nextObject(); + + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + + p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + + ops = p1.get(0); + + p2 = (PGPLiteralData)pgpFact.nextObject(); + if (!p2.getModificationTime().equals(testDate)) + { + fail("Modification time not preserved"); + } + + dIn = p2.getInputStream(); + + ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), secretKey.getPublicKey()); + + while ((ch = dIn.read()) >= 0) + { + ops.update((byte)ch); + } + + p3 = (PGPSignatureList)pgpFact.nextObject(); + + if (!ops.verify(p3.get(0))) + { + fail("Failed v3 generated signature check"); + } + + // + // extract PGP 8 private key + // + pgpPriv = new PGPSecretKeyRing(pgp8Key, new JcaKeyFingerprintCalculator()); + + secretKey = pgpPriv.getSecretKey(); + + pgpPrivKey = secretKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().setProvider("SC").build()).setProvider("SC").build(pgp8Pass)); + + // + // expiry + // + testExpiry(expiry60and30daysSig13Key, 60, 30); + + fingerPrintTest(); + existingEmbeddedJpegTest(); + embeddedJpegTest(); + sigsubpacketTest(); + multipleExpiryTest(); + } + + private void testExpiry( + byte[] encodedRing, + int masterDays, + int subKeyDays) + throws Exception + { + PGPPublicKeyRing pubRing = new PGPPublicKeyRing(encodedRing, new JcaKeyFingerprintCalculator()); + PGPPublicKey k = pubRing.getPublicKey(); + + if (k.getValidDays() != masterDays) + { + fail("mismatch on master valid days."); + } + + Iterator it = pubRing.getPublicKeys(); + + it.next(); + + k = (PGPPublicKey)it.next(); + + if (k.getValidDays() != subKeyDays) + { + fail("mismatch on subkey valid days."); + } + } + + private boolean noIDEA() + { + try + { + Cipher.getInstance("IDEA", "SC"); + + return false; + } + catch (Exception e) + { + return true; + } + } + + public String getName() + { + return "PGPRSATest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PGPRSATest()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPSignatureTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPSignatureTest.java new file mode 100644 index 00000000..12f68a53 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPSignatureTest.java @@ -0,0 +1,1202 @@ +package org.spongycastle.openpgp.test; + +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; +import java.util.Iterator; + +import org.spongycastle.bcpg.CompressionAlgorithmTags; +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.bcpg.PublicKeyAlgorithmTags; +import org.spongycastle.bcpg.SignatureSubpacketTags; +import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.spongycastle.bcpg.sig.KeyFlags; +import org.spongycastle.bcpg.sig.NotationData; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPLiteralData; +import org.spongycastle.openpgp.PGPLiteralDataGenerator; +import org.spongycastle.openpgp.PGPOnePassSignature; +import org.spongycastle.openpgp.PGPOnePassSignatureList; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; +import org.spongycastle.openpgp.PGPV3SignatureGenerator; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.spongycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.io.Streams; +import org.spongycastle.util.test.SimpleTest; +import org.spongycastle.util.test.UncloseableOutputStream; + +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="); + + byte[] okAttr = + Base64.decode( + "mQENBFOkuoMBCAC+8WcWLBZovlR5pLW4tbOoH3APia+poMEeTNkXKe8yAH0f" + + "ZmTQgeXFBIizd4Ka1QETbayv+C6Axt6Ipdwf+3N/lqcOqg6PEwuIX4MBrv5R" + + "ILMH5QyM3a3RlyXa7xES3I9t2VHiZvl15OrTZe67YNGtxlXyeawt6v/9d/a3" + + "M1EaUzjN4H2EfI3P/VWpMUvQkn70996UKInOyaSB0hef/QS10jshG9DdgmLM" + + "1/mJFRp8ynZOV4yGLnAdoEoPGG/HJZEzWfqOiwmWZOIrZIwedY1eKuMIhUGv" + + "LTC9u+9X0h+Y0st5eb1pf8OLvrpRpEyHMrxXfj/V3rxom4d160ifGihPABEB" + + "AAG0GndpdGggYXR0dHIgPGF0dHJAYXR0ci5uZXQ+iQE4BBMBAgAiBQJTpLqD" + + "AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRBCjbg0bKVgCXJiB/wO" + + "6ksdrAy+zVxygFhk6Ju2vpMAOGnLl1nqBVT1mA5XiJu3rSiJmROLF2l21K0M" + + "BICZfz+mjIwN56RZNzZnEmXk/E2+PgADV5VTRRsjqlyoeN/NrLWuTm9FyngJ" + + "f96jVPysN6FzYRUB5Fuys57P+nu0RMoLGkHmQhp4L5hgNJTBy1SRnXukoIgJ" + + "2Ra3EBQ7dBrzuWW1ycwU5acfOoxfcVqgXkiXaxgvujFChZGWT6djbnbbzlMm" + + "sMKr6POKChEPWo1HJXXz1OaPsd75JA8bImgnrHhB3dHhD2wIqzQrtTxvraqz" + + "ZWWR2xYZPltzBSlaAdn8Hf0GGBoMhutb3tJLzbAX0cybzJkBEAABAQAAAAAA" + + "AAAAAAAAAP/Y/+AAEEpGSUYAAQEAAAEAAQAA/9sAQwAKBwcIBwYKCAgICwoK" + + "Cw4YEA4NDQ4dFRYRGCMfJSQiHyIhJis3LyYpNCkhIjBBMTQ5Oz4+PiUuRElD" + + "PEg3PT47/9sAQwEKCwsODQ4cEBAcOygiKDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7" + + "Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7/8AAEQgAkAB4AwEiAAIR" + + "AQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIB" + + "AwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHw" + + "JDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVm" + + "Z2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4" + + "ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8B" + + "AAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQE" + + "AAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDTh" + + "JfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2" + + "d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG" + + "x8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A" + + "9moqtf30Gm2cl3cvtijGSa4a++LNlGStlZvKR0ZuBWkKU6nwomU4x3PQqK8g" + + "uPinrEzYhhihX86ns/Ffia/XzElJUHOV4/rW/wBUqJXlZEe2i9j1iivMP+Ex" + + "1q3+/KCw6gip4PiXdREC5tUkHcrwaTwlVbK4e1iekUVzmheNdO1ycWyK8U5G" + + "drf410QOa55RcXaSNE09ULRRRUjCiiigAooooAKKKKAOY+IblfCN1g9cA/rX" + + "h1fQPiXT4dU0o2dwXEcrclCARgE8ZB9K4J/AGkKeJr38ZU/+Ir0MLiIUoNSO" + + "erTlJ3R54v3hXpfg3UdNGmrHPMsToOc9+KrQeBdAd2SS7vkYdPnX/wCIqy3g" + + "fRoThb+9GP8AaQ/+yVdavRqxs2yYU5wdzH164t57+V7XHlZOCOh5rn5n5Ndr" + + "J4U0xBt/tC8x16p/8RTP+EK0uRQ32q9IPfzE/wDiKuGKpRSSYnSm3c5/wjP5" + + "XiKFywUDqScelevR6/pCR4k1S0DDqPOXI/WvPLjwdplpbtPG9zI6so2yspU5" + + "YDoFHrW7pOmRWpEiqVyuPlHH41xYmpGpPmibU4uKszqY9f0aZtseq2bN6eeu" + + "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" + + "0GvLdt0Lx24c" + ); + + byte[] attrLongLength = + Base64.decode( + "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" + + "/9sAQwAKBwcIBwYKCAgICwoKCw4YEA4NDQ4dFRYRGCMfJSQiHyIhJis3LyYp" + + "NCkhIjBBMTQ5Oz4+PiUuRElDPEg3PT47/9sAQwEKCwsODQ4cEBAcOygiKDs7" + + "Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7" + + "Ozs7/8AAEQgAkAB4AwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAAB" + + "AgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNR" + + "YQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNE" + + "RUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeY" + + "mZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn" + + "6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkK" + + "C//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRC" + + "kaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNU" + + "VVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWm" + + "p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX2" + + "9/j5+v/aAAwDAQACEQMRAD8A9moqtf30Gm2cl3cvtijGSa4a++LNlGStlZvK" + + "R0ZuBWkKU6nwomU4x3PQqK8guPinrEzYhhihX86ns/Ffia/XzElJUHOV4/rW" + + "/wBUqJXlZEe2i9j1iivMP+Ex1q3+/KCw6gip4PiXdREC5tUkHcrwaTwlVbK4" + + "e1iekUVzmheNdO1ycWyK8U5Gdrf410QOa55RcXaSNE09ULRRRUjCiiigAooo" + + "oAKKKKAOY+IblfCN1g9cA/rXh1fQPiXT4dU0o2dwXEcrclCARgE8ZB9K4J/A" + + "GkKeJr38ZU/+Ir0MLiIUoNSOerTlJ3R54v3hXpfg3UdNGmrHPMsToOc9+KrQ" + + "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"); + + public void performTest() + throws Exception + { + // + // RSA tests + // + PGPSecretKeyRing pgpPriv = new PGPSecretKeyRing(rsaKeyRing, new JcaKeyFingerprintCalculator()); + PGPSecretKey secretKey = pgpPriv.getSecretKey(); + PGPPrivateKey pgpPrivKey = secretKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("SC").build(rsaPass)); + + 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(new JcaPGPContentSignerBuilder(PublicKeyAlgorithmTags.RSA_GENERAL, HashAlgorithmTags.SHA1).setProvider("SC")); + + sGen.init(PGPSignature.KEY_REVOCATION, pgpPrivKey); + + PGPSignature sig = sGen.generateCertification(secretKey.getPublicKey()); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), secretKey.getPublicKey()); + + if (!sig.verifyCertification(secretKey.getPublicKey())) + { + fail("revocation verification failed."); + } + + PGPSecretKeyRing pgpDSAPriv = new PGPSecretKeyRing(dsaKeyRing, new JcaKeyFingerprintCalculator()); + PGPSecretKey secretDSAKey = pgpDSAPriv.getSecretKey(); + PGPPrivateKey pgpPrivDSAKey = secretDSAKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("SC").build(dsaPass)); + + sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1).setProvider("SC")); + + sGen.init(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(); + + JcaPGPObjectFactory f = new JcaPGPObjectFactory(sigBytes); + + sig = ((PGPSignatureList) f.nextObject()).get(0); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), secretDSAKey.getPublicKey()); + + 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(new JcaPGPContentSignerBuilder(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1).setProvider("SC")); + + sGen.init(PGPSignature.SUBKEY_BINDING, pgpPrivDSAKey); + + sGen.setHashedSubpackets(null); + sGen.setUnhashedSubpackets(null); + + sig = sGen.generateCertification(TEST_USER_ID, secretKey.getPublicKey()); + + sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), secretDSAKey.getPublicKey()); + + 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 (PGPException e) + { + // expected + } + + // + // override hash packets + // + sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(PublicKeyAlgorithmTags.DSA, HashAlgorithmTags.SHA1).setProvider("SC")); + + sGen.init(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.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), secretDSAKey.getPublicKey()); + + 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, new JcaKeyFingerprintCalculator()); + secretKey = pgpPriv.getSecretKey(); + pgpPrivKey = secretKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("SC").build(dsaPass)); + + 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(); + + testSubpacketGenerator(); + testUserAttributeEncoding(); + } + + private void testUserAttributeEncoding() + throws Exception + { + PGPPublicKeyRing pkr = new PGPPublicKeyRing(okAttr, new BcKeyFingerprintCalculator()); + + checkUserAttribute("normal", pkr, pkr.getPublicKey()); + + pkr = new PGPPublicKeyRing(attrLongLength, new BcKeyFingerprintCalculator()); + + checkUserAttribute("long", pkr, pkr.getPublicKey()); + } + + private void checkUserAttribute(String type, PGPPublicKeyRing pkr, PGPPublicKey masterPk) + throws PGPException + { + Iterator attrit = pkr.getPublicKey().getUserAttributes(); + while (attrit.hasNext()) + { + PGPUserAttributeSubpacketVector attr = (PGPUserAttributeSubpacketVector)attrit.next(); + + Iterator sigit = masterPk.getSignaturesForUserAttribute(attr); + while (sigit.hasNext()) + { + PGPSignature sig = (PGPSignature)sigit.next(); + + sig.init(new BcPGPContentVerifierBuilderProvider(), masterPk); + if (!sig.verifyCertification(attr, masterPk)) + { + fail("user attribute sig failed to verify on " + type); + } + } + } + } + + private void testSubpacketGenerator() + { + PGPSignatureSubpacketGenerator sGen = new PGPSignatureSubpacketGenerator(); + + String name1 = genString(64); + String value1 = genString(72); + + sGen.setNotationData(true, true, name1, value1); + + PGPSignatureSubpacketVector sVec = sGen.generate(); + + NotationData[] nd = sVec.getNotationDataOccurrences(); + + if (nd.length != 1 || !nd[0].isHumanReadable()) + { + fail("length and readability test 1 failed"); + } + + if (!nd[0].getNotationName().equals(name1) || !nd[0].getNotationValue().equals(value1)) + { + fail("name/value test 1 failed"); + } + + String name2 = genString(256); + String value2 = genString(264); + + sGen.setNotationData(true, false, name2, value2); + + sVec = sGen.generate(); + + nd = sVec.getNotationDataOccurrences(); + + if (nd.length != 2 || !nd[0].isHumanReadable() || nd[1].isHumanReadable()) + { + fail("length and readability test 2 failed"); + } + + if (!nd[0].getNotationName().equals(name1) || !nd[0].getNotationValue().equals(value1)) + { + fail("name/value test 2.1 failed"); + } + + if (!nd[1].getNotationName().equals(name2) || !nd[1].getNotationValue().equals(value2)) + { + fail("name/value test 2.2 failed"); + } + + String name3 = genString(0xffff); + String value3 = genString(0xffff); + + sGen.setNotationData(true, false, name3, value3); + + sVec = sGen.generate(); + + nd = sVec.getNotationDataOccurrences(); + + if (nd.length != 3 || !nd[0].isHumanReadable() || nd[1].isHumanReadable() || nd[2].isHumanReadable()) + { + fail("length and readability test 3 failed"); + } + + if (!nd[0].getNotationName().equals(name1) || !nd[0].getNotationValue().equals(value1)) + { + fail("name/value test 3.1 failed"); + } + + if (!nd[1].getNotationName().equals(name2) || !nd[1].getNotationValue().equals(value2)) + { + fail("name/value test 3.2 failed"); + } + + if (!nd[2].getNotationName().equals(name3) || !nd[2].getNotationValue().equals(value3)) + { + fail("name/value test 3.3 failed"); + } + + String name4 = genString(0xffff1); + String value4 = genString(0xfffff); + + try + { + sGen.setNotationData(true, false, name4, value4); + fail("truncation occurs silently"); + } + catch (IllegalArgumentException e) + { + if (!"notationName exceeds maximum length.".equals(e.getMessage())) + { + fail("wrong message"); + } + } + + try + { + sGen.setNotationData(true, false, name3, value4); + fail("truncation occurs silently"); + } + catch (IllegalArgumentException e) + { + if (!"notationValue exceeds maximum length.".equals(e.getMessage())) + { + fail("wrong message"); + } + } + } + + private String genString(int length) + { + char[] chars = new char[length]; + + for (int i = 0; i != length; i++) + { + chars[i] = (char)('a' + (i % 26)); + } + + return new String(chars); + } + + 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 + { + JcaPGPObjectFactory f = new JcaPGPObjectFactory(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[i]); + } + } + } + } + + 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(new JcaPGPContentSignerBuilder(encAlgorithm, hashAlgorithm).setProvider("SC")); + + sGen.init(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(new JcaPGPContentSignerBuilder(encAlgorithm, HashAlgorithmTags.SHA1).setProvider("SC")); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ByteArrayInputStream testIn = new ByteArrayInputStream(data); + Date creationTime = new Date(); + + sGen.init(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(new JcaPGPContentSignerBuilder(encAlgorithm, hashAlgorithm).setProvider("SC")); + + sGen.init(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(new JcaPGPContentSignerBuilder(encAlgorithm, HashAlgorithmTags.SHA1).setProvider("SC")); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ByteArrayInputStream testIn = new ByteArrayInputStream(data); + + sGen.init(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 + { + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(encodedSig); + PGPOnePassSignatureList p1 = (PGPOnePassSignatureList)pgpFact.nextObject(); + PGPOnePassSignature ops = p1.get(0); + PGPLiteralData p2 = (PGPLiteralData)pgpFact.nextObject(); + InputStream dIn = p2.getInputStream(); + + ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pubKey); + + 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.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), pubKey); + + 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()); + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/PGPUnicodeTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/PGPUnicodeTest.java new file mode 100644 index 00000000..7a043c65 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/PGPUnicodeTest.java @@ -0,0 +1,184 @@ +package org.spongycastle.openpgp.test; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.math.BigInteger; +import java.nio.charset.Charset; +import java.security.Security; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPPrivateKey; +import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.openpgp.PGPSecretKeyRingCollection; +import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider; +import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; + +public class PGPUnicodeTest + extends TestCase +{ + private static final String TEST_DATA_HOME = "bc.test.data.home"; + + public void setUp() + { + if (Security.getProvider("SC") == null) + { + Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider()); + } + } + + 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! + } + + public void test_UmlautPassphrase() + { + + try + { + BigInteger keyId = new BigInteger("362961283C48132B9F14C5C3EC87272EFCB986D2", 16); + + String passphrase = new String("Händle".getBytes("UTF-16"), "UTF-16"); +// FileInputStream passwordFile = new FileInputStream("testdata/passphrase_for_test.txt"); +// byte[] password = new byte[passwordFile.available()]; +// passwordFile.read(password); +// passwordFile.close(); +// String passphrase = new String(password); + + test_key(keyId, passphrase); + + // all fine! + + } + catch (Exception e) + { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + public void test_ASCIIPassphrase() + { + + try + { + BigInteger keyId = new BigInteger("A392B7310C64026022405257AA2AAAC7CB417459", 16); + + String passphrase = "Admin123"; + + test_key(keyId, passphrase); + + // all fine! + + } + catch (Exception e) + { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + public void test_CyrillicPassphrase() + { + + try + { + BigInteger keyId = new BigInteger("B7773AF32BE4EC1806B1BACC4680E7F3960C44E7", 16); + + // XXX The password text file must not have the UTF-8 BOM ! + // Ref: http://stackoverflow.com/questions/2223882/whats-different-between-utf-8-and-utf-8-without-bom + + FileInputStream passwordFile = new FileInputStream(getDataHome() + "passphrase_cyr.txt"); + Reader reader = new InputStreamReader(passwordFile, Charset.forName("UTF-8")); + BufferedReader in = new BufferedReader(reader); + String passphrase = in.readLine(); + in.close(); + passwordFile.close(); + + test_key(keyId, passphrase); + + // all fine! + + } + catch (Exception e) + { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + private PGPSecretKeyRingCollection loadSecretKeyCollection( + String keyName) + throws Exception + { + FileInputStream fIn = new FileInputStream(getDataHome() + keyName); + + return new PGPSecretKeyRingCollection(fIn, new JcaKeyFingerprintCalculator()); + } + + private String getDataHome() + { + String dataHome = System.getProperty(TEST_DATA_HOME); + + if (dataHome == null) + { + throw new IllegalStateException(TEST_DATA_HOME + " property not set"); + } + + return dataHome + "/openpgp/unicode/"; + } + + public static void main (String[] args) + throws Exception + { + junit.textui.TestRunner.run(suite()); + } + + public static Test suite() + throws Exception + { + TestSuite suite = new TestSuite("Unicode Password tests"); + + suite.addTestSuite(PGPUnicodeTest.class); + + return suite; + } +} diff --git a/pg/src/test/java/org/spongycastle/openpgp/test/RegressionTest.java b/pg/src/test/java/org/spongycastle/openpgp/test/RegressionTest.java new file mode 100644 index 00000000..da3cd486 --- /dev/null +++ b/pg/src/test/java/org/spongycastle/openpgp/test/RegressionTest.java @@ -0,0 +1,50 @@ +package org.spongycastle.openpgp.test; + +import java.security.Security; + +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +public class RegressionTest +{ + public static Test[] tests = { + new BcPGPKeyRingTest(), + new PGPKeyRingTest(), + new BcPGPRSATest(), + new PGPRSATest(), + new BcPGPDSATest(), + new PGPDSATest(), + new BcPGPDSAElGamalTest(), + new PGPDSAElGamalTest(), + new BcPGPPBETest(), + new PGPPBETest(), + new PGPMarkerTest(), + new PGPPacketTest(), + new PGPArmoredTest(), + new PGPSignatureTest(), + new PGPClearSignedSignatureTest(), + new PGPCompressionTest(), + new PGPNoPrivateKeyTest(), + new PGPECDSATest(), + new PGPECDHTest(), + new PGPECMessageTest(), + new PGPParsingTest() + }; + + public static void main( + String[] args) + { + Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider()); + + for (int i = 0; i != tests.length; i++) + { + TestResult result = tests[i].perform(); + System.out.println(result); + if (result.getException() != null) + { + result.getException().printStackTrace(); + } + } + } +} + |