1 /*
2  * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.crypto.provider;
27 
28 import java.io.*;
29 import java.security.NoSuchAlgorithmException;
30 import java.security.AlgorithmParametersSpi;
31 import java.security.spec.AlgorithmParameterSpec;
32 import java.security.spec.InvalidParameterSpecException;
33 import javax.crypto.spec.IvParameterSpec;
34 import javax.crypto.spec.PBEParameterSpec;
35 import sun.security.util.*;
36 
37 /**
38  * This class implements the parameter set used with password-based
39  * encryption scheme 2 (PBES2), which is defined in PKCS#5 as follows:
40  *
41  * <pre>
42  * -- PBES2
43  *
44  * PBES2Algorithms ALGORITHM-IDENTIFIER ::=
45  *   { {PBES2-params IDENTIFIED BY id-PBES2}, ...}
46  *
47  * id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13}
48  *
49  * PBES2-params ::= SEQUENCE {
50  *   keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
51  *   encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
52  *
53  * PBES2-KDFs ALGORITHM-IDENTIFIER ::=
54  *   { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... }
55  *
56  * PBES2-Encs ALGORITHM-IDENTIFIER ::= { ... }
57  *
58  * -- PBKDF2
59  *
60  * PBKDF2Algorithms ALGORITHM-IDENTIFIER ::=
61  *   { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ...}
62  *
63  * id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12}
64  *
65  * PBKDF2-params ::= SEQUENCE {
66  *     salt CHOICE {
67  *       specified OCTET STRING,
68  *       otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
69  *     },
70  *     iterationCount INTEGER (1..MAX),
71  *     keyLength INTEGER (1..MAX) OPTIONAL,
72  *     prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
73  * }
74  *
75  * PBKDF2-SaltSources ALGORITHM-IDENTIFIER ::= { ... }
76  *
77  * PBKDF2-PRFs ALGORITHM-IDENTIFIER ::= {
78  *     {NULL IDENTIFIED BY id-hmacWithSHA1} |
79  *     {NULL IDENTIFIED BY id-hmacWithSHA224} |
80  *     {NULL IDENTIFIED BY id-hmacWithSHA256} |
81  *     {NULL IDENTIFIED BY id-hmacWithSHA384} |
82  *     {NULL IDENTIFIED BY id-hmacWithSHA512}, ... }
83  *
84  * algid-hmacWithSHA1 AlgorithmIdentifier {{PBKDF2-PRFs}} ::=
85  *     {algorithm id-hmacWithSHA1, parameters NULL : NULL}
86  *
87  * id-hmacWithSHA1 OBJECT IDENTIFIER ::= {digestAlgorithm 7}
88  *
89  * PBES2-Encs ALGORITHM-IDENTIFIER ::= { ... }
90  *
91  * </pre>
92  */
93 
94 abstract class PBES2Parameters extends AlgorithmParametersSpi {
95 
96     private static final int pkcs5PBKDF2[] =
97                                         {1, 2, 840, 113549, 1, 5, 12};
98     private static final int pkcs5PBES2[] =
99                                         {1, 2, 840, 113549, 1, 5, 13};
100     private static final int hmacWithSHA1[] =
101                                         {1, 2, 840, 113549, 2, 7};
102     private static final int hmacWithSHA224[] =
103                                         {1, 2, 840, 113549, 2, 8};
104     private static final int hmacWithSHA256[] =
105                                         {1, 2, 840, 113549, 2, 9};
106     private static final int hmacWithSHA384[] =
107                                         {1, 2, 840, 113549, 2, 10};
108     private static final int hmacWithSHA512[] =
109                                         {1, 2, 840, 113549, 2, 11};
110     private static final int aes128CBC[] =
111                                         {2, 16, 840, 1, 101, 3, 4, 1, 2};
112     private static final int aes192CBC[] =
113                                         {2, 16, 840, 1, 101, 3, 4, 1, 22};
114     private static final int aes256CBC[] =
115                                         {2, 16, 840, 1, 101, 3, 4, 1, 42};
116 
117     private static ObjectIdentifier pkcs5PBKDF2_OID;
118     private static ObjectIdentifier pkcs5PBES2_OID;
119     private static ObjectIdentifier hmacWithSHA1_OID;
120     private static ObjectIdentifier hmacWithSHA224_OID;
121     private static ObjectIdentifier hmacWithSHA256_OID;
122     private static ObjectIdentifier hmacWithSHA384_OID;
123     private static ObjectIdentifier hmacWithSHA512_OID;
124     private static ObjectIdentifier aes128CBC_OID;
125     private static ObjectIdentifier aes192CBC_OID;
126     private static ObjectIdentifier aes256CBC_OID;
127 
128     static {
129         try {
130             pkcs5PBKDF2_OID = new ObjectIdentifier(pkcs5PBKDF2);
131             pkcs5PBES2_OID = new ObjectIdentifier(pkcs5PBES2);
132             hmacWithSHA1_OID = new ObjectIdentifier(hmacWithSHA1);
133             hmacWithSHA224_OID = new ObjectIdentifier(hmacWithSHA224);
134             hmacWithSHA256_OID = new ObjectIdentifier(hmacWithSHA256);
135             hmacWithSHA384_OID = new ObjectIdentifier(hmacWithSHA384);
136             hmacWithSHA512_OID = new ObjectIdentifier(hmacWithSHA512);
137             aes128CBC_OID = new ObjectIdentifier(aes128CBC);
138             aes192CBC_OID = new ObjectIdentifier(aes192CBC);
139             aes256CBC_OID = new ObjectIdentifier(aes256CBC);
140         } catch (IOException ioe) {
141             // should not happen
142         }
143     }
144 
145     // the PBES2 algorithm name
146     private String pbes2AlgorithmName = null;
147 
148     // the salt
149     private byte[] salt = null;
150 
151     // the iteration count
152     private int iCount = 0;
153 
154     // the cipher parameter
155     private AlgorithmParameterSpec cipherParam = null;
156 
157     // the key derivation function (default is HmacSHA1)
158     private ObjectIdentifier kdfAlgo_OID = hmacWithSHA1_OID;
159 
160     // the encryption function
161     private ObjectIdentifier cipherAlgo_OID = null;
162 
163     // the cipher keysize (in bits)
164     private int keysize = -1;
165 
PBES2Parameters()166     PBES2Parameters() {
167         // KDF, encryption & keysize values are set later, in engineInit(byte[])
168     }
169 
PBES2Parameters(String pbes2AlgorithmName)170     PBES2Parameters(String pbes2AlgorithmName) throws NoSuchAlgorithmException {
171         int and;
172         String kdfAlgo = null;
173         String cipherAlgo = null;
174 
175         // Extract the KDF and encryption algorithm names
176         this.pbes2AlgorithmName = pbes2AlgorithmName;
177         if (pbes2AlgorithmName.startsWith("PBEWith") &&
178             (and = pbes2AlgorithmName.indexOf("And", 7 + 1)) > 0) {
179             kdfAlgo = pbes2AlgorithmName.substring(7, and);
180             cipherAlgo = pbes2AlgorithmName.substring(and + 3);
181 
182             // Check for keysize
183             int underscore;
184             if ((underscore = cipherAlgo.indexOf('_')) > 0) {
185                 int slash;
186                 if ((slash = cipherAlgo.indexOf('/', underscore + 1)) > 0) {
187                     keysize =
188                         Integer.parseInt(cipherAlgo.substring(underscore + 1,
189                             slash));
190                 } else {
191                     keysize =
192                         Integer.parseInt(cipherAlgo.substring(underscore + 1));
193                 }
194                 cipherAlgo = cipherAlgo.substring(0, underscore);
195             }
196         } else {
197             throw new NoSuchAlgorithmException("No crypto implementation for " +
198                 pbes2AlgorithmName);
199         }
200 
201         switch (kdfAlgo) {
202         case "HmacSHA1":
203             kdfAlgo_OID = hmacWithSHA1_OID;
204             break;
205         case "HmacSHA224":
206             kdfAlgo_OID = hmacWithSHA224_OID;
207             break;
208         case "HmacSHA256":
209             kdfAlgo_OID = hmacWithSHA256_OID;
210             break;
211         case "HmacSHA384":
212             kdfAlgo_OID = hmacWithSHA384_OID;
213             break;
214         case "HmacSHA512":
215             kdfAlgo_OID = hmacWithSHA512_OID;
216             break;
217         default:
218             throw new NoSuchAlgorithmException(
219                 "No crypto implementation for " + kdfAlgo);
220         }
221 
222         if (cipherAlgo.equals("AES")) {
223             this.keysize = keysize;
224             switch (keysize) {
225             case 128:
226                 cipherAlgo_OID = aes128CBC_OID;
227                 break;
228             case 256:
229                 cipherAlgo_OID = aes256CBC_OID;
230                 break;
231             default:
232                 throw new NoSuchAlgorithmException(
233                     "No Cipher implementation for " + keysize + "-bit " +
234                         cipherAlgo);
235             }
236         } else {
237             throw new NoSuchAlgorithmException("No Cipher implementation for " +
238                 cipherAlgo);
239         }
240     }
241 
engineInit(AlgorithmParameterSpec paramSpec)242     protected void engineInit(AlgorithmParameterSpec paramSpec)
243         throws InvalidParameterSpecException
244     {
245        if (!(paramSpec instanceof PBEParameterSpec)) {
246            throw new InvalidParameterSpecException
247                ("Inappropriate parameter specification");
248        }
249        this.salt = ((PBEParameterSpec)paramSpec).getSalt().clone();
250        this.iCount = ((PBEParameterSpec)paramSpec).getIterationCount();
251        this.cipherParam = ((PBEParameterSpec)paramSpec).getParameterSpec();
252     }
253 
254     @SuppressWarnings("deprecation")
engineInit(byte[] encoded)255     protected void engineInit(byte[] encoded)
256         throws IOException
257     {
258         String kdfAlgo = null;
259         String cipherAlgo = null;
260 
261         DerValue pBES2_params = new DerValue(encoded);
262         if (pBES2_params.tag != DerValue.tag_Sequence) {
263             throw new IOException("PBE parameter parsing error: "
264                 + "not an ASN.1 SEQUENCE tag");
265         }
266         DerValue kdf = pBES2_params.data.getDerValue();
267 
268         // Before JDK-8202837, PBES2-params was mistakenly encoded like
269         // an AlgorithmId which is a sequence of its own OID and the real
270         // PBES2-params. If the first DerValue is an OID instead of a
271         // PBES2-KDFs (which should be a SEQUENCE), we are likely to be
272         // dealing with this buggy encoding. Skip the OID and treat the
273         // next DerValue as the real PBES2-params.
274         if (kdf.getTag() == DerValue.tag_ObjectId) {
275             pBES2_params = pBES2_params.data.getDerValue();
276             kdf = pBES2_params.data.getDerValue();
277         }
278 
279         kdfAlgo = parseKDF(kdf);
280 
281         if (pBES2_params.tag != DerValue.tag_Sequence) {
282             throw new IOException("PBE parameter parsing error: "
283                 + "not an ASN.1 SEQUENCE tag");
284         }
285         cipherAlgo = parseES(pBES2_params.data.getDerValue());
286 
287         pbes2AlgorithmName = new StringBuilder().append("PBEWith")
288             .append(kdfAlgo).append("And").append(cipherAlgo).toString();
289     }
290 
291     @SuppressWarnings("deprecation")
parseKDF(DerValue keyDerivationFunc)292     private String parseKDF(DerValue keyDerivationFunc) throws IOException {
293 
294         if (!pkcs5PBKDF2_OID.equals(keyDerivationFunc.data.getOID())) {
295             throw new IOException("PBE parameter parsing error: "
296                 + "expecting the object identifier for PBKDF2");
297         }
298         if (keyDerivationFunc.tag != DerValue.tag_Sequence) {
299             throw new IOException("PBE parameter parsing error: "
300                 + "not an ASN.1 SEQUENCE tag");
301         }
302         DerValue pBKDF2_params = keyDerivationFunc.data.getDerValue();
303         if (pBKDF2_params.tag != DerValue.tag_Sequence) {
304             throw new IOException("PBE parameter parsing error: "
305                 + "not an ASN.1 SEQUENCE tag");
306         }
307         DerValue specified = pBKDF2_params.data.getDerValue();
308         // the 'specified' ASN.1 CHOICE for 'salt' is supported
309         if (specified.tag == DerValue.tag_OctetString) {
310             salt = specified.getOctetString();
311         } else {
312             // the 'otherSource' ASN.1 CHOICE for 'salt' is not supported
313             throw new IOException("PBE parameter parsing error: "
314                 + "not an ASN.1 OCTET STRING tag");
315         }
316         iCount = pBKDF2_params.data.getInteger();
317 
318         DerValue prf = null;
319         // keyLength INTEGER (1..MAX) OPTIONAL,
320         if (pBKDF2_params.data.available() > 0) {
321             DerValue keyLength = pBKDF2_params.data.getDerValue();
322             if (keyLength.tag == DerValue.tag_Integer) {
323                 keysize = keyLength.getInteger() * 8; // keysize (in bits)
324             } else {
325                 // Should be the prf
326                 prf = keyLength;
327             }
328         }
329         // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
330         String kdfAlgo = "HmacSHA1";
331         if (prf == null) {
332             if (pBKDF2_params.data.available() > 0) {
333                 prf = pBKDF2_params.data.getDerValue();
334             }
335         }
336         if (prf != null) {
337             kdfAlgo_OID = prf.data.getOID();
338             if (hmacWithSHA1_OID.equals(kdfAlgo_OID)) {
339                 kdfAlgo = "HmacSHA1";
340             } else if (hmacWithSHA224_OID.equals(kdfAlgo_OID)) {
341                 kdfAlgo = "HmacSHA224";
342             } else if (hmacWithSHA256_OID.equals(kdfAlgo_OID)) {
343                 kdfAlgo = "HmacSHA256";
344             } else if (hmacWithSHA384_OID.equals(kdfAlgo_OID)) {
345                 kdfAlgo = "HmacSHA384";
346             } else if (hmacWithSHA512_OID.equals(kdfAlgo_OID)) {
347                 kdfAlgo = "HmacSHA512";
348             } else {
349                 throw new IOException("PBE parameter parsing error: "
350                         + "expecting the object identifier for a HmacSHA key "
351                         + "derivation function");
352             }
353             if (prf.data.available() != 0) {
354                 // parameter is 'NULL' for all HmacSHA KDFs
355                 DerValue parameter = prf.data.getDerValue();
356                 if (parameter.tag != DerValue.tag_Null) {
357                     throw new IOException("PBE parameter parsing error: "
358                             + "not an ASN.1 NULL tag");
359                 }
360             }
361         }
362 
363         return kdfAlgo;
364     }
365 
366     @SuppressWarnings("deprecation")
parseES(DerValue encryptionScheme)367     private String parseES(DerValue encryptionScheme) throws IOException {
368         String cipherAlgo = null;
369 
370         cipherAlgo_OID = encryptionScheme.data.getOID();
371         if (aes128CBC_OID.equals(cipherAlgo_OID)) {
372             cipherAlgo = "AES_128";
373             // parameter is AES-IV 'OCTET STRING (SIZE(16))'
374             cipherParam =
375                 new IvParameterSpec(encryptionScheme.data.getOctetString());
376             keysize = 128;
377         } else if (aes256CBC_OID.equals(cipherAlgo_OID)) {
378             cipherAlgo = "AES_256";
379             // parameter is AES-IV 'OCTET STRING (SIZE(16))'
380             cipherParam =
381                 new IvParameterSpec(encryptionScheme.data.getOctetString());
382             keysize = 256;
383         } else {
384             throw new IOException("PBE parameter parsing error: "
385                 + "expecting the object identifier for AES cipher");
386         }
387 
388         return cipherAlgo;
389     }
390 
engineInit(byte[] encoded, String decodingMethod)391     protected void engineInit(byte[] encoded, String decodingMethod)
392         throws IOException
393     {
394         engineInit(encoded);
395     }
396 
397     protected <T extends AlgorithmParameterSpec>
engineGetParameterSpec(Class<T> paramSpec)398             T engineGetParameterSpec(Class<T> paramSpec)
399         throws InvalidParameterSpecException
400     {
401         if (PBEParameterSpec.class.isAssignableFrom(paramSpec)) {
402             return paramSpec.cast(
403                 new PBEParameterSpec(this.salt, this.iCount, this.cipherParam));
404         } else {
405             throw new InvalidParameterSpecException
406                 ("Inappropriate parameter specification");
407         }
408     }
409 
engineGetEncoded()410     protected byte[] engineGetEncoded() throws IOException {
411         DerOutputStream out = new DerOutputStream();
412 
413         DerOutputStream pBES2_params = new DerOutputStream();
414 
415         DerOutputStream keyDerivationFunc = new DerOutputStream();
416         keyDerivationFunc.putOID(pkcs5PBKDF2_OID);
417 
418         DerOutputStream pBKDF2_params = new DerOutputStream();
419         pBKDF2_params.putOctetString(salt); // choice: 'specified OCTET STRING'
420         pBKDF2_params.putInteger(iCount);
421 
422         if (keysize > 0) {
423             pBKDF2_params.putInteger(keysize / 8); // derived key length (in octets)
424         }
425 
426         DerOutputStream prf = new DerOutputStream();
427         // algorithm is id-hmacWithSHA1/SHA224/SHA256/SHA384/SHA512
428         prf.putOID(kdfAlgo_OID);
429         // parameters is 'NULL'
430         prf.putNull();
431         pBKDF2_params.write(DerValue.tag_Sequence, prf);
432 
433         keyDerivationFunc.write(DerValue.tag_Sequence, pBKDF2_params);
434         pBES2_params.write(DerValue.tag_Sequence, keyDerivationFunc);
435 
436         DerOutputStream encryptionScheme = new DerOutputStream();
437         // algorithm is id-aes128-CBC or id-aes256-CBC
438         encryptionScheme.putOID(cipherAlgo_OID);
439         // parameters is 'AES-IV ::= OCTET STRING (SIZE(16))'
440         if (cipherParam != null && cipherParam instanceof IvParameterSpec) {
441             encryptionScheme.putOctetString(
442                 ((IvParameterSpec)cipherParam).getIV());
443         } else {
444             throw new IOException("Wrong parameter type: IV expected");
445         }
446         pBES2_params.write(DerValue.tag_Sequence, encryptionScheme);
447 
448         out.write(DerValue.tag_Sequence, pBES2_params);
449 
450         return out.toByteArray();
451     }
452 
engineGetEncoded(String encodingMethod)453     protected byte[] engineGetEncoded(String encodingMethod)
454         throws IOException
455     {
456         return engineGetEncoded();
457     }
458 
459     /*
460      * Returns a formatted string describing the parameters.
461      *
462      * The algorithn name pattern is: "PBEWith<prf>And<encryption>"
463      * where <prf> is one of: HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384,
464      * or HmacSHA512, and <encryption> is AES with a keysize suffix.
465      */
engineToString()466     protected String engineToString() {
467         return pbes2AlgorithmName;
468     }
469 
470     public static final class General extends PBES2Parameters {
General()471         public General() throws NoSuchAlgorithmException {
472             super();
473         }
474     }
475 
476     public static final class HmacSHA1AndAES_128 extends PBES2Parameters {
HmacSHA1AndAES_128()477         public HmacSHA1AndAES_128() throws NoSuchAlgorithmException {
478             super("PBEWithHmacSHA1AndAES_128");
479         }
480     }
481 
482     public static final class HmacSHA224AndAES_128 extends PBES2Parameters {
HmacSHA224AndAES_128()483         public HmacSHA224AndAES_128() throws NoSuchAlgorithmException {
484             super("PBEWithHmacSHA224AndAES_128");
485         }
486     }
487 
488     public static final class HmacSHA256AndAES_128 extends PBES2Parameters {
HmacSHA256AndAES_128()489         public HmacSHA256AndAES_128() throws NoSuchAlgorithmException {
490             super("PBEWithHmacSHA256AndAES_128");
491         }
492     }
493 
494     public static final class HmacSHA384AndAES_128 extends PBES2Parameters {
HmacSHA384AndAES_128()495         public HmacSHA384AndAES_128() throws NoSuchAlgorithmException {
496             super("PBEWithHmacSHA384AndAES_128");
497         }
498     }
499 
500     public static final class HmacSHA512AndAES_128 extends PBES2Parameters {
HmacSHA512AndAES_128()501         public HmacSHA512AndAES_128() throws NoSuchAlgorithmException {
502             super("PBEWithHmacSHA512AndAES_128");
503         }
504     }
505 
506     public static final class HmacSHA1AndAES_256 extends PBES2Parameters {
HmacSHA1AndAES_256()507         public HmacSHA1AndAES_256() throws NoSuchAlgorithmException {
508             super("PBEWithHmacSHA1AndAES_256");
509         }
510     }
511 
512     public static final class HmacSHA224AndAES_256 extends PBES2Parameters {
HmacSHA224AndAES_256()513         public HmacSHA224AndAES_256() throws NoSuchAlgorithmException {
514             super("PBEWithHmacSHA224AndAES_256");
515         }
516     }
517 
518     public static final class HmacSHA256AndAES_256 extends PBES2Parameters {
HmacSHA256AndAES_256()519         public HmacSHA256AndAES_256() throws NoSuchAlgorithmException {
520             super("PBEWithHmacSHA256AndAES_256");
521         }
522     }
523 
524     public static final class HmacSHA384AndAES_256 extends PBES2Parameters {
HmacSHA384AndAES_256()525         public HmacSHA384AndAES_256() throws NoSuchAlgorithmException {
526             super("PBEWithHmacSHA384AndAES_256");
527         }
528     }
529 
530     public static final class HmacSHA512AndAES_256 extends PBES2Parameters {
HmacSHA512AndAES_256()531         public HmacSHA512AndAES_256() throws NoSuchAlgorithmException {
532             super("PBEWithHmacSHA512AndAES_256");
533         }
534     }
535 }
536