1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16package libcore.javax.crypto.spec;
17
18import java.security.AlgorithmParameters;
19import java.security.Key;
20import java.util.Arrays;
21
22import junit.framework.TestCase;
23
24import javax.crypto.Cipher;
25import javax.crypto.SecretKeyFactory;
26import javax.crypto.spec.IvParameterSpec;
27import javax.crypto.spec.PBEKeySpec;
28import javax.crypto.spec.PBEParameterSpec;
29
30public class AlgorithmParametersTestPBES2 extends TestCase {
31
32    private static final int[] KEY_SIZES = { 128, 256 };
33    int[] SHA_VARIANTS = { 1, 224, 256, 384, 512 };
34
35    private static final PBEParameterSpec TEST_PBE_PARAMETER_SPEC = new PBEParameterSpec(
36            new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }, // salt
37            34, // iterationCount
38            new IvParameterSpec(new byte[] {
39                    40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55 // IV
40            }));
41
42    // For SHA variants other than SHA1, known answers generated with:
43    //
44    // AlgorithmParameters ap = AlgorithmParameters.getInstance(
45    //         "PBEWithHmacSHA" + shaVariant + "AndAES_" + keySize,
46    //         new com.sun.crypto.provider.SunJCE());
47    // AlgorithmParameterSpec spec = TEST_PBE_PARAMETER_SPEC;
48    // ap.init(spec);
49    // System.out.println("Encoded: " + Arrays.toString(ap.getEncoded()));
50    //
51    // For SHA1, the RI does encode the prf (SHA1) although it is the default one, and thus it
52    // shouldn't be explicitly encoded, according to DER. Checked with an ASN1 decoder that the
53    // only difference between our encoding and the RI's one is that SHA1 is not explicitly
54    // encoded.
55    private static final byte[][] GET_ENCODED_KNOWN_ANSWERS = new byte[][] {
56        // PBEWithHmacSHA1AndAES_128
57        { 48, 75, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 13, 48, 62, 48, 29, 6, 9, 42, -122, 72,
58                -122, -9, 13, 1, 5, 12, 48, 16, 4, 8, 0, 1, 2, 3, 4, 5, 6, 7, 2, 1, 34, 2, 1, 16,
59                48, 29, 6, 9, 96, -122, 72, 1, 101, 3, 4, 1, 2, 4, 16, 40, 41, 42, 43, 44, 45, 46,
60                47, 48, 49, 50, 51, 52, 53, 54, 55 },
61        // PBEWithHmacSHA224AndAES_128
62        { 48, 89, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 13, 48, 76, 48, 43, 6, 9, 42, -122, 72,
63                -122, -9, 13, 1, 5, 12, 48, 30, 4, 8, 0, 1, 2, 3, 4, 5, 6, 7, 2, 1, 34, 2, 1, 16,
64                48, 12, 6, 8, 42, -122, 72, -122, -9, 13, 2, 8, 5, 0, 48, 29, 6, 9, 96, -122, 72, 1,
65                101, 3, 4, 1, 2, 4, 16, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
66                55 },
67        // PBEWithHmacSHA256AndAES_128
68        { 48, 89, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 13, 48, 76, 48, 43, 6, 9, 42, -122, 72,
69                -122, -9, 13, 1, 5, 12, 48, 30, 4, 8, 0, 1, 2, 3, 4, 5, 6, 7, 2, 1, 34, 2, 1, 16,
70                48, 12, 6, 8, 42, -122, 72, -122, -9, 13, 2, 9, 5, 0, 48, 29, 6, 9, 96, -122, 72, 1,
71                101, 3, 4, 1, 2, 4, 16, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
72                55 },
73        // PBEWithHmacSHA384AndAES_128
74        { 48, 89, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 13, 48, 76, 48, 43, 6, 9, 42, -122, 72,
75                -122, -9, 13, 1, 5, 12, 48, 30, 4, 8, 0, 1, 2, 3, 4, 5, 6, 7, 2, 1, 34, 2, 1, 16,
76                48, 12, 6, 8, 42, -122, 72, -122, -9, 13, 2, 10, 5, 0, 48, 29, 6, 9, 96, -122, 72,
77                1, 101, 3, 4, 1, 2, 4, 16, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
78                54, 55 },
79        // PBEWithHmacSHA512AndAES_128
80        { 48, 89, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 13, 48, 76, 48, 43, 6, 9, 42, -122, 72,
81                -122, -9, 13, 1, 5, 12, 48, 30, 4, 8, 0, 1, 2, 3, 4, 5, 6, 7, 2, 1, 34, 2, 1, 16,
82                48, 12, 6, 8, 42, -122, 72, -122, -9, 13, 2, 11, 5, 0, 48, 29, 6, 9, 96, -122, 72,
83                1, 101, 3, 4, 1, 2, 4, 16, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
84                54, 55 },
85        // PBEWithHmacSHA1AndAES_256
86        { 48, 75, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 13, 48, 62, 48, 29, 6, 9, 42, -122, 72,
87                -122, -9, 13, 1, 5, 12, 48, 16, 4, 8, 0, 1, 2, 3, 4, 5, 6, 7, 2, 1, 34, 2, 1, 32,
88                48, 29, 6, 9, 96, -122, 72, 1, 101, 3, 4, 1, 42, 4, 16, 40, 41, 42, 43, 44, 45, 46,
89                47, 48, 49, 50, 51, 52, 53, 54, 55},
90        // PBEWithHmacSHA224AndAES_256
91        { 48, 89, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 13, 48, 76, 48, 43, 6, 9, 42, -122, 72,
92                -122, -9, 13, 1, 5, 12, 48, 30, 4, 8, 0, 1, 2, 3, 4, 5, 6, 7, 2, 1, 34, 2, 1, 32,
93                48, 12, 6, 8, 42, -122, 72, -122, -9, 13, 2, 8, 5, 0, 48, 29, 6, 9, 96, -122, 72, 1,
94                101, 3, 4, 1, 42, 4, 16, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
95                55 },
96        // PBEWithHmacSHA256AndAES_256
97        { 48, 89, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 13, 48, 76, 48, 43, 6, 9, 42, -122, 72,
98                -122, -9, 13, 1, 5, 12, 48, 30, 4, 8, 0, 1, 2, 3, 4, 5, 6, 7, 2, 1, 34, 2, 1, 32,
99                48, 12, 6, 8, 42, -122, 72, -122, -9, 13, 2, 9, 5, 0, 48, 29, 6, 9, 96, -122, 72, 1,
100                101, 3, 4, 1, 42, 4, 16, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
101                55 },
102        // PBEWithHmacSHA384AndAES_256
103        { 48, 89, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 13, 48, 76, 48, 43, 6, 9, 42, -122, 72,
104                -122, -9, 13, 1, 5, 12, 48, 30, 4, 8, 0, 1, 2, 3, 4, 5, 6, 7, 2, 1, 34, 2, 1, 32,
105                48, 12, 6, 8, 42, -122, 72, -122, -9, 13, 2, 10, 5, 0, 48, 29, 6, 9, 96, -122, 72,
106                1, 101, 3, 4, 1, 42, 4, 16, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
107                54, 55 },
108        // PBEWithHmacSHA512AndAES_256
109        { 48, 89, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 13, 48, 76, 48, 43, 6, 9, 42, -122, 72,
110                -122, -9, 13, 1, 5, 12, 48, 30, 4, 8, 0, 1, 2, 3, 4, 5, 6, 7, 2, 1, 34, 2, 1, 32,
111                48, 12, 6, 8, 42, -122, 72, -122, -9, 13, 2, 11, 5, 0, 48, 29, 6, 9, 96, -122, 72,
112                1, 101, 3, 4, 1, 42, 4, 16, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
113                54, 55 } };
114
115    // Known answers obtained with:
116    // String algorithmName = "PBEWithHmacSHA" + shaVariant + "AndAES_" + keySize;
117    // SecretKeyFactory skf = SecretKeyFactory.getInstance(
118    //        algorithmName, sunProvider);
119    // Key key = skf.generateSecret(pbeKS);
120    // Cipher c = Cipher.getInstance(algorithmName, sunProvider);
121    //            c.init(Cipher.ENCRYPT_MODE, key, TEST_PBE_PARAMETER_SPEC);
122    // byte[] encrypted = c.doFinal(plaintext);
123    private static final byte[][] ENCRYPT_KNOWN_ANSWERS = new byte[][]{
124        // PBEWithHmacSHA1AndAES_128
125        { -42, -84, 94, -75, -84, 12, -83, -100, -76, -58, -78, 82, -78, 11, -70, 67, 92, 111, -90,
126                -75, 43, 31, 16, 47, -81, -127, -65, -127, -41, 121, 77, -90, -15, 3, 5, -12, 66,
127                37, -80, 107, -99, 106, -59, -79, -32, -7, -27, 110 },
128        { 121, 36, -19, 19, -89, 95, -15, 50, -62, 36, -23, -78, -7, 43, 79, -31, 17, 88, -35, -89,
129                -11, 108, -8, -64, 77, 57, 64, 36, 70, -102, -65, 77, 74, 20, 9, -121, -9, 69, -115,
130                21, 32, -22, -107, -75, -76, 111, 79, 99 },
131        // PBEWithHmacSHA224AndAES_128
132        { 1, 60, 84, 10, 3, 110, 3, -112, 27, 126, 59, -63, -34, 117, 83, -67, -115, 117, -23, 57,
133                -70, -126, 57, -84, -3, -102, -87, 98, 77, 10, -19, -41, 20, -95, 53, -112, -48, 22,
134                22, -99, -71, -88, -111, -87, 3, -126, -83, 64 },
135        // PBEWithHmacSHA256AndAES_128
136        { -102, -122, 69, -75, -11, -61, -13, 82, 122, -97, 112, -27, 61, 22, -28, -34, -66, -47,
137                123, 104, 20, -115, 83, -33, -38, 65, -101, -128, -20, -34, 95, 53, -69, 11, -79,
138                -78, 37, 2, -81, 126, 97, -10, -69, -56, 89, -22, -25, -72 },
139        // PBEWithHmacSHA384AndAES_128
140        { -67, -57, -99, -6, 102, 87, -111, 18, 63, 7, -99, 32, -110, -24, 44, -94, -24, 101, 39,
141                115, 24, 20, -31, 126, 99, -113, -40, 27, 79, -48, 98, 84, 67, -51, 115, -21, -118,
142                9, 11, -117, -25, -73, -106, 36, -28, -18, 96, 16 },
143        // PBEWithHmacSHA512AndAES_128
144        { -72, 97, -41, -80, 0, 39, -121, 107, -89, -72, -103, -52, 100, 126, -89, -59, -4, 73,
145                -116, 0, 69, 95, 23, -25, 67, -81, -23, 1, 18, 57, -73, 89, 79, 124, -128, -113, 12,
146                78, 14, 12, 64, 112, -105, -6, 13, -112, 26, -92 },
147        // PBEWithHmacSHA1AndAES_256
148        { 98, 125, 91, -63, 96, 15, -103, -127, 70, -73, -25, 40, -126, 116, 15, -102, -108, 117,
149                -111, -65, -24, -114, 90, -126, -115, 15, -86, -72, -109, 47, 39, -102, -52, 123,
150                -4, -50, -99, 33, 92, 32, -110, -6, -2, -114, -116, 2, -16, -106 },
151        // PBEWithHmacSHA256AndAES_256
152        { 126, -32, 53, 14, -13, 26, 127, -23, -38, -56, 66, 1, 45, -128, -16, -99, -34, -31, -49,
153                126, 120, -47, -39, -108, -12, 16, 16, -127, 64, -64, 75, 53, 41, 51, 53, -37, -95,
154                3, -87, -100, 103, -55, 30, 5, 29, 8, 93, 123 },
155        // PBEWithHmacSHA384AndAES_256
156        { 68, 99, -46, -114, 37, -29, 59, -80, 16, 113, 116, 97, -9, -36, -32, 8, 59, -124, -73,
157                -66, -105, -57, 41, -78, 86, -128, 90, 51, -29, 108, -24, -62, 87, 94, -87, -5, 126,
158                95, -101, -39, -126, -76, 77, -2, 44, -70, -70, -88 },
159        // PBEWithHmacSHA512AndAES_256
160        { -93, -114, 1, -58, 117, -41, -114, 58, 56, 108, -16, -57, -36, -76, 92, -65, 100, 119, -9,
161                8, -93, 113, -3, -85, -31, -26, 20, 115, -45, -56, 30, 106, -16, -66, 4, -53, 2,
162                -113, 8, -116, -38, 0, 126, -87, 61, -32, 57, -35}
163    };
164
165    public void testGetEncoded_knownAnswers() throws Exception {
166        int i = 0;
167        for (int keySize : KEY_SIZES) {
168            for (int shaVariant : SHA_VARIANTS) {
169                AlgorithmParameters ap = AlgorithmParameters.getInstance(
170                        "PBEWithHmacSHA"+ shaVariant + "AndAES_" + keySize, "BC");
171                ap.init(TEST_PBE_PARAMETER_SPEC);
172                assertEquals(
173                        Arrays.toString(GET_ENCODED_KNOWN_ANSWERS[i]),
174                        Arrays.toString(ap.getEncoded()));
175                i++;
176            }
177        }
178    }
179
180    public void test_encodeAndDecode() throws Exception {
181        AlgorithmParameters ap = AlgorithmParameters.getInstance(
182                "PBEWithHmacSHA224AndAES_128", "BC");
183        ap.init(TEST_PBE_PARAMETER_SPEC);
184        AlgorithmParameters ap2 = AlgorithmParameters.getInstance(
185                "PBEWithHmacSHA224AndAES_128", "BC");
186        ap2.init(ap.getEncoded());
187        PBEParameterSpec encodedSpec = ap2.getParameterSpec(PBEParameterSpec.class);
188        assertEquals(Arrays.toString(TEST_PBE_PARAMETER_SPEC.getSalt()),
189                Arrays.toString(encodedSpec.getSalt()));
190        assertEquals(TEST_PBE_PARAMETER_SPEC.getIterationCount(), encodedSpec.getIterationCount());
191        assertTrue(encodedSpec.getParameterSpec() instanceof IvParameterSpec);
192        assertEquals(
193                Arrays.toString(
194                        ((IvParameterSpec) TEST_PBE_PARAMETER_SPEC.getParameterSpec()).getIV()),
195                Arrays.toString(((IvParameterSpec) encodedSpec.getParameterSpec()).getIV()));
196    }
197
198    public void test_encryptWithAlgorithmParameters() throws Exception {
199        byte[] plaintext = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 , 15, 16, 17, 18, 19,
200                20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33 };
201        PBEKeySpec pbeKS = new PBEKeySpec("aaaaa".toCharArray());
202        int i = 0;
203        for (int keySize : KEY_SIZES) {
204            for (int shaVariant : SHA_VARIANTS) {
205                String algorithmName = "PBEWithHmacSHA" + shaVariant + "AndAES_" + keySize;
206                AlgorithmParameters ap = AlgorithmParameters.getInstance(algorithmName, "BC");
207                ap.init(TEST_PBE_PARAMETER_SPEC);
208                SecretKeyFactory skf = SecretKeyFactory.getInstance(
209                        algorithmName, "BC");
210                Key key = skf.generateSecret(pbeKS);
211                Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
212                c.init(Cipher.ENCRYPT_MODE, key, ap);
213                byte[] encrypted = c.doFinal(plaintext);
214                assertEquals(
215                        Arrays.toString(ENCRYPT_KNOWN_ANSWERS[i]),
216                        Arrays.toString(encrypted));
217                c.init(Cipher.DECRYPT_MODE, key, ap);
218                byte[] decrypted = c.doFinal(encrypted);
219                assertEquals(
220                        Arrays.toString(plaintext),
221                        Arrays.toString(decrypted));
222                i++;
223            }
224        }
225    }
226
227    public void test_correctNames()  throws Exception {
228        for (int keySize : KEY_SIZES) {
229            for (int shaVariant : SHA_VARIANTS) {
230                String algorithmName = "PBEWithHmacSHA" + shaVariant + "AndAES_" + keySize;
231                AlgorithmParameters ap = AlgorithmParameters.getInstance(algorithmName, "BC");
232                ap.init(TEST_PBE_PARAMETER_SPEC);
233                assertTrue(ap.toString().matches("(?i:.*hmacsha" + shaVariant + ".*)"));
234                assertTrue(ap.toString().matches("(?i:.*aes" + +keySize + ".*)"));
235            }
236        }
237    }
238
239    public void test_encryptWithNoSalt() throws Exception {
240        // Encrypting with no salt is allowed if using a PKCS5 scheme, which
241        // the SHA-based ones aren't but MD5-based ones are.
242        String algorithmName = "PBEwithMD5andDES";
243        SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithmName, "BC");
244        Key key = skf.generateSecret(new PBEKeySpec("aaaaa".toCharArray()));
245        Cipher c = Cipher.getInstance(algorithmName, "BC");
246        c.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(new byte[0], 1000));
247    }
248}
249