package org.bouncycastle.crypto.agreement.kdf; 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.KDFParameters; /** * Generator for Concatenation Key Derivation Function defined in NIST SP 800-56A, Sect 5.8.1 */ public class ConcatenationKDFGenerator implements DerivationFunction { private Digest digest; private byte[] shared; private byte[] otherInfo; private int hLen; /** * @param digest the digest to be used as the source of generated bytes */ public ConcatenationKDFGenerator( Digest digest) { this.digest = digest; this.hLen = digest.getDigestSize(); } public void init( DerivationParameters param) { if (param instanceof KDFParameters) { KDFParameters p = (KDFParameters)param; shared = p.getSharedSecret(); otherInfo = p.getIV(); } else { throw new IllegalArgumentException("KDF parameters required for generator"); } } /** * return the underlying digest. */ public Digest getDigest() { return digest; } /** * int to octet string. */ private void ItoOSP( int i, byte[] sp) { sp[0] = (byte)(i >>> 24); sp[1] = (byte)(i >>> 16); sp[2] = (byte)(i >>> 8); sp[3] = (byte)(i >>> 0); } /** * fill len bytes of the output buffer with bytes generated from * the derivation function. * * @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"); } byte[] hashBuf = new byte[hLen]; byte[] C = new byte[4]; int counter = 1; int outputLen = 0; digest.reset(); if (len > hLen) { do { ItoOSP(counter, C); digest.update(C, 0, C.length); digest.update(shared, 0, shared.length); digest.update(otherInfo, 0, otherInfo.length); digest.doFinal(hashBuf, 0); System.arraycopy(hashBuf, 0, out, outOff + outputLen, hLen); outputLen += hLen; } while ((counter++) < (len / hLen)); } if (outputLen < len) { ItoOSP(counter, C); digest.update(C, 0, C.length); digest.update(shared, 0, shared.length); digest.update(otherInfo, 0, otherInfo.length); digest.doFinal(hashBuf, 0); System.arraycopy(hashBuf, 0, out, outOff + outputLen, len - outputLen); } return len; } }