1 package org.bouncycastle.crypto.generators;
2 
3 import org.bouncycastle.crypto.CipherParameters;
4 import org.bouncycastle.crypto.Digest;
5 import org.bouncycastle.crypto.PBEParametersGenerator;
6 import org.bouncycastle.crypto.params.KeyParameter;
7 import org.bouncycastle.crypto.params.ParametersWithIV;
8 import org.bouncycastle.crypto.util.DigestFactory;
9 
10 /**
11  * Generator for PBE derived keys and ivs as usd by OpenSSL.
12  * <p>
13  * Originally this scheme was a simple extension of PKCS 5 V2.0 Scheme 1 using MD5 with an
14  * iteration count of 1. The default digest was changed to SHA-256 with OpenSSL 1.1.0. This
15  * implementation still defaults to MD5, but the digest can now be set.
16  * <p>
17  */
18 public class OpenSSLPBEParametersGenerator
19     extends PBEParametersGenerator
20 {
21     private final Digest  digest;
22 
23     /**
24      * Construct a OpenSSL Parameters generator - digest the original MD5.
25      */
OpenSSLPBEParametersGenerator()26     public OpenSSLPBEParametersGenerator()
27     {
28         this(DigestFactory.createMD5());
29     }
30 
31     /**
32      * Construct a OpenSSL Parameters generator - digest as specified.
33      *
34      * @param digest the digest to use as the PRF.
35      */
OpenSSLPBEParametersGenerator(Digest digest)36     public OpenSSLPBEParametersGenerator(Digest digest)
37     {
38         this.digest = digest;
39     }
40 
41     /**
42      * Initialise - note the iteration count for this algorithm is fixed at 1.
43      *
44      * @param password password to use.
45      * @param salt salt to use.
46      */
init( byte[] password, byte[] salt)47     public void init(
48        byte[] password,
49        byte[] salt)
50     {
51         super.init(password, salt, 1);
52     }
53 
54     /**
55      * the derived key function, the ith hash of the password and the salt.
56      */
generateDerivedKey( int bytesNeeded)57     private byte[] generateDerivedKey(
58         int bytesNeeded)
59     {
60         byte[]  buf = new byte[digest.getDigestSize()];
61         byte[]  key = new byte[bytesNeeded];
62         int     offset = 0;
63 
64         for (;;)
65         {
66             digest.update(password, 0, password.length);
67             digest.update(salt, 0, salt.length);
68 
69             digest.doFinal(buf, 0);
70 
71             int len = (bytesNeeded > buf.length) ? buf.length : bytesNeeded;
72             System.arraycopy(buf, 0, key, offset, len);
73             offset += len;
74 
75             // check if we need any more
76             bytesNeeded -= len;
77             if (bytesNeeded == 0)
78             {
79                 break;
80             }
81 
82             // do another round
83             digest.reset();
84             digest.update(buf, 0, buf.length);
85         }
86 
87         return key;
88     }
89 
90     /**
91      * Generate a key parameter derived from the password, salt, and iteration
92      * count we are currently initialised with.
93      *
94      * @param keySize the size of the key we want (in bits)
95      * @return a KeyParameter object.
96      * @exception IllegalArgumentException if the key length larger than the base hash size.
97      */
generateDerivedParameters( int keySize)98     public CipherParameters generateDerivedParameters(
99         int keySize)
100     {
101         keySize = keySize / 8;
102 
103         byte[]  dKey = generateDerivedKey(keySize);
104 
105         return new KeyParameter(dKey, 0, keySize);
106     }
107 
108     /**
109      * Generate a key with initialisation vector parameter derived from
110      * the password, salt, and iteration count we are currently initialised
111      * with.
112      *
113      * @param keySize the size of the key we want (in bits)
114      * @param ivSize the size of the iv we want (in bits)
115      * @return a ParametersWithIV object.
116      * @exception IllegalArgumentException if keySize + ivSize is larger than the base hash size.
117      */
generateDerivedParameters( int keySize, int ivSize)118     public CipherParameters generateDerivedParameters(
119         int     keySize,
120         int     ivSize)
121     {
122         keySize = keySize / 8;
123         ivSize = ivSize / 8;
124 
125         byte[]  dKey = generateDerivedKey(keySize + ivSize);
126 
127         return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
128     }
129 
130     /**
131      * Generate a key parameter for use with a MAC derived from the password,
132      * salt, and iteration count we are currently initialised with.
133      *
134      * @param keySize the size of the key we want (in bits)
135      * @return a KeyParameter object.
136      * @exception IllegalArgumentException if the key length larger than the base hash size.
137      */
generateDerivedMacParameters( int keySize)138     public CipherParameters generateDerivedMacParameters(
139         int keySize)
140     {
141         return generateDerivedParameters(keySize);
142     }
143 }
144