Home | History | Annotate | Download | only in pkcs
      1 package org.bouncycastle.asn1.pkcs;
      2 
      3 import java.math.BigInteger;
      4 import java.util.Enumeration;
      5 
      6 import org.bouncycastle.asn1.ASN1EncodableVector;
      7 import org.bouncycastle.asn1.ASN1Integer;
      8 import org.bouncycastle.asn1.ASN1Object;
      9 import org.bouncycastle.asn1.ASN1OctetString;
     10 import org.bouncycastle.asn1.ASN1Primitive;
     11 import org.bouncycastle.asn1.ASN1Sequence;
     12 import org.bouncycastle.asn1.DERNull;
     13 import org.bouncycastle.asn1.DEROctetString;
     14 import org.bouncycastle.asn1.DERSequence;
     15 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
     16 import org.bouncycastle.util.Arrays;
     17 
     18 /**
     19  * <pre>
     20  *     PBKDF2-params ::= SEQUENCE {
     21  *               salt CHOICE {
     22  *                      specified OCTET STRING,
     23  *                      otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
     24  *               },
     25  *              iterationCount INTEGER (1..MAX),
     26  *              keyLength INTEGER (1..MAX) OPTIONAL,
     27  *              prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
     28  * </pre>
     29  */
     30 public class PBKDF2Params
     31     extends ASN1Object
     32 {
     33     private static final AlgorithmIdentifier algid_hmacWithSHA1 = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA1, DERNull.INSTANCE);
     34 
     35     private final ASN1OctetString octStr;
     36     private final ASN1Integer iterationCount;
     37     private final ASN1Integer keyLength;
     38     private final AlgorithmIdentifier prf;
     39 
     40     /**
     41      * Create PBKDF2Params from the passed in object,
     42      *
     43      * @param obj either PBKDF2Params or an ASN1Sequence.
     44      * @return a PBKDF2Params instance.
     45      */
     46     public static PBKDF2Params getInstance(
     47         Object obj)
     48     {
     49         if (obj instanceof PBKDF2Params)
     50         {
     51             return (PBKDF2Params)obj;
     52         }
     53 
     54         if (obj != null)
     55         {
     56             return new PBKDF2Params(ASN1Sequence.getInstance(obj));
     57         }
     58 
     59         return null;
     60     }
     61 
     62     /**
     63      * Create a PBKDF2Params with the specified salt, iteration count, and algid-hmacWithSHA1 for the prf.
     64      *
     65      * @param salt           input salt.
     66      * @param iterationCount input iteration count.
     67      */
     68     public PBKDF2Params(
     69         byte[] salt,
     70         int iterationCount)
     71     {
     72         this(salt, iterationCount, 0);
     73     }
     74 
     75     /**
     76      * Create a PBKDF2Params with the specified salt, iteration count, keyLength, and algid-hmacWithSHA1 for the prf.
     77      *
     78      * @param salt           input salt.
     79      * @param iterationCount input iteration count.
     80      * @param keyLength      intended key length to be produced.
     81      */
     82     public PBKDF2Params(
     83         byte[] salt,
     84         int iterationCount,
     85         int keyLength)
     86     {
     87         this(salt, iterationCount, keyLength, null);
     88     }
     89 
     90     /**
     91      * Create a PBKDF2Params with the specified salt, iteration count, keyLength, and a defined prf.
     92      *
     93      * @param salt           input salt.
     94      * @param iterationCount input iteration count.
     95      * @param keyLength      intended key length to be produced.
     96      * @param prf            the pseudo-random function to use.
     97      */
     98     public PBKDF2Params(
     99         byte[] salt,
    100         int iterationCount,
    101         int keyLength,
    102         AlgorithmIdentifier prf)
    103     {
    104         this.octStr = new DEROctetString(Arrays.clone(salt));
    105         this.iterationCount = new ASN1Integer(iterationCount);
    106 
    107         if (keyLength > 0)
    108         {
    109             this.keyLength = new ASN1Integer(keyLength);
    110         }
    111         else
    112         {
    113             this.keyLength = null;
    114         }
    115 
    116         this.prf = prf;
    117     }
    118 
    119     /**
    120      * Create a PBKDF2Params with the specified salt, iteration count, and a defined prf.
    121      *
    122      * @param salt           input salt.
    123      * @param iterationCount input iteration count.
    124      * @param prf            the pseudo-random function to use.
    125      */
    126     public PBKDF2Params(
    127         byte[] salt,
    128         int iterationCount,
    129         AlgorithmIdentifier prf)
    130     {
    131         this(salt, iterationCount, 0, prf);
    132     }
    133 
    134     private PBKDF2Params(
    135         ASN1Sequence seq)
    136     {
    137         Enumeration e = seq.getObjects();
    138 
    139         octStr = (ASN1OctetString)e.nextElement();
    140         iterationCount = (ASN1Integer)e.nextElement();
    141 
    142         if (e.hasMoreElements())
    143         {
    144             Object o = e.nextElement();
    145 
    146             if (o instanceof ASN1Integer)
    147             {
    148                 keyLength = ASN1Integer.getInstance(o);
    149                 if (e.hasMoreElements())
    150                 {
    151                     o = e.nextElement();
    152                 }
    153                 else
    154                 {
    155                     o = null;
    156                 }
    157             }
    158             else
    159             {
    160                 keyLength = null;
    161             }
    162 
    163             if (o != null)
    164             {
    165                 prf = AlgorithmIdentifier.getInstance(o);
    166             }
    167             else
    168             {
    169                 prf = null;
    170             }
    171         }
    172         else
    173         {
    174             keyLength = null;
    175             prf = null;
    176         }
    177     }
    178 
    179     /**
    180      * Return the salt to use.
    181      *
    182      * @return the input salt.
    183      */
    184     public byte[] getSalt()
    185     {
    186         return octStr.getOctets();
    187     }
    188 
    189     /**
    190      * Return the iteration count to use.
    191      *
    192      * @return the input iteration count.
    193      */
    194     public BigInteger getIterationCount()
    195     {
    196         return iterationCount.getValue();
    197     }
    198 
    199     /**
    200      * Return the intended length in octets of the derived key.
    201      *
    202      * @return length in octets for derived key, if specified.
    203      */
    204     public BigInteger getKeyLength()
    205     {
    206         if (keyLength != null)
    207         {
    208             return keyLength.getValue();
    209         }
    210 
    211         return null;
    212     }
    213 
    214     /**
    215      * Return true if the PRF is the default (hmacWithSHA1)
    216      *
    217      * @return true if PRF is default, false otherwise.
    218      */
    219     public boolean isDefaultPrf()
    220     {
    221         return prf == null || prf.equals(algid_hmacWithSHA1);
    222     }
    223 
    224     /**
    225      * Return the algId of the underlying pseudo random function to use.
    226      *
    227      * @return the prf algorithm identifier.
    228      */
    229     public AlgorithmIdentifier getPrf()
    230     {
    231         if (prf != null)
    232         {
    233             return prf;
    234         }
    235 
    236         return algid_hmacWithSHA1;
    237     }
    238 
    239     /**
    240      * Return an ASN.1 structure suitable for encoding.
    241      *
    242      * @return the object as an ASN.1 encodable structure.
    243      */
    244     public ASN1Primitive toASN1Primitive()
    245     {
    246         ASN1EncodableVector v = new ASN1EncodableVector();
    247 
    248         v.add(octStr);
    249         v.add(iterationCount);
    250 
    251         if (keyLength != null)
    252         {
    253             v.add(keyLength);
    254         }
    255 
    256         if (prf != null && !prf.equals(algid_hmacWithSHA1))
    257         {
    258             v.add(prf);
    259         }
    260 
    261         return new DERSequence(v);
    262     }
    263 }
    264