001: package org.bouncycastle.crypto.generators;
002:
003: import org.bouncycastle.crypto.DataLengthException;
004: import org.bouncycastle.crypto.DerivationFunction;
005: import org.bouncycastle.crypto.DerivationParameters;
006: import org.bouncycastle.crypto.Digest;
007: import org.bouncycastle.crypto.params.ISO18033KDFParameters;
008: import org.bouncycastle.crypto.params.KDFParameters;
009:
010: /**
011: * Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
012: * <br>
013: * This implementation is based on ISO 18033/P1363a.
014: */
015: public class BaseKDFBytesGenerator implements DerivationFunction {
016: private int counterStart;
017: private Digest digest;
018: private byte[] shared;
019: private byte[] iv;
020:
021: /**
022: * Construct a KDF Parameters generator.
023: * <p>
024: * @param counterStart value of counter.
025: * @param digest the digest to be used as the source of derived keys.
026: */
027: protected BaseKDFBytesGenerator(int counterStart, Digest digest) {
028: this .counterStart = counterStart;
029: this .digest = digest;
030: }
031:
032: public void init(DerivationParameters param) {
033: if (param instanceof KDFParameters) {
034: KDFParameters p = (KDFParameters) param;
035:
036: shared = p.getSharedSecret();
037: iv = p.getIV();
038: } else if (param instanceof ISO18033KDFParameters) {
039: ISO18033KDFParameters p = (ISO18033KDFParameters) param;
040:
041: shared = p.getSeed();
042: iv = null;
043: } else {
044: throw new IllegalArgumentException(
045: "KDF parameters required for KDF2Generator");
046: }
047: }
048:
049: /**
050: * return the underlying digest.
051: */
052: public Digest getDigest() {
053: return digest;
054: }
055:
056: /**
057: * fill len bytes of the output buffer with bytes generated from
058: * the derivation function.
059: *
060: * @throws IllegalArgumentException if the size of the request will cause an overflow.
061: * @throws DataLengthException if the out buffer is too small.
062: */
063: public int generateBytes(byte[] out, int outOff, int len)
064: throws DataLengthException, IllegalArgumentException {
065: if ((out.length - len) < outOff) {
066: throw new DataLengthException("output buffer too small");
067: }
068:
069: long oBytes = len;
070: int outLen = digest.getDigestSize();
071:
072: //
073: // this is at odds with the standard implementation, the
074: // maximum value should be hBits * (2^32 - 1) where hBits
075: // is the digest output size in bits. We can't have an
076: // array with a long index at the moment...
077: //
078: if (oBytes > ((2L << 32) - 1)) {
079: throw new IllegalArgumentException(
080: "Output length too large");
081: }
082:
083: int cThreshold = (int) ((oBytes + outLen - 1) / outLen);
084:
085: byte[] dig = null;
086:
087: dig = new byte[digest.getDigestSize()];
088:
089: int counter = counterStart;
090:
091: for (int i = 0; i < cThreshold; i++) {
092: digest.update(shared, 0, shared.length);
093:
094: digest.update((byte) (counter >> 24));
095: digest.update((byte) (counter >> 16));
096: digest.update((byte) (counter >> 8));
097: digest.update((byte) counter);
098:
099: if (iv != null) {
100: digest.update(iv, 0, iv.length);
101: }
102:
103: digest.doFinal(dig, 0);
104:
105: if (len > outLen) {
106: System.arraycopy(dig, 0, out, outOff, outLen);
107: outOff += outLen;
108: len -= outLen;
109: } else {
110: System.arraycopy(dig, 0, out, outOff, len);
111: }
112:
113: counter++;
114: }
115:
116: digest.reset();
117:
118: return len;
119: }
120: }
|