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.Digest;
      5 import org.bouncycastle.crypto.ExtendedDigest;
      6 import org.bouncycastle.crypto.PBEParametersGenerator;
      7 import org.bouncycastle.crypto.params.KeyParameter;
      8 import org.bouncycastle.crypto.params.ParametersWithIV;
      9 
     10 /**
     11  * Generator for PBE derived keys and ivs as defined by PKCS 12 V1.0.
     12  * <p>
     13  * The document this implementation is based on can be found at
     14  * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/index.html>
     15  * RSA's PKCS12 Page</a>
     16  */
     17 public class PKCS12ParametersGenerator
     18     extends PBEParametersGenerator
     19 {
     20     public static final int KEY_MATERIAL = 1;
     21     public static final int IV_MATERIAL  = 2;
     22     public static final int MAC_MATERIAL = 3;
     23 
     24     private Digest digest;
     25 
     26     private int     u;
     27     private int     v;
     28 
     29     /**
     30      * Construct a PKCS 12 Parameters generator. This constructor will
     31      * accept any digest which also implements ExtendedDigest.
     32      *
     33      * @param digest the digest to be used as the source of derived keys.
     34      * @exception IllegalArgumentException if an unknown digest is passed in.
     35      */
     36     public PKCS12ParametersGenerator(
     37         Digest  digest)
     38     {
     39         this.digest = digest;
     40         if (digest instanceof ExtendedDigest)
     41         {
     42             u = digest.getDigestSize();
     43             v = ((ExtendedDigest)digest).getByteLength();
     44         }
     45         else
     46         {
     47             throw new IllegalArgumentException("Digest " + digest.getAlgorithmName() + " unsupported");
     48         }
     49     }
     50 
     51     /**
     52      * add a + b + 1, returning the result in a. The a value is treated
     53      * as a BigInteger of length (b.length * 8) bits. The result is
     54      * modulo 2^b.length in case of overflow.
     55      */
     56     private void adjust(
     57         byte[]  a,
     58         int     aOff,
     59         byte[]  b)
     60     {
     61         int  x = (b[b.length - 1] & 0xff) + (a[aOff + b.length - 1] & 0xff) + 1;
     62 
     63         a[aOff + b.length - 1] = (byte)x;
     64         x >>>= 8;
     65 
     66         for (int i = b.length - 2; i >= 0; i--)
     67         {
     68             x += (b[i] & 0xff) + (a[aOff + i] & 0xff);
     69             a[aOff + i] = (byte)x;
     70             x >>>= 8;
     71         }
     72     }
     73 
     74     /**
     75      * generation of a derived key ala PKCS12 V1.0.
     76      */
     77     private byte[] generateDerivedKey(
     78         int idByte,
     79         int n)
     80     {
     81         byte[]  D = new byte[v];
     82         byte[]  dKey = new byte[n];
     83 
     84         for (int i = 0; i != D.length; i++)
     85         {
     86             D[i] = (byte)idByte;
     87         }
     88 
     89         byte[]  S;
     90 
     91         if ((salt != null) && (salt.length != 0))
     92         {
     93             S = new byte[v * ((salt.length + v - 1) / v)];
     94 
     95             for (int i = 0; i != S.length; i++)
     96             {
     97                 S[i] = salt[i % salt.length];
     98             }
     99         }
    100         else
    101         {
    102             S = new byte[0];
    103         }
    104 
    105         byte[]  P;
    106 
    107         if ((password != null) && (password.length != 0))
    108         {
    109             P = new byte[v * ((password.length + v - 1) / v)];
    110 
    111             for (int i = 0; i != P.length; i++)
    112             {
    113                 P[i] = password[i % password.length];
    114             }
    115         }
    116         else
    117         {
    118             P = new byte[0];
    119         }
    120 
    121         byte[]  I = new byte[S.length + P.length];
    122 
    123         System.arraycopy(S, 0, I, 0, S.length);
    124         System.arraycopy(P, 0, I, S.length, P.length);
    125 
    126         byte[]  B = new byte[v];
    127         int     c = (n + u - 1) / u;
    128         byte[]  A = new byte[u];
    129 
    130         for (int i = 1; i <= c; i++)
    131         {
    132             digest.update(D, 0, D.length);
    133             digest.update(I, 0, I.length);
    134             digest.doFinal(A, 0);
    135             for (int j = 1; j < iterationCount; j++)
    136             {
    137                 digest.update(A, 0, A.length);
    138                 digest.doFinal(A, 0);
    139             }
    140 
    141             for (int j = 0; j != B.length; j++)
    142             {
    143                 B[j] = A[j % A.length];
    144             }
    145 
    146             for (int j = 0; j != I.length / v; j++)
    147             {
    148                 adjust(I, j * v, B);
    149             }
    150 
    151             if (i == c)
    152             {
    153                 System.arraycopy(A, 0, dKey, (i - 1) * u, dKey.length - ((i - 1) * u));
    154             }
    155             else
    156             {
    157                 System.arraycopy(A, 0, dKey, (i - 1) * u, A.length);
    158             }
    159         }
    160 
    161         return dKey;
    162     }
    163 
    164     /**
    165      * Generate a key parameter derived from the password, salt, and iteration
    166      * count we are currently initialised with.
    167      *
    168      * @param keySize the size of the key we want (in bits)
    169      * @return a KeyParameter object.
    170      */
    171     public CipherParameters generateDerivedParameters(
    172         int keySize)
    173     {
    174         keySize = keySize / 8;
    175 
    176         byte[]  dKey = generateDerivedKey(KEY_MATERIAL, keySize);
    177 
    178         return new KeyParameter(dKey, 0, keySize);
    179     }
    180 
    181     /**
    182      * Generate a key with initialisation vector parameter derived from
    183      * the password, salt, and iteration count we are currently initialised
    184      * with.
    185      *
    186      * @param keySize the size of the key we want (in bits)
    187      * @param ivSize the size of the iv we want (in bits)
    188      * @return a ParametersWithIV object.
    189      */
    190     public CipherParameters generateDerivedParameters(
    191         int     keySize,
    192         int     ivSize)
    193     {
    194         keySize = keySize / 8;
    195         ivSize = ivSize / 8;
    196 
    197         byte[]  dKey = generateDerivedKey(KEY_MATERIAL, keySize);
    198 
    199         byte[]  iv = generateDerivedKey(IV_MATERIAL, ivSize);
    200 
    201         return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize);
    202     }
    203 
    204     /**
    205      * Generate a key parameter for use with a MAC derived from the password,
    206      * salt, and iteration count we are currently initialised with.
    207      *
    208      * @param keySize the size of the key we want (in bits)
    209      * @return a KeyParameter object.
    210      */
    211     public CipherParameters generateDerivedMacParameters(
    212         int keySize)
    213     {
    214         keySize = keySize / 8;
    215 
    216         byte[]  dKey = generateDerivedKey(MAC_MATERIAL, keySize);
    217 
    218         return new KeyParameter(dKey, 0, keySize);
    219     }
    220 }
    221