001package org.apache.commons.ssl.org.bouncycastle.asn1.pkcs;
002
003import java.math.BigInteger;
004import java.util.Enumeration;
005
006import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1EncodableVector;
007import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Integer;
008import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Object;
009import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1OctetString;
010import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Primitive;
011import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Sequence;
012import org.apache.commons.ssl.org.bouncycastle.asn1.DERNull;
013import org.apache.commons.ssl.org.bouncycastle.asn1.DEROctetString;
014import org.apache.commons.ssl.org.bouncycastle.asn1.DERSequence;
015import org.apache.commons.ssl.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
016
017/**
018 * <pre>
019 *     PBKDF2-params ::= SEQUENCE {
020 *               salt CHOICE {
021 *                      specified OCTET STRING,
022 *                      otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
023 *               },
024 *              iterationCount INTEGER (1..MAX),
025 *              keyLength INTEGER (1..MAX) OPTIONAL,
026 *              prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
027 * </pre>
028 */
029public class PBKDF2Params
030    extends ASN1Object
031{
032    private static final AlgorithmIdentifier algid_hmacWithSHA1 = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA1, DERNull.INSTANCE);
033
034    private ASN1OctetString octStr;
035    private ASN1Integer      iterationCount;
036    private ASN1Integer      keyLength;
037    private AlgorithmIdentifier prf;
038
039    /**
040     * Create PBKDF2Params from the passed in object,
041     *
042     * @param obj either PBKDF2Params or an ASN2Sequence.
043     * @return a PBKDF2Params instance.
044     */
045    public static PBKDF2Params getInstance(
046        Object  obj)
047    {
048        if (obj instanceof PBKDF2Params)
049        {
050            return (PBKDF2Params)obj;
051        }
052
053        if (obj != null)
054        {
055            return new PBKDF2Params(ASN1Sequence.getInstance(obj));
056        }
057
058        return null;
059    }
060
061    /**
062     * Create a PBKDF2Params with the specified salt, iteration count, and algid-hmacWithSHA1 for the prf.
063     *
064     * @param salt  input salt.
065     * @param iterationCount input iteration count.
066     */
067    public PBKDF2Params(
068        byte[]  salt,
069        int     iterationCount)
070    {
071        this.octStr = new DEROctetString(salt);
072        this.iterationCount = new ASN1Integer(iterationCount);
073    }
074
075    /**
076     * Create a PBKDF2Params with the specified salt, iteration count, keyLength, and algid-hmacWithSHA1 for the prf.
077     *
078     * @param salt  input salt.
079     * @param iterationCount input iteration count.
080     * @param keyLength intended key length to be produced.
081     */
082    public PBKDF2Params(
083        byte[]  salt,
084        int     iterationCount,
085        int     keyLength)
086    {
087        this(salt, iterationCount);
088
089        this.keyLength = new ASN1Integer(keyLength);
090    }
091
092    /**
093     * Create a PBKDF2Params with the specified salt, iteration count, keyLength, and a defined prf.
094     *
095     * @param salt  input salt.
096     * @param iterationCount input iteration count.
097     * @param keyLength intended key length to be produced.
098     * @param prf the pseudo-random function to use.
099     */
100    public PBKDF2Params(
101        byte[]  salt,
102        int     iterationCount,
103        int     keyLength,
104        AlgorithmIdentifier prf)
105    {
106        this(salt, iterationCount);
107
108        this.keyLength = new ASN1Integer(keyLength);
109        this.prf = prf;
110    }
111
112    /**
113     * Create a PBKDF2Params with the specified salt, iteration count, and a defined prf.
114     *
115     * @param salt  input salt.
116     * @param iterationCount input iteration count.
117     * @param prf the pseudo-random function to use.
118     */
119    public PBKDF2Params(
120        byte[]  salt,
121        int     iterationCount,
122        AlgorithmIdentifier prf)
123    {
124        this(salt, iterationCount);
125        this.prf = prf;
126    }
127
128    private PBKDF2Params(
129        ASN1Sequence  seq)
130    {
131        Enumeration e = seq.getObjects();
132
133        octStr = (ASN1OctetString)e.nextElement();
134        iterationCount = (ASN1Integer)e.nextElement();
135
136        if (e.hasMoreElements())
137        {
138            Object o = e.nextElement();
139
140            if (o instanceof ASN1Integer)
141            {
142                keyLength = ASN1Integer.getInstance(o);
143                if (e.hasMoreElements())
144                {
145                    o = e.nextElement();
146                }
147                else
148                {
149                    o = null;
150                }
151            }
152            else
153            {
154                keyLength = null;
155            }
156
157            if (o != null)
158            {
159                prf = AlgorithmIdentifier.getInstance(o);
160            }
161        }
162    }
163
164    /**
165     * Return the salt to use.
166     *
167     * @return the input salt.
168     */
169    public byte[] getSalt()
170    {
171        return octStr.getOctets();
172    }
173
174    /**
175     * Return the iteration count to use.
176     *
177     * @return the input iteration count.
178     */
179    public BigInteger getIterationCount()
180    {
181        return iterationCount.getValue();
182    }
183
184    /**
185     * Return the intended length in octets of the derived key.
186     *
187     * @return length in octets for derived key, if specified.
188     */
189    public BigInteger getKeyLength()
190    {
191        if (keyLength != null)
192        {
193            return keyLength.getValue();
194        }
195
196        return null;
197    }
198
199    /**
200     * Return true if the PRF is the default (hmacWithSHA1)
201     *
202     * @return true if PRF is default, false otherwise.
203     */
204    public boolean isDefaultPrf()
205    {
206        return prf == null || prf.equals(algid_hmacWithSHA1);
207    }
208
209    /**
210     * Return the algId of the underlying pseudo random function to use.
211     *
212     * @return the prf algorithm identifier.
213     */
214    public AlgorithmIdentifier getPrf()
215    {
216        if (prf != null)
217        {
218            return prf;
219        }
220
221        return algid_hmacWithSHA1;
222    }
223
224    /**
225     * Return an ASN.1 structure suitable for encoding.
226     *
227     * @return the object as an ASN.1 encodable structure.
228     */
229    public ASN1Primitive toASN1Primitive()
230    {
231        ASN1EncodableVector  v = new ASN1EncodableVector();
232
233        v.add(octStr);
234        v.add(iterationCount);
235
236        if (keyLength != null)
237        {
238            v.add(keyLength);
239        }
240
241        if (prf != null && !prf.equals(algid_hmacWithSHA1))
242        {
243            v.add(prf);
244        }
245
246        return new DERSequence(v);
247    }
248}