1package org.bouncycastle.asn1.pkcs; 2 3import java.math.BigInteger; 4import java.util.Enumeration; 5 6import org.bouncycastle.asn1.ASN1EncodableVector; 7import org.bouncycastle.asn1.ASN1Integer; 8import org.bouncycastle.asn1.ASN1Object; 9import org.bouncycastle.asn1.ASN1OctetString; 10import org.bouncycastle.asn1.ASN1Primitive; 11import org.bouncycastle.asn1.ASN1Sequence; 12import org.bouncycastle.asn1.DERNull; 13import org.bouncycastle.asn1.DEROctetString; 14import org.bouncycastle.asn1.DERSequence; 15import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 16 17/** 18 * <pre> 19 * PBKDF2-params ::= SEQUENCE { 20 * salt CHOICE { 21 * specified OCTET STRING, 22 * otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} 23 * }, 24 * iterationCount INTEGER (1..MAX), 25 * keyLength INTEGER (1..MAX) OPTIONAL, 26 * prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 } 27 * </pre> 28 */ 29public class PBKDF2Params 30 extends ASN1Object 31{ 32 private static final AlgorithmIdentifier algid_hmacWithSHA1 = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA1, DERNull.INSTANCE); 33 34 private ASN1OctetString octStr; 35 private ASN1Integer iterationCount; 36 private ASN1Integer keyLength; 37 private AlgorithmIdentifier prf; 38 39 /** 40 * Create PBKDF2Params from the passed in object, 41 * 42 * @param obj either PBKDF2Params or an ASN2Sequence. 43 * @return a PBKDF2Params instance. 44 */ 45 public static PBKDF2Params getInstance( 46 Object obj) 47 { 48 if (obj instanceof PBKDF2Params) 49 { 50 return (PBKDF2Params)obj; 51 } 52 53 if (obj != null) 54 { 55 return new PBKDF2Params(ASN1Sequence.getInstance(obj)); 56 } 57 58 return null; 59 } 60 61 /** 62 * Create a PBKDF2Params with the specified salt, iteration count, and algid-hmacWithSHA1 for the prf. 63 * 64 * @param salt input salt. 65 * @param iterationCount input iteration count. 66 */ 67 public PBKDF2Params( 68 byte[] salt, 69 int iterationCount) 70 { 71 this.octStr = new DEROctetString(salt); 72 this.iterationCount = new ASN1Integer(iterationCount); 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); 88 89 this.keyLength = new ASN1Integer(keyLength); 90 } 91 92 /** 93 * Create a PBKDF2Params with the specified salt, iteration count, keyLength, and a defined prf. 94 * 95 * @param salt input salt. 96 * @param iterationCount input iteration count. 97 * @param keyLength intended key length to be produced. 98 * @param prf the pseudo-random function to use. 99 */ 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} 249