001: package org.bouncycastle.crypto.agreement.kdf;
002:
003: import org.bouncycastle.asn1.ASN1EncodableVector;
004: import org.bouncycastle.asn1.DERObjectIdentifier;
005: import org.bouncycastle.asn1.DEROctetString;
006: import org.bouncycastle.asn1.DERSequence;
007: import org.bouncycastle.asn1.DERTaggedObject;
008: import org.bouncycastle.crypto.DataLengthException;
009: import org.bouncycastle.crypto.DerivationFunction;
010: import org.bouncycastle.crypto.DerivationParameters;
011: import org.bouncycastle.crypto.Digest;
012:
013: /**
014: * RFC 2631 Diffie-hellman KEK derivation function.
015: */
016: public class DHKEKGenerator implements DerivationFunction {
017: private final Digest digest;
018:
019: private DERObjectIdentifier algorithm;
020: private int keySize;
021: private byte[] z;
022: private byte[] partyAInfo;
023:
024: public DHKEKGenerator(Digest digest) {
025: this .digest = digest;
026: }
027:
028: public void init(DerivationParameters param) {
029: DHKDFParameters params = (DHKDFParameters) param;
030:
031: this .algorithm = params.getAlgorithm();
032: this .keySize = params.getKeySize();
033: this .z = params.getZ();
034: this .partyAInfo = params.getExtraInfo();
035: }
036:
037: public Digest getDigest() {
038: return digest;
039: }
040:
041: public int generateBytes(byte[] out, int outOff, int len)
042: throws DataLengthException, IllegalArgumentException {
043: if ((out.length - len) < outOff) {
044: throw new DataLengthException("output buffer too small");
045: }
046:
047: long oBytes = len;
048: int outLen = digest.getDigestSize();
049:
050: //
051: // this is at odds with the standard implementation, the
052: // maximum value should be hBits * (2^32 - 1) where hBits
053: // is the digest output size in bits. We can't have an
054: // array with a long index at the moment...
055: //
056: if (oBytes > ((2L << 32) - 1)) {
057: throw new IllegalArgumentException(
058: "Output length too large");
059: }
060:
061: int cThreshold = (int) ((oBytes + outLen - 1) / outLen);
062:
063: byte[] dig = new byte[digest.getDigestSize()];
064:
065: int counter = 1;
066:
067: for (int i = 0; i < cThreshold; i++) {
068: digest.update(z, 0, z.length);
069:
070: // OtherInfo
071: ASN1EncodableVector v1 = new ASN1EncodableVector();
072: // KeySpecificInfo
073: ASN1EncodableVector v2 = new ASN1EncodableVector();
074:
075: v2.add(algorithm);
076: v2.add(new DEROctetString(integerToBytes(counter)));
077:
078: v1.add(new DERSequence(v2));
079:
080: if (partyAInfo != null) {
081: v1.add(new DERTaggedObject(true, 0, new DEROctetString(
082: partyAInfo)));
083: }
084:
085: v1.add(new DERTaggedObject(true, 2, new DEROctetString(
086: integerToBytes(keySize))));
087:
088: byte[] other = new DERSequence(v1).getDEREncoded();
089:
090: digest.update(other, 0, other.length);
091:
092: digest.doFinal(dig, 0);
093:
094: if (len > outLen) {
095: System.arraycopy(dig, 0, out, outOff, outLen);
096: outOff += outLen;
097: len -= outLen;
098: } else {
099: System.arraycopy(dig, 0, out, outOff, len);
100: }
101:
102: counter++;
103: }
104:
105: digest.reset();
106:
107: return len;
108: }
109:
110: private byte[] integerToBytes(int keySize) {
111: byte[] val = new byte[4];
112:
113: val[0] = (byte) (keySize >> 24);
114: val[1] = (byte) (keySize >> 16);
115: val[2] = (byte) (keySize >> 8);
116: val[3] = (byte) keySize;
117:
118: return val;
119: }
120: }
|