Home | History | Annotate | Download | only in generators
      1 package org.bouncycastle.crypto.generators;
      2 
      3 import org.bouncycastle.crypto.CipherParameters;
      4 import org.bouncycastle.crypto.Mac;
      5 import org.bouncycastle.crypto.PBEParametersGenerator;
      6 import org.bouncycastle.crypto.digests.SHA1Digest;
      7 import org.bouncycastle.crypto.macs.HMac;
      8 import org.bouncycastle.crypto.params.KeyParameter;
      9 import org.bouncycastle.crypto.params.ParametersWithIV;
     10 
     11 /**
     12  * Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 2.
     13  * This generator uses a SHA-1 HMac as the calculation function.
     14  * <p>
     15  * The document this implementation is based on can be found at
     16  * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html>
     17  * RSA's PKCS5 Page</a>
     18  */
     19 public class PKCS5S2ParametersGenerator
     20     extends PBEParametersGenerator
     21 {
     22     private Mac    hMac = new HMac(new SHA1Digest());
     23 
     24     /**
     25      * construct a PKCS5 Scheme 2 Parameters generator.
     26      */
     27     public PKCS5S2ParametersGenerator()
     28     {
     29     }
     30 
     31     private void F(
     32         byte[]  P,
     33         byte[]  S,
     34         int     c,
     35         byte[]  iBuf,
     36         byte[]  out,
     37         int     outOff)
     38     {
     39         byte[]              state = new byte[hMac.getMacSize()];
     40         CipherParameters    param = new KeyParameter(P);
     41 
     42         hMac.init(param);
     43 
     44         if (S != null)
     45         {
     46             hMac.update(S, 0, S.length);
     47         }
     48 
     49         hMac.update(iBuf, 0, iBuf.length);
     50 
     51         hMac.doFinal(state, 0);
     52 
     53         System.arraycopy(state, 0, out, outOff, state.length);
     54 
     55         if (c == 0)
     56         {
     57             throw new IllegalArgumentException("iteration count must be at least 1.");
     58         }
     59 
     60         for (int count = 1; count < c; count++)
     61         {
     62             hMac.init(param);
     63             hMac.update(state, 0, state.length);
     64             hMac.doFinal(state, 0);
     65 
     66             for (int j = 0; j != state.length; j++)
     67             {
     68                 out[outOff + j] ^= state[j];
     69             }
     70         }
     71     }
     72 
     73     private void intToOctet(
     74         byte[]  buf,
     75         int     i)
     76     {
     77         buf[0] = (byte)(i >>> 24);
     78         buf[1] = (byte)(i >>> 16);
     79         buf[2] = (byte)(i >>> 8);
     80         buf[3] = (byte)i;
     81     }
     82 
     83     private byte[] generateDerivedKey(
     84         int dkLen)
     85     {
     86         int     hLen = hMac.getMacSize();
     87         int     l = (dkLen + hLen - 1) / hLen;
     88         byte[]  iBuf = new byte[4];
     89         byte[]  out = new byte[l * hLen];
     90 
     91         for (int i = 1; i <= l; i++)
     92         {
     93             intToOctet(iBuf, i);
     94 
     95             F(password, salt, iterationCount, iBuf, out, (i - 1) * hLen);
     96         }
     97 
     98         return out;
     99     }
    100 
    101     /**
    102      * Generate a key parameter derived from the password, salt, and iteration
    103      * count we are currently initialised with.
    104      *
    105      * @param keySize the size of the key we want (in bits)
    106      * @return a KeyParameter object.
    107      */
    108     public CipherParameters generateDerivedParameters(
    109         int keySize)
    110     {
    111         keySize = keySize / 8;
    112 
    113         byte[]  dKey = generateDerivedKey(keySize);
    114 
    115         return new KeyParameter(dKey, 0, keySize);
    116     }
    117 
    118     /**
    119      * Generate a key with initialisation vector parameter derived from
    120      * the password, salt, and iteration count we are currently initialised
    121      * with.
    122      *
    123      * @param keySize the size of the key we want (in bits)
    124      * @param ivSize the size of the iv we want (in bits)
    125      * @return a ParametersWithIV object.
    126      */
    127     public CipherParameters generateDerivedParameters(
    128         int     keySize,
    129         int     ivSize)
    130     {
    131         keySize = keySize / 8;
    132         ivSize = ivSize / 8;
    133 
    134         byte[]  dKey = generateDerivedKey(keySize + ivSize);
    135 
    136         return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
    137     }
    138 
    139     /**
    140      * Generate a key parameter for use with a MAC derived from the password,
    141      * salt, and iteration count we are currently initialised with.
    142      *
    143      * @param keySize the size of the key we want (in bits)
    144      * @return a KeyParameter object.
    145      */
    146     public CipherParameters generateDerivedMacParameters(
    147         int keySize)
    148     {
    149         return generateDerivedParameters(keySize);
    150     }
    151 }
    152