Home | History | Annotate | Download | only in provider
      1 package org.bouncycastle.jce.provider;
      2 
      3 import java.security.spec.AlgorithmParameterSpec;
      4 
      5 import javax.crypto.spec.PBEParameterSpec;
      6 
      7 import org.bouncycastle.crypto.CipherParameters;
      8 import org.bouncycastle.crypto.Digest;
      9 import org.bouncycastle.crypto.PBEParametersGenerator;
     10 import org.bouncycastle.crypto.digests.MD5Digest;
     11 // BEGIN android-removed
     12 // import org.bouncycastle.crypto.digests.RIPEMD160Digest;
     13 // END android-removed
     14 import org.bouncycastle.crypto.digests.SHA1Digest;
     15 import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
     16 import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator;
     17 import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
     18 import org.bouncycastle.crypto.params.KeyParameter;
     19 import org.bouncycastle.crypto.params.ParametersWithIV;
     20 
     21 /**
     22  * Generator for PBE derived keys and ivs as defined by PKCS 12 V1.0,
     23  * with a bug affecting 180 bit plus keys - this class is only here to
     24  * allow smooth migration of the version 0 keystore to version 1. Don't
     25  * use it (it won't be staying around).
     26  * <p>
     27  * The document this implementation is based on can be found at
     28  * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/index.html>
     29  * RSA's PKCS12 Page</a>
     30  */
     31 class OldPKCS12ParametersGenerator
     32     extends PBEParametersGenerator
     33 {
     34     public static final int KEY_MATERIAL = 1;
     35     public static final int IV_MATERIAL  = 2;
     36     public static final int MAC_MATERIAL = 3;
     37 
     38     private Digest digest;
     39 
     40     private int     u;
     41     private int     v;
     42 
     43     /**
     44      * Construct a PKCS 12 Parameters generator. This constructor will
     45      * accept MD5, SHA1, and RIPEMD160.
     46      *
     47      * @param digest the digest to be used as the source of derived keys.
     48      * @exception IllegalArgumentException if an unknown digest is passed in.
     49      */
     50     public OldPKCS12ParametersGenerator(
     51         Digest  digest)
     52     {
     53         this.digest = digest;
     54         if (digest instanceof MD5Digest)
     55         {
     56             u = 128 / 8;
     57             v = 512 / 8;
     58         }
     59         else if (digest instanceof SHA1Digest)
     60         {
     61             u = 160 / 8;
     62             v = 512 / 8;
     63         }
     64         // BEGIN android-removed
     65         // else if (digest instanceof RIPEMD160Digest)
     66         // {
     67         //     u = 160 / 8;
     68         //     v = 512 / 8;
     69         // }
     70         // END android-removed
     71         else
     72         {
     73             throw new IllegalArgumentException("Digest " + digest.getAlgorithmName() + " unsupported");
     74         }
     75     }
     76 
     77     /**
     78      * add a + b + 1, returning the result in a. The a value is treated
     79      * as a BigInteger of length (b.length * 8) bits. The result is
     80      * modulo 2^b.length in case of overflow.
     81      */
     82     private void adjust(
     83         byte[]  a,
     84         int     aOff,
     85         byte[]  b)
     86     {
     87         int  x = (b[b.length - 1] & 0xff) + (a[aOff + b.length - 1] & 0xff) + 1;
     88 
     89         a[aOff + b.length - 1] = (byte)x;
     90         x >>>= 8;
     91 
     92         for (int i = b.length - 2; i >= 0; i--)
     93         {
     94             x += (b[i] & 0xff) + (a[aOff + i] & 0xff);
     95             a[aOff + i] = (byte)x;
     96             x >>>= 8;
     97         }
     98     }
     99 
    100     /**
    101      * generation of a derived key ala PKCS12 V1.0.
    102      */
    103     private byte[] generateDerivedKey(
    104         int idByte,
    105         int n)
    106     {
    107         byte[]  D = new byte[v];
    108         byte[]  dKey = new byte[n];
    109 
    110         for (int i = 0; i != D.length; i++)
    111         {
    112             D[i] = (byte)idByte;
    113         }
    114 
    115         byte[]  S;
    116 
    117         if ((salt != null) && (salt.length != 0))
    118         {
    119             S = new byte[v * ((salt.length + v - 1) / v)];
    120 
    121             for (int i = 0; i != S.length; i++)
    122             {
    123                 S[i] = salt[i % salt.length];
    124             }
    125         }
    126         else
    127         {
    128             S = new byte[0];
    129         }
    130 
    131         byte[]  P;
    132 
    133         if ((password != null) && (password.length != 0))
    134         {
    135             P = new byte[v * ((password.length + v - 1) / v)];
    136 
    137             for (int i = 0; i != P.length; i++)
    138             {
    139                 P[i] = password[i % password.length];
    140             }
    141         }
    142         else
    143         {
    144             P = new byte[0];
    145         }
    146 
    147         byte[]  I = new byte[S.length + P.length];
    148 
    149         System.arraycopy(S, 0, I, 0, S.length);
    150         System.arraycopy(P, 0, I, S.length, P.length);
    151 
    152         byte[]  B = new byte[v];
    153         int     c = (n + u - 1) / u;
    154 
    155         for (int i = 1; i <= c; i++)
    156         {
    157             byte[]  A = new byte[u];
    158 
    159             digest.update(D, 0, D.length);
    160             digest.update(I, 0, I.length);
    161             digest.doFinal(A, 0);
    162             for (int j = 1; j != iterationCount; j++)
    163             {
    164                 digest.update(A, 0, A.length);
    165                 digest.doFinal(A, 0);
    166             }
    167 
    168             for (int j = 0; j != B.length; j++)
    169             {
    170                 B[i] = A[j % A.length];
    171             }
    172 
    173             for (int j = 0; j != I.length / v; j++)
    174             {
    175                 adjust(I, j * v, B);
    176             }
    177 
    178             if (i == c)
    179             {
    180                 System.arraycopy(A, 0, dKey, (i - 1) * u, dKey.length - ((i - 1) * u));
    181             }
    182             else
    183             {
    184                 System.arraycopy(A, 0, dKey, (i - 1) * u, A.length);
    185             }
    186         }
    187 
    188         return dKey;
    189     }
    190 
    191     /**
    192      * Generate a key parameter derived from the password, salt, and iteration
    193      * count we are currently initialised with.
    194      *
    195      * @param keySize the size of the key we want (in bits)
    196      * @return a KeyParameter object.
    197      */
    198     public CipherParameters generateDerivedParameters(
    199         int keySize)
    200     {
    201         keySize = keySize / 8;
    202 
    203         byte[]  dKey = generateDerivedKey(KEY_MATERIAL, keySize);
    204 
    205         return new KeyParameter(dKey, 0, keySize);
    206     }
    207 
    208     /**
    209      * Generate a key with initialisation vector parameter derived from
    210      * the password, salt, and iteration count we are currently initialised
    211      * with.
    212      *
    213      * @param keySize the size of the key we want (in bits)
    214      * @param ivSize the size of the iv we want (in bits)
    215      * @return a ParametersWithIV object.
    216      */
    217     public CipherParameters generateDerivedParameters(
    218         int     keySize,
    219         int     ivSize)
    220     {
    221         keySize = keySize / 8;
    222         ivSize = ivSize / 8;
    223 
    224         byte[]  dKey = generateDerivedKey(KEY_MATERIAL, keySize);
    225 
    226         byte[]  iv = generateDerivedKey(IV_MATERIAL, ivSize);
    227 
    228         return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize);
    229     }
    230 
    231     /**
    232      * Generate a key parameter for use with a MAC derived from the password,
    233      * salt, and iteration count we are currently initialised with.
    234      *
    235      * @param keySize the size of the key we want (in bits)
    236      * @return a KeyParameter object.
    237      */
    238     public CipherParameters generateDerivedMacParameters(
    239         int keySize)
    240     {
    241         keySize = keySize / 8;
    242 
    243         byte[]  dKey = generateDerivedKey(MAC_MATERIAL, keySize);
    244 
    245         return new KeyParameter(dKey, 0, keySize);
    246     }
    247 }
    248 
    249 public interface BrokenPBE
    250 {
    251     //
    252     // PBE Based encryption constants - by default we do PKCS12 with SHA-1
    253     //
    254     static final int        MD5         = 0;
    255     static final int        SHA1        = 1;
    256     static final int        RIPEMD160   = 2;
    257 
    258     static final int        PKCS5S1     = 0;
    259     static final int        PKCS5S2     = 1;
    260     static final int        PKCS12      = 2;
    261     static final int        OLD_PKCS12  = 3;
    262 
    263     /**
    264      * uses the appropriate mixer to generate the key and IV if neccessary.
    265      */
    266     static class Util
    267     {
    268         /**
    269          * a faulty parity routine...
    270          *
    271          * @param bytes the byte array to set the parity on.
    272          */
    273         static private void setOddParity(
    274             byte[] bytes)
    275         {
    276             for (int i = 0; i < bytes.length; i++)
    277             {
    278                 int b = bytes[i];
    279                 bytes[i] = (byte)((b & 0xfe) |
    280                                 (((b >> 1) ^
    281                                 (b >> 2) ^
    282                                 (b >> 3) ^
    283                                 (b >> 4) ^
    284                                 (b >> 5) ^
    285                                 (b >> 6) ^
    286                                 (b >> 7)) ^ 0x01));
    287             }
    288         }
    289 
    290         static private PBEParametersGenerator makePBEGenerator(
    291             int                     type,
    292             int                     hash)
    293         {
    294             PBEParametersGenerator  generator;
    295 
    296             if (type == PKCS5S1)
    297             {
    298                 switch (hash)
    299                 {
    300                 case MD5:
    301                     generator = new PKCS5S1ParametersGenerator(new MD5Digest());
    302                     break;
    303                 case SHA1:
    304                     generator = new PKCS5S1ParametersGenerator(new SHA1Digest());
    305                     break;
    306                 default:
    307                     throw new IllegalStateException("PKCS5 scheme 1 only supports only MD5 and SHA1.");
    308                 }
    309             }
    310             else if (type == PKCS5S2)
    311             {
    312                 generator = new PKCS5S2ParametersGenerator();
    313             }
    314             else if (type == OLD_PKCS12)
    315             {
    316                 switch (hash)
    317                 {
    318                 case MD5:
    319                     generator = new OldPKCS12ParametersGenerator(new MD5Digest());
    320                     break;
    321                 case SHA1:
    322                     generator = new OldPKCS12ParametersGenerator(new SHA1Digest());
    323                     break;
    324                 // BEGIN android-removed
    325                 // case RIPEMD160:
    326                 //     generator = new OldPKCS12ParametersGenerator(new RIPEMD160Digest());
    327                 //     break;
    328                 // END android-removed
    329                 default:
    330                     throw new IllegalStateException("unknown digest scheme for PBE encryption.");
    331                 }
    332             }
    333             else
    334             {
    335                 switch (hash)
    336                 {
    337                 case MD5:
    338                     generator = new PKCS12ParametersGenerator(new MD5Digest());
    339                     break;
    340                 case SHA1:
    341                     generator = new PKCS12ParametersGenerator(new SHA1Digest());
    342                     break;
    343                 // BEGIN android-removed
    344                 // case RIPEMD160:
    345                 //     generator = new PKCS12ParametersGenerator(new RIPEMD160Digest());
    346                 //     break;
    347                 // END android-removed
    348                 default:
    349                     throw new IllegalStateException("unknown digest scheme for PBE encryption.");
    350                 }
    351             }
    352 
    353             return generator;
    354         }
    355 
    356         /**
    357          * construct a key and iv (if neccessary) suitable for use with a
    358          * Cipher.
    359          */
    360         static CipherParameters makePBEParameters(
    361             JCEPBEKey               pbeKey,
    362             AlgorithmParameterSpec  spec,
    363             int                     type,
    364             int                     hash,
    365             String                  targetAlgorithm,
    366             int                     keySize,
    367             int                     ivSize)
    368         {
    369             if ((spec == null) || !(spec instanceof PBEParameterSpec))
    370             {
    371                 throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
    372             }
    373 
    374             PBEParameterSpec        pbeParam = (PBEParameterSpec)spec;
    375             PBEParametersGenerator  generator = makePBEGenerator(type, hash);
    376             byte[]                  key = pbeKey.getEncoded();
    377             CipherParameters        param;
    378 
    379             generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
    380 
    381             if (ivSize != 0)
    382             {
    383                 param = generator.generateDerivedParameters(keySize, ivSize);
    384             }
    385             else
    386             {
    387                 param = generator.generateDerivedParameters(keySize);
    388             }
    389 
    390             if (targetAlgorithm.startsWith("DES"))
    391             {
    392                 if (param instanceof ParametersWithIV)
    393                 {
    394                     KeyParameter    kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
    395 
    396                     setOddParity(kParam.getKey());
    397                 }
    398                 else
    399                 {
    400                     KeyParameter    kParam = (KeyParameter)param;
    401 
    402                     setOddParity(kParam.getKey());
    403                 }
    404             }
    405 
    406             for (int i = 0; i != key.length; i++)
    407             {
    408                 key[i] = 0;
    409             }
    410 
    411             return param;
    412         }
    413 
    414         /**
    415          * generate a PBE based key suitable for a MAC algorithm, the
    416          * key size is chosen according the MAC size, or the hashing algorithm,
    417          * whichever is greater.
    418          */
    419         static CipherParameters makePBEMacParameters(
    420             JCEPBEKey               pbeKey,
    421             AlgorithmParameterSpec  spec,
    422             int                     type,
    423             int                     hash,
    424             int                     keySize)
    425         {
    426             if ((spec == null) || !(spec instanceof PBEParameterSpec))
    427             {
    428                 throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
    429             }
    430 
    431             PBEParameterSpec        pbeParam = (PBEParameterSpec)spec;
    432             PBEParametersGenerator  generator = makePBEGenerator(type, hash);
    433             byte[]                  key = pbeKey.getEncoded();
    434             CipherParameters        param;
    435 
    436             generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
    437 
    438             param = generator.generateDerivedMacParameters(keySize);
    439 
    440             for (int i = 0; i != key.length; i++)
    441             {
    442                 key[i] = 0;
    443             }
    444 
    445             return param;
    446         }
    447     }
    448 }
    449