001: package org.bouncycastle.crypto.generators;
002:
003: import org.bouncycastle.crypto.CipherParameters;
004: import org.bouncycastle.crypto.Digest;
005: import org.bouncycastle.crypto.ExtendedDigest;
006: import org.bouncycastle.crypto.PBEParametersGenerator;
007: import org.bouncycastle.crypto.params.KeyParameter;
008: import org.bouncycastle.crypto.params.ParametersWithIV;
009:
010: /**
011: * Generator for PBE derived keys and ivs as defined by PKCS 12 V1.0.
012: * <p>
013: * The document this implementation is based on can be found at
014: * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/index.html>
015: * RSA's PKCS12 Page</a>
016: */
017: public class PKCS12ParametersGenerator extends PBEParametersGenerator {
018: public static final int KEY_MATERIAL = 1;
019: public static final int IV_MATERIAL = 2;
020: public static final int MAC_MATERIAL = 3;
021:
022: private Digest digest;
023:
024: private int u;
025: private int v;
026:
027: /**
028: * Construct a PKCS 12 Parameters generator. This constructor will
029: * accept any digest which also implements ExtendedDigest.
030: *
031: * @param digest the digest to be used as the source of derived keys.
032: * @exception IllegalArgumentException if an unknown digest is passed in.
033: */
034: public PKCS12ParametersGenerator(Digest digest) {
035: this .digest = digest;
036: if (digest instanceof ExtendedDigest) {
037: u = digest.getDigestSize();
038: v = ((ExtendedDigest) digest).getByteLength();
039: } else {
040: throw new IllegalArgumentException("Digest "
041: + digest.getAlgorithmName() + " unsupported");
042: }
043: }
044:
045: /**
046: * add a + b + 1, returning the result in a. The a value is treated
047: * as a BigInteger of length (b.length * 8) bits. The result is
048: * modulo 2^b.length in case of overflow.
049: */
050: private void adjust(byte[] a, int aOff, byte[] b) {
051: int x = (b[b.length - 1] & 0xff)
052: + (a[aOff + b.length - 1] & 0xff) + 1;
053:
054: a[aOff + b.length - 1] = (byte) x;
055: x >>>= 8;
056:
057: for (int i = b.length - 2; i >= 0; i--) {
058: x += (b[i] & 0xff) + (a[aOff + i] & 0xff);
059: a[aOff + i] = (byte) x;
060: x >>>= 8;
061: }
062: }
063:
064: /**
065: * generation of a derived key ala PKCS12 V1.0.
066: */
067: private byte[] generateDerivedKey(int idByte, int n) {
068: byte[] D = new byte[v];
069: byte[] dKey = new byte[n];
070:
071: for (int i = 0; i != D.length; i++) {
072: D[i] = (byte) idByte;
073: }
074:
075: byte[] S;
076:
077: if ((salt != null) && (salt.length != 0)) {
078: S = new byte[v * ((salt.length + v - 1) / v)];
079:
080: for (int i = 0; i != S.length; i++) {
081: S[i] = salt[i % salt.length];
082: }
083: } else {
084: S = new byte[0];
085: }
086:
087: byte[] P;
088:
089: if ((password != null) && (password.length != 0)) {
090: P = new byte[v * ((password.length + v - 1) / v)];
091:
092: for (int i = 0; i != P.length; i++) {
093: P[i] = password[i % password.length];
094: }
095: } else {
096: P = new byte[0];
097: }
098:
099: byte[] I = new byte[S.length + P.length];
100:
101: System.arraycopy(S, 0, I, 0, S.length);
102: System.arraycopy(P, 0, I, S.length, P.length);
103:
104: byte[] B = new byte[v];
105: int c = (n + u - 1) / u;
106:
107: for (int i = 1; i <= c; i++) {
108: byte[] A = new byte[u];
109:
110: digest.update(D, 0, D.length);
111: digest.update(I, 0, I.length);
112: digest.doFinal(A, 0);
113: for (int j = 1; j != iterationCount; j++) {
114: digest.update(A, 0, A.length);
115: digest.doFinal(A, 0);
116: }
117:
118: for (int j = 0; j != B.length; j++) {
119: B[j] = A[j % A.length];
120: }
121:
122: for (int j = 0; j != I.length / v; j++) {
123: adjust(I, j * v, B);
124: }
125:
126: if (i == c) {
127: System.arraycopy(A, 0, dKey, (i - 1) * u, dKey.length
128: - ((i - 1) * u));
129: } else {
130: System.arraycopy(A, 0, dKey, (i - 1) * u, A.length);
131: }
132: }
133:
134: return dKey;
135: }
136:
137: /**
138: * Generate a key parameter derived from the password, salt, and iteration
139: * count we are currently initialised with.
140: *
141: * @param keySize the size of the key we want (in bits)
142: * @return a KeyParameter object.
143: */
144: public CipherParameters generateDerivedParameters(int keySize) {
145: keySize = keySize / 8;
146:
147: byte[] dKey = generateDerivedKey(KEY_MATERIAL, keySize);
148:
149: return new KeyParameter(dKey, 0, keySize);
150: }
151:
152: /**
153: * Generate a key with initialisation vector parameter derived from
154: * the password, salt, and iteration count we are currently initialised
155: * with.
156: *
157: * @param keySize the size of the key we want (in bits)
158: * @param ivSize the size of the iv we want (in bits)
159: * @return a ParametersWithIV object.
160: */
161: public CipherParameters generateDerivedParameters(int keySize,
162: int ivSize) {
163: keySize = keySize / 8;
164: ivSize = ivSize / 8;
165:
166: byte[] dKey = generateDerivedKey(KEY_MATERIAL, keySize);
167:
168: byte[] iv = generateDerivedKey(IV_MATERIAL, ivSize);
169:
170: return new ParametersWithIV(new KeyParameter(dKey, 0, keySize),
171: iv, 0, ivSize);
172: }
173:
174: /**
175: * Generate a key parameter for use with a MAC derived from the password,
176: * salt, and iteration count we are currently initialised with.
177: *
178: * @param keySize the size of the key we want (in bits)
179: * @return a KeyParameter object.
180: */
181: public CipherParameters generateDerivedMacParameters(int keySize) {
182: keySize = keySize / 8;
183:
184: byte[] dKey = generateDerivedKey(MAC_MATERIAL, keySize);
185:
186: return new KeyParameter(dKey, 0, keySize);
187: }
188: }
|