/* See LICENSE for licensing and NOTICE for copyright. */ package org.cryptacular.util; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.security.KeyPair; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.DSAPublicKey; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPrivateCrtKey; import java.security.interfaces.RSAPublicKey; import org.cryptacular.FailListener; import org.cryptacular.generator.KeyPairGenerator; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; /** * Unit test for {@link KeyPairUtil} class. * * @author Middleware Services */ @Listeners(FailListener.class) public class KeyPairUtilTest { private static final String KEY_PATH = "src/test/resources/keys/"; private final SecureRandom random = new SecureRandom(); private final KeyPair rsa512 = KeyPairGenerator.generateRSA(random, 512); private final KeyPair dsa1024 = KeyPairGenerator.generateDSA(random, 1024); private final KeyPair ec256 = KeyPairGenerator.generateEC(random, 256); private final KeyPair ec224 = KeyPairGenerator.generateEC(random, "P-224"); @DataProvider(name = "public-keys") public Object[][] getPublicKeys() { return new Object[][] { new Object[] {dsa1024.getPublic(), 1024}, new Object[] {rsa512.getPublic(), 512}, new Object[] {ec256.getPublic(), 256}, }; } @DataProvider(name = "private-keys") public Object[][] getPrivateKeys() { return new Object[][] { new Object[] {dsa1024.getPrivate(), 160}, new Object[] {rsa512.getPrivate(), 512}, new Object[] {ec224.getPrivate(), 224}, }; } @DataProvider(name = "key-pairs") public Object[][] getKeyPairs() { final KeyPair rsa512p2 = KeyPairGenerator.generateRSA(random, 512); return new Object[][] { new Object[] {rsa512.getPublic(), rsa512.getPrivate(), true}, new Object[] {rsa512p2.getPublic(), rsa512p2.getPrivate(), true}, new Object[] {rsa512.getPublic(), rsa512p2.getPrivate(), false}, }; } @DataProvider(name = "private-key-files") public Object[][] getPrivateKeyFiles() { return new Object[][] { new Object[] {KEY_PATH + "dsa-openssl-nopass.der", DSAPrivateKey.class}, new Object[] {KEY_PATH + "dsa-openssl-nopass.pem", DSAPrivateKey.class}, new Object[] { KEY_PATH + "rsa-openssl-nopass.der", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-openssl-nopass.pem", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "ec-openssl-prime256v1-named-nopass.der", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-openssl-secp224k1-explicit-nopass.der", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-openssl-secp224k1-explicit-nopass.pem", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-openssl-sect571r1-explicit-nopass.der", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-openssl-sect571r1-explicit-nopass.pem", ECPrivateKey.class, }, new Object[] {KEY_PATH + "dsa-pkcs8-nopass.der", DSAPrivateKey.class}, new Object[] {KEY_PATH + "dsa-pkcs8-nopass.pem", DSAPrivateKey.class}, new Object[] { KEY_PATH + "rsa-pkcs8-nopass.der", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-nopass.pem", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-nopass-noheader.pem", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "ec-pkcs8-secp224k1-explicit-nopass.der", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-pkcs8-secp224k1-explicit-nopass.pem", ECPrivateKey.class, }, }; } @DataProvider(name = "encrypted-private-key-files") public Object[][] getEncryptedPrivateKeyFiles() { return new Object[][] { new Object[] { KEY_PATH + "dsa-openssl-des3.pem", "vtcrypt", DSAPrivateKey.class, }, new Object[] { KEY_PATH + "rsa-openssl-des.pem", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-openssl-des-noheader.pem", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-openssl-des3.pem", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "ec-openssl-secp224k1-explicit-des.pem", "vtcrypt", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-openssl-sect571r1-explicit-des.pem", "vtcrypt", ECPrivateKey.class, }, new Object[] { KEY_PATH + "dsa-pkcs8-priv.der", "vtcrypt", DSAPrivateKey.class, }, new Object[] { KEY_PATH + "dsa-pkcs8-priv.pem", "vtcrypt", DSAPrivateKey.class, }, new Object[] { KEY_PATH + "dsa-pkcs8-v2-des3.der", "vtcrypt", DSAPrivateKey.class, }, new Object[] { KEY_PATH + "dsa-pkcs8-v2-des3.pem", "vtcrypt", DSAPrivateKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-v1-md5-des.der", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-v1-md5-des.pem", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-v1-md5-rc2-64.der", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-v2-aes256.der", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-v2-aes256.pem", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "rsa-pkcs8-v2-aes256-noheader.pem", "vtcrypt", RSAPrivateCrtKey.class, }, new Object[] { KEY_PATH + "ec-pkcs8-secp224k1-explicit-sha1-rc4-128.der", "vtcrypt", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-pkcs8-secp224k1-explicit-v1-sha1-rc2-64.der", "vtcrypt", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-pkcs8-secp224k1-explicit-v2-des3.pem", "vtcrypt", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-pkcs8-sect571r1-explicit-v2-aes128.pem", "vtcrypt", ECPrivateKey.class, }, new Object[] { KEY_PATH + "ec-pkcs8-sect571r1-named-v1-sha1-rc2-64.der", "vtcrypt", ECPrivateKey.class, }, }; } @DataProvider(name = "public-key-files") public Object[][] getPublicKeyFiles() { return new Object[][] { new Object[] {KEY_PATH + "dsa-pub.der", DSAPublicKey.class}, new Object[] {KEY_PATH + "dsa-pub.pem", DSAPublicKey.class}, new Object[] { KEY_PATH + "ec-secp224k1-explicit-pub.der", ECPublicKey.class, }, new Object[] { KEY_PATH + "ec-secp224k1-explicit-pub.pem", ECPublicKey.class, }, new Object[] {KEY_PATH + "rsa-pub.der", RSAPublicKey.class}, new Object[] {KEY_PATH + "rsa-pub.pem", RSAPublicKey.class}, }; } @Test(dataProvider = "public-keys") public void testLengthPublicKey(final PublicKey key, final int expectedLength) throws Exception { assertEquals(KeyPairUtil.length(key), expectedLength); } @Test(dataProvider = "private-keys") public void testLengthPrivateKey(final PrivateKey key, final int expectedLength) throws Exception { assertEquals(KeyPairUtil.length(key), expectedLength); } @Test(dataProvider = "key-pairs") public void testIsKeyPair(final PublicKey pubKey, final PrivateKey privKey, final boolean expected) throws Exception { assertEquals(KeyPairUtil.isKeyPair(pubKey, privKey), expected); } @Test(dataProvider = "private-key-files") public void testReadPrivateKey(final String path, final Class<?> expectedType) throws Exception { final PrivateKey key = KeyPairUtil.readPrivateKey(path); assertNotNull(key); assertTrue(expectedType.isAssignableFrom(key.getClass())); } @Test(dataProvider = "encrypted-private-key-files") public void testReadEncryptedPrivateKey(final String path, final String password, final Class<?> expectedType) throws Exception { final PrivateKey key = KeyPairUtil.readPrivateKey(path, password.toCharArray()); assertNotNull(key); assertTrue(expectedType.isAssignableFrom(key.getClass())); } @Test(dataProvider = "public-key-files") public void testReadPublicKey(final String path, final Class<?> expectedType) throws Exception { final PublicKey key = KeyPairUtil.readPublicKey(path); assertNotNull(key); assertTrue(expectedType.isAssignableFrom(key.getClass())); } @Test(dataProvider = "private-key-files") public void testClosePrivateKey(final String path, final Class<?> expectedType) throws Exception { final TestableFileInputStream is = new TestableFileInputStream(path); final PrivateKey key = KeyPairUtil.readPrivateKey(is); assertNotNull(key); assertTrue(is.isClosed()); } @Test(dataProvider = "public-key-files") public void testClosePublicKey(final String path, final Class<?> expectedType) throws Exception { final TestableFileInputStream is = new TestableFileInputStream(path); final PublicKey key = KeyPairUtil.readPublicKey(is); assertNotNull(key); assertTrue(is.isClosed()); } /** * Class for testing usage of {@link FileInputStream}. */ private class TestableFileInputStream extends FileInputStream { /** Whether {@link #close()} has been invoked. */ private boolean isClosed; /** * Default constructor. * * @param name of the file to open * * @throws FileNotFoundException if an error occurs */ TestableFileInputStream(final String name) throws FileNotFoundException { super(name); } @Override public void close() throws IOException { super.close(); isClosed = true; } /** * Returns whether {@link #close()} has been invoked. * * @return whether {@link #close()} has been invoked */ public boolean isClosed() { return isClosed; } } }