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 */ getInstance( Object obj)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 */ PBKDF2Params( byte[] salt, int iterationCount)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 */ PBKDF2Params( byte[] salt, int iterationCount, int keyLength)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 */ PBKDF2Params( byte[] salt, int iterationCount, int keyLength, AlgorithmIdentifier prf)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 */ PBKDF2Params( byte[] salt, int iterationCount, AlgorithmIdentifier prf)126 public PBKDF2Params( 127 byte[] salt, 128 int iterationCount, 129 AlgorithmIdentifier prf) 130 { 131 this(salt, iterationCount, 0, prf); 132 } 133 PBKDF2Params( ASN1Sequence seq)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 */ getSalt()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 */ getIterationCount()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 */ getKeyLength()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 */ isDefaultPrf()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 */ getPrf()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 */ toASN1Primitive()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