PKCS12ParametersGenerator.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
1package org.bouncycastle.crypto.generators; 2 3import org.bouncycastle.crypto.CipherParameters; 4import org.bouncycastle.crypto.Digest; 5import org.bouncycastle.crypto.ExtendedDigest; 6import org.bouncycastle.crypto.PBEParametersGenerator; 7import org.bouncycastle.crypto.params.KeyParameter; 8import org.bouncycastle.crypto.params.ParametersWithIV; 9 10/** 11 * Generator for PBE derived keys and ivs as defined by PKCS 12 V1.0. 12 * <p> 13 * The document this implementation is based on can be found at 14 * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/index.html> 15 * RSA's PKCS12 Page</a> 16 */ 17public class PKCS12ParametersGenerator 18 extends PBEParametersGenerator 19{ 20 public static final int KEY_MATERIAL = 1; 21 public static final int IV_MATERIAL = 2; 22 public static final int MAC_MATERIAL = 3; 23 24 private Digest digest; 25 26 private int u; 27 private int v; 28 29 /** 30 * Construct a PKCS 12 Parameters generator. This constructor will 31 * accept any digest which also implements ExtendedDigest. 32 * 33 * @param digest the digest to be used as the source of derived keys. 34 * @exception IllegalArgumentException if an unknown digest is passed in. 35 */ 36 public PKCS12ParametersGenerator( 37 Digest digest) 38 { 39 this.digest = digest; 40 if (digest instanceof ExtendedDigest) 41 { 42 u = digest.getDigestSize(); 43 v = ((ExtendedDigest)digest).getByteLength(); 44 } 45 else 46 { 47 throw new IllegalArgumentException("Digest " + digest.getAlgorithmName() + " unsupported"); 48 } 49 } 50 51 /** 52 * add a + b + 1, returning the result in a. The a value is treated 53 * as a BigInteger of length (b.length * 8) bits. The result is 54 * modulo 2^b.length in case of overflow. 55 */ 56 private void adjust( 57 byte[] a, 58 int aOff, 59 byte[] b) 60 { 61 int x = (b[b.length - 1] & 0xff) + (a[aOff + b.length - 1] & 0xff) + 1; 62 63 a[aOff + b.length - 1] = (byte)x; 64 x >>>= 8; 65 66 for (int i = b.length - 2; i >= 0; i--) 67 { 68 x += (b[i] & 0xff) + (a[aOff + i] & 0xff); 69 a[aOff + i] = (byte)x; 70 x >>>= 8; 71 } 72 } 73 74 /** 75 * generation of a derived key ala PKCS12 V1.0. 76 */ 77 private byte[] generateDerivedKey( 78 int idByte, 79 int n) 80 { 81 byte[] D = new byte[v]; 82 byte[] dKey = new byte[n]; 83 84 for (int i = 0; i != D.length; i++) 85 { 86 D[i] = (byte)idByte; 87 } 88 89 byte[] S; 90 91 if ((salt != null) && (salt.length != 0)) 92 { 93 S = new byte[v * ((salt.length + v - 1) / v)]; 94 95 for (int i = 0; i != S.length; i++) 96 { 97 S[i] = salt[i % salt.length]; 98 } 99 } 100 else 101 { 102 S = new byte[0]; 103 } 104 105 byte[] P; 106 107 if ((password != null) && (password.length != 0)) 108 { 109 P = new byte[v * ((password.length + v - 1) / v)]; 110 111 for (int i = 0; i != P.length; i++) 112 { 113 P[i] = password[i % password.length]; 114 } 115 } 116 else 117 { 118 P = new byte[0]; 119 } 120 121 byte[] I = new byte[S.length + P.length]; 122 123 System.arraycopy(S, 0, I, 0, S.length); 124 System.arraycopy(P, 0, I, S.length, P.length); 125 126 byte[] B = new byte[v]; 127 int c = (n + u - 1) / u; 128 129 for (int i = 1; i <= c; i++) 130 { 131 byte[] A = new byte[u]; 132 133 digest.update(D, 0, D.length); 134 digest.update(I, 0, I.length); 135 digest.doFinal(A, 0); 136 for (int j = 1; j < iterationCount; j++) 137 { 138 digest.update(A, 0, A.length); 139 digest.doFinal(A, 0); 140 } 141 142 for (int j = 0; j != B.length; j++) 143 { 144 B[j] = A[j % A.length]; 145 } 146 147 for (int j = 0; j != I.length / v; j++) 148 { 149 adjust(I, j * v, B); 150 } 151 152 if (i == c) 153 { 154 System.arraycopy(A, 0, dKey, (i - 1) * u, dKey.length - ((i - 1) * u)); 155 } 156 else 157 { 158 System.arraycopy(A, 0, dKey, (i - 1) * u, A.length); 159 } 160 } 161 162 return dKey; 163 } 164 165 /** 166 * Generate a key parameter derived from the password, salt, and iteration 167 * count we are currently initialised with. 168 * 169 * @param keySize the size of the key we want (in bits) 170 * @return a KeyParameter object. 171 */ 172 public CipherParameters generateDerivedParameters( 173 int keySize) 174 { 175 keySize = keySize / 8; 176 177 byte[] dKey = generateDerivedKey(KEY_MATERIAL, keySize); 178 179 return new KeyParameter(dKey, 0, keySize); 180 } 181 182 /** 183 * Generate a key with initialisation vector parameter derived from 184 * the password, salt, and iteration count we are currently initialised 185 * with. 186 * 187 * @param keySize the size of the key we want (in bits) 188 * @param ivSize the size of the iv we want (in bits) 189 * @return a ParametersWithIV object. 190 */ 191 public CipherParameters generateDerivedParameters( 192 int keySize, 193 int ivSize) 194 { 195 keySize = keySize / 8; 196 ivSize = ivSize / 8; 197 198 byte[] dKey = generateDerivedKey(KEY_MATERIAL, keySize); 199 200 byte[] iv = generateDerivedKey(IV_MATERIAL, ivSize); 201 202 return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize); 203 } 204 205 /** 206 * Generate a key parameter for use with a MAC derived from the password, 207 * salt, and iteration count we are currently initialised with. 208 * 209 * @param keySize the size of the key we want (in bits) 210 * @return a KeyParameter object. 211 */ 212 public CipherParameters generateDerivedMacParameters( 213 int keySize) 214 { 215 keySize = keySize / 8; 216 217 byte[] dKey = generateDerivedKey(MAC_MATERIAL, keySize); 218 219 return new KeyParameter(dKey, 0, keySize); 220 } 221} 222