| package org.bouncycastle.crypto.test; |
| |
| import java.io.ByteArrayInputStream; |
| |
| import org.bouncycastle.asn1.ASN1InputStream; |
| import org.bouncycastle.asn1.ASN1OctetString; |
| import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; |
| import org.bouncycastle.asn1.pkcs.EncryptionScheme; |
| import org.bouncycastle.asn1.pkcs.KeyDerivationFunc; |
| import org.bouncycastle.asn1.pkcs.PBES2Parameters; |
| import org.bouncycastle.asn1.pkcs.PBKDF2Params; |
| import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; |
| import org.bouncycastle.asn1.pkcs.RC2CBCParameter; |
| import org.bouncycastle.crypto.BufferedBlockCipher; |
| import org.bouncycastle.crypto.CipherParameters; |
| import org.bouncycastle.crypto.PBEParametersGenerator; |
| import org.bouncycastle.crypto.engines.DESEngine; |
| import org.bouncycastle.crypto.engines.DESedeEngine; |
| import org.bouncycastle.crypto.engines.RC2Engine; |
| import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; |
| import org.bouncycastle.crypto.modes.CBCBlockCipher; |
| import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; |
| import org.bouncycastle.crypto.params.KeyParameter; |
| import org.bouncycastle.crypto.params.ParametersWithIV; |
| import org.bouncycastle.util.encoders.Base64; |
| import org.bouncycastle.util.encoders.Hex; |
| import org.bouncycastle.util.test.SimpleTest; |
| |
| /** |
| * A test class for PKCS5 PBES2 with PBKDF2 (PKCS5 v2.0) using |
| * test vectors provider at |
| * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html> |
| * RSA's PKCS5 Page</a> |
| * <br> |
| * The vectors are Base 64 encoded and encrypted using the password "password" |
| * (without quotes). They should all yield the same PrivateKeyInfo object. |
| */ |
| public class PKCS5Test |
| extends SimpleTest |
| { |
| /** |
| * encrypted using des-cbc. |
| */ |
| static byte[] sample1 = Base64.decode( |
| "MIIBozA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIfWBDXwLp4K4CAggA" |
| + "MBEGBSsOAwIHBAiaCF/AvOgQ6QSCAWDWX4BdAzCRNSQSANSuNsT5X8mWYO27mr3Y" |
| + "9c9LoBVXGNmYWKA77MI4967f7SmjNcgXj3xNE/jmnVz6hhsjS8E5VPT3kfyVkpdZ" |
| + "0lr5e9Yk2m3JWpPU7++v5zBkZmC4V/MwV/XuIs6U+vykgzMgpxQg0oZKS9zgmiZo" |
| + "f/4dOCL0UtCDnyOSvqT7mCVIcMDIEKu8QbVlgZYBop08l60EuEU3gARUo8WsYQmO" |
| + "Dz/ldx0Z+znIT0SXVuOwc+RVItC5T/Qx+aijmmpt+9l14nmaGBrEkmuhmtdvU/4v" |
| + "aptewGRgmjOfD6cqK+zs0O5NrrJ3P/6ZSxXj91CQgrThGfOv72bUncXEMNtc8pks" |
| + "2jpHFjGMdKufnadAD7XuMgzkkaklEXZ4f5tU6heIIwr51g0GBEGF96gYPFnjnSQM" |
| + "75JE02Clo+DfcfXpcybPTwwFg2jd6JTTOfkdf6OdSlA/1XNK43FA"); |
| |
| /** |
| * encrypted using des-ede3-cbc. |
| */ |
| static byte[] sample2 = Base64.decode( |
| "MIIBpjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIeFeOWl1jywYCAggA" |
| + "MBQGCCqGSIb3DQMHBAjUJ5eGBhQGtQSCAWBrHrRgqO8UUMLcWzZEtpk1l3mjxiF/" |
| + "koCMkHsFwowgyWhEbgIkTgbSViK54LVK8PskekcGNLph+rB6bGZ7pPbL5pbXASJ8" |
| + "+MkQcG3FZdlS4Ek9tTJDApj3O1UubZGFG4uvTlJJFbF1BOJ3MkY3XQ9Gl1qwv7j5" |
| + "6e103Da7Cq9+oIDKmznza78XXQYrUsPo8mJGjUxPskEYlzwvHjKubRnYm/K6RKhi" |
| + "5f4zX4BQ/Dt3H812ZjRXrsjAJP0KrD/jyD/jCT7zNBVPH1izBds+RwizyQAHwfNJ" |
| + "BFR78TH4cgzB619X47FDVOnT0LqQNVd0O3cSwnPrXE9XR3tPayE+iOB15llFSmi8" |
| + "z0ByOXldEpkezCn92Umk++suzIVj1qfsK+bv2phZWJPbLEIWPDRHUbYf76q5ArAr" |
| + "u4xtxT/hoK3krEs/IN3d70qjlUJ36SEw1UaZ82PWhakQbdtu39ZraMJB"); |
| |
| /** |
| * encrypted using rc2-cbc. |
| */ |
| static byte[] sample3 = Base64.decode( |
| "MIIBrjBIBgkqhkiG9w0BBQ0wOzAeBgkqhkiG9w0BBQwwEQQIrHyQPBZqWLUCAggA" |
| + "AgEQMBkGCCqGSIb3DQMCMA0CAToECEhbh7YZKiPSBIIBYCT1zp6o5jpFlIkgwPop" |
| + "7bW1+8ACr4exqzkeb3WflQ8cWJ4cURxzVdvxUnXeW1VJdaQZtjS/QHs5GhPTG/0f" |
| + "wtvnaPfwrIJ3FeGaZfcg2CrYhalOFmEb4xrE4KyoEQmUN8tb/Cg94uzd16BOPw21" |
| + "RDnE8bnPdIGY7TyL95kbkqH23mK53pi7h+xWIgduW+atIqDyyt55f7WMZcvDvlj6" |
| + "VpN/V0h+qxBHL274WA4dj6GYgeyUFpi60HdGCK7By2TBy8h1ZvKGjmB9h8jZvkx1" |
| + "MkbRumXxyFsowTZawyYvO8Um6lbfEDP9zIEUq0IV8RqH2MRyblsPNSikyYhxX/cz" |
| + "tdDxRKhilySbSBg5Kr8OfcwKp9bpinN96nmG4xr3Tch1bnVvqJzOQ5+Vva2WwVvH" |
| + "2JkWvYm5WaANg4Q6bRxu9vz7DuhbJjQdZbxFezIAgrJdSe92B00jO/0Kny1WjiVO" |
| + "6DA="); |
| |
| static byte[] result = Hex.decode( |
| "30820155020100300d06092a864886f70d01010105000482013f3082013b020100024100" |
| + "debbfc2c09d61bada2a9462f24224e54cc6b3cc0755f15ce318ef57e79df17026b6a85cc" |
| + "a12428027245045df2052a329a2f9ad3d17b78a10572ad9b22bf343b020301000102402d" |
| + "90a96adcec472743527bc023153d8f0d6e96b40c8ed228276d467d843306429f8670559b" |
| + "f376dd41857f6397c2fc8d95e0e53ed62de420b855430ee4a1b8a1022100ffcaf0838239" |
| + "31e073ff534f06a5d415b3d414bc614a4544a3dff7ed271817eb022100deea30242117db" |
| + "2d3b8837f58f1da530ff83cf9283680da33683ec4e583610f1022100e6026381adb0a683" |
| + "f16a8f4c096b462979b9e4277cc89f3ed8a905b46fa9ff9f02210097c146d4d1d2b3dbaf" |
| + "53a504ff51674c5c271800de84d003f4f10ac6ab36e38102202bfa141f10bda874e1017d" |
| + "845e82767c1c38e82745daf421f0c8cd09d7652387"); |
| |
| private class PBETest |
| extends SimpleTest |
| { |
| int id; |
| BufferedBlockCipher cipher; |
| byte[] sample; |
| int keySize; |
| |
| PBETest( |
| int id, |
| BufferedBlockCipher cipher, |
| byte[] sample, |
| int keySize) |
| { |
| this.id = id; |
| this.cipher = cipher; |
| this.sample = sample; |
| this.keySize = keySize; |
| } |
| |
| public String getName() |
| { |
| return cipher.getUnderlyingCipher().getAlgorithmName() + " PKCS5S2 Test " + id; |
| } |
| |
| public void performTest() |
| { |
| char[] password = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd' }; |
| PBEParametersGenerator generator = new PKCS5S2ParametersGenerator(); |
| ByteArrayInputStream bIn = new ByteArrayInputStream(sample); |
| ASN1InputStream dIn = new ASN1InputStream(bIn); |
| EncryptedPrivateKeyInfo info = null; |
| |
| try |
| { |
| info = EncryptedPrivateKeyInfo.getInstance(dIn.readObject()); |
| } |
| catch (Exception e) |
| { |
| fail("failed construction - exception " + e.toString(), e); |
| } |
| |
| PBES2Parameters alg = PBES2Parameters.getInstance(info.getEncryptionAlgorithm().getParameters()); |
| PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters()); |
| EncryptionScheme scheme = alg.getEncryptionScheme(); |
| |
| if (func.getKeyLength() != null) |
| { |
| keySize = func.getKeyLength().intValue() * 8; |
| } |
| |
| int iterationCount = func.getIterationCount().intValue(); |
| byte[] salt = func.getSalt(); |
| |
| generator.init( |
| PBEParametersGenerator.PKCS5PasswordToBytes(password), |
| salt, |
| iterationCount); |
| |
| CipherParameters param; |
| |
| if (scheme.getAlgorithm().equals(PKCSObjectIdentifiers.RC2_CBC)) |
| { |
| RC2CBCParameter rc2Params = RC2CBCParameter.getInstance(scheme.getParameters()); |
| byte[] iv = rc2Params.getIV(); |
| |
| param = new ParametersWithIV(generator.generateDerivedParameters(keySize), iv); |
| } |
| else |
| { |
| byte[] iv = ASN1OctetString.getInstance(scheme.getParameters()).getOctets(); |
| |
| param = new ParametersWithIV(generator.generateDerivedParameters(keySize), iv); |
| } |
| |
| cipher.init(false, param); |
| |
| byte[] data = info.getEncryptedData(); |
| byte[] out = new byte[cipher.getOutputSize(data.length)]; |
| int len = cipher.processBytes(data, 0, data.length, out, 0); |
| |
| try |
| { |
| len += cipher.doFinal(out, len); |
| } |
| catch (Exception e) |
| { |
| fail("failed doFinal - exception " + e.toString()); |
| } |
| |
| if (result.length != len) |
| { |
| fail("failed length"); |
| } |
| |
| for (int i = 0; i != len; i++) |
| { |
| if (out[i] != result[i]) |
| { |
| fail("failed comparison"); |
| } |
| } |
| } |
| } |
| |
| public String getName() |
| { |
| return "PKCS5S2"; |
| } |
| |
| public void performTest() |
| throws Exception |
| { |
| BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new DESEngine())); |
| SimpleTest test = new PBETest(0, cipher, sample1, 64); |
| |
| test.performTest(); |
| |
| cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new DESedeEngine())); |
| test = new PBETest(1, cipher, sample2, 192); |
| |
| test.performTest(); |
| |
| cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new RC2Engine())); |
| test = new PBETest(2, cipher, sample3, 0); |
| test.performTest(); |
| |
| // |
| // RFC 3211 tests |
| // |
| char[] password = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd' }; |
| PBEParametersGenerator generator = new PKCS5S2ParametersGenerator(); |
| |
| byte[] salt = Hex.decode("1234567878563412"); |
| |
| generator.init( |
| PBEParametersGenerator.PKCS5PasswordToBytes(password), |
| salt, |
| 5); |
| |
| if (!areEqual(((KeyParameter)generator.generateDerivedParameters(64)).getKey(), Hex.decode("d1daa78615f287e6"))) |
| { |
| fail("64 test failed"); |
| } |
| |
| password = "All n-entities must communicate with other n-entities via n-1 entiteeheehees".toCharArray(); |
| |
| generator.init( |
| PBEParametersGenerator.PKCS5PasswordToBytes(password), |
| salt, |
| 500); |
| |
| if (!areEqual(((KeyParameter)generator.generateDerivedParameters(192)).getKey(), Hex.decode("6a8970bf68c92caea84a8df28510858607126380cc47ab2d"))) |
| { |
| fail("192 test failed"); |
| } |
| |
| generator.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt, 60000); |
| if (!areEqual(((KeyParameter)generator.generateDerivedParameters(192)).getKey(), Hex.decode("29aaef810c12ecd2236bbcfb55407f9852b5573dc1c095bb"))) |
| { |
| fail("192 (60000) test failed"); |
| } |
| } |
| |
| public static void main( |
| String[] args) |
| { |
| runTest(new PKCS5Test()); |
| } |
| } |