blob: 268ae9b110704a69e53f03cd50c939fe943c9e73 [file] [log] [blame]
package org.bouncycastle.crypto.generators;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.DerivationFunction;
import org.bouncycastle.crypto.DerivationParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.params.ISO18033KDFParameters;
import org.bouncycastle.crypto.params.KDFParameters;
/**
* Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
* <br>
* This implementation is based on ISO 18033/P1363a.
*/
public class BaseKDFBytesGenerator
implements DerivationFunction
{
private int counterStart;
private Digest digest;
private byte[] shared;
private byte[] iv;
/**
* Construct a KDF Parameters generator.
* <p>
* @param counterStart value of counter.
* @param digest the digest to be used as the source of derived keys.
*/
protected BaseKDFBytesGenerator(
int counterStart,
Digest digest)
{
this.counterStart = counterStart;
this.digest = digest;
}
public void init(
DerivationParameters param)
{
if (param instanceof KDFParameters)
{
KDFParameters p = (KDFParameters)param;
shared = p.getSharedSecret();
iv = p.getIV();
}
else if (param instanceof ISO18033KDFParameters)
{
ISO18033KDFParameters p = (ISO18033KDFParameters)param;
shared = p.getSeed();
iv = null;
}
else
{
throw new IllegalArgumentException("KDF parameters required for KDF2Generator");
}
}
/**
* return the underlying digest.
*/
public Digest getDigest()
{
return digest;
}
/**
* fill len bytes of the output buffer with bytes generated from
* the derivation function.
*
* @throws IllegalArgumentException if the size of the request will cause an overflow.
* @throws DataLengthException if the out buffer is too small.
*/
public int generateBytes(
byte[] out,
int outOff,
int len)
throws DataLengthException, IllegalArgumentException
{
if ((out.length - len) < outOff)
{
throw new DataLengthException("output buffer too small");
}
long oBytes = len;
int outLen = digest.getDigestSize();
//
// this is at odds with the standard implementation, the
// maximum value should be hBits * (2^32 - 1) where hBits
// is the digest output size in bits. We can't have an
// array with a long index at the moment...
//
if (oBytes > ((2L << 32) - 1))
{
throw new IllegalArgumentException("Output length too large");
}
int cThreshold = (int)((oBytes + outLen - 1) / outLen);
byte[] dig = null;
dig = new byte[digest.getDigestSize()];
int counter = counterStart;
for (int i = 0; i < cThreshold; i++)
{
digest.update(shared, 0, shared.length);
digest.update((byte)(counter >> 24));
digest.update((byte)(counter >> 16));
digest.update((byte)(counter >> 8));
digest.update((byte)counter);
if (iv != null)
{
digest.update(iv, 0, iv.length);
}
digest.doFinal(dig, 0);
if (len > outLen)
{
System.arraycopy(dig, 0, out, outOff, outLen);
outOff += outLen;
len -= outLen;
}
else
{
System.arraycopy(dig, 0, out, outOff, len);
}
counter++;
}
digest.reset();
return len;
}
}