001: package org.bouncycastle.crypto.generators;
002:
003: import org.bouncycastle.crypto.CipherParameters;
004: import org.bouncycastle.crypto.Mac;
005: import org.bouncycastle.crypto.PBEParametersGenerator;
006: import org.bouncycastle.crypto.digests.SHA1Digest;
007: import org.bouncycastle.crypto.macs.HMac;
008: import org.bouncycastle.crypto.params.KeyParameter;
009: import org.bouncycastle.crypto.params.ParametersWithIV;
010:
011: /**
012: * Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 2.
013: * This generator uses a SHA-1 HMac as the calculation function.
014: * <p>
015: * The document this implementation is based on can be found at
016: * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html>
017: * RSA's PKCS5 Page</a>
018: */
019: public class PKCS5S2ParametersGenerator extends PBEParametersGenerator {
020: private Mac hMac = new HMac(new SHA1Digest());
021:
022: /**
023: * construct a PKCS5 Scheme 2 Parameters generator.
024: */
025: public PKCS5S2ParametersGenerator() {
026: }
027:
028: private void F(byte[] P, byte[] S, int c, byte[] iBuf, byte[] out,
029: int outOff) {
030: byte[] state = new byte[hMac.getMacSize()];
031: CipherParameters param = new KeyParameter(P);
032:
033: hMac.init(param);
034:
035: if (S != null) {
036: hMac.update(S, 0, S.length);
037: }
038:
039: hMac.update(iBuf, 0, iBuf.length);
040:
041: hMac.doFinal(state, 0);
042:
043: System.arraycopy(state, 0, out, outOff, state.length);
044:
045: if (c == 0) {
046: throw new IllegalArgumentException(
047: "iteration count must be at least 1.");
048: }
049:
050: for (int count = 1; count < c; count++) {
051: hMac.init(param);
052: hMac.update(state, 0, state.length);
053: hMac.doFinal(state, 0);
054:
055: for (int j = 0; j != state.length; j++) {
056: out[outOff + j] ^= state[j];
057: }
058: }
059: }
060:
061: private void intToOctet(byte[] buf, int i) {
062: buf[0] = (byte) (i >>> 24);
063: buf[1] = (byte) (i >>> 16);
064: buf[2] = (byte) (i >>> 8);
065: buf[3] = (byte) i;
066: }
067:
068: private byte[] generateDerivedKey(int dkLen) {
069: int hLen = hMac.getMacSize();
070: int l = (dkLen + hLen - 1) / hLen;
071: byte[] iBuf = new byte[4];
072: byte[] out = new byte[l * hLen];
073:
074: for (int i = 1; i <= l; i++) {
075: intToOctet(iBuf, i);
076:
077: F(password, salt, iterationCount, iBuf, out, (i - 1) * hLen);
078: }
079:
080: return out;
081: }
082:
083: /**
084: * Generate a key parameter derived from the password, salt, and iteration
085: * count we are currently initialised with.
086: *
087: * @param keySize the size of the key we want (in bits)
088: * @return a KeyParameter object.
089: */
090: public CipherParameters generateDerivedParameters(int keySize) {
091: keySize = keySize / 8;
092:
093: byte[] dKey = generateDerivedKey(keySize);
094:
095: return new KeyParameter(dKey, 0, keySize);
096: }
097:
098: /**
099: * Generate a key with initialisation vector parameter derived from
100: * the password, salt, and iteration count we are currently initialised
101: * with.
102: *
103: * @param keySize the size of the key we want (in bits)
104: * @param ivSize the size of the iv we want (in bits)
105: * @return a ParametersWithIV object.
106: */
107: public CipherParameters generateDerivedParameters(int keySize,
108: int ivSize) {
109: keySize = keySize / 8;
110: ivSize = ivSize / 8;
111:
112: byte[] dKey = generateDerivedKey(keySize + ivSize);
113:
114: return new ParametersWithIV(new KeyParameter(dKey, 0, keySize),
115: dKey, keySize, ivSize);
116: }
117:
118: /**
119: * Generate a key parameter for use with a MAC derived from the password,
120: * salt, and iteration count we are currently initialised with.
121: *
122: * @param keySize the size of the key we want (in bits)
123: * @return a KeyParameter object.
124: */
125: public CipherParameters generateDerivedMacParameters(int keySize) {
126: return generateDerivedParameters(keySize);
127: }
128: }
|