summary refs log tree commit diff
path: root/Crypto/src/crypto/agreement/kdf/DHKekGenerator.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Crypto/src/crypto/agreement/kdf/DHKekGenerator.cs')
-rw-r--r--Crypto/src/crypto/agreement/kdf/DHKekGenerator.cs129
1 files changed, 129 insertions, 0 deletions
diff --git a/Crypto/src/crypto/agreement/kdf/DHKekGenerator.cs b/Crypto/src/crypto/agreement/kdf/DHKekGenerator.cs
new file mode 100644
index 000000000..fa2921539
--- /dev/null
+++ b/Crypto/src/crypto/agreement/kdf/DHKekGenerator.cs
@@ -0,0 +1,129 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Kdf
+{
+	/**
+	* RFC 2631 Diffie-hellman KEK derivation function.
+	*/
+	public class DHKekGenerator
+		: IDerivationFunction
+	{
+		private readonly IDigest digest;
+
+		private DerObjectIdentifier	algorithm;
+		private int					keySize;
+		private byte[]				z;
+		private byte[]				partyAInfo;
+
+		public DHKekGenerator(
+			IDigest digest)
+		{
+			this.digest = digest;
+		}
+
+		public void Init(
+			IDerivationParameters param)
+		{
+			DHKdfParameters parameters = (DHKdfParameters)param;
+
+			this.algorithm = parameters.Algorithm;
+			this.keySize = parameters.KeySize;
+			this.z = parameters.GetZ(); // TODO Clone?
+			this.partyAInfo = parameters.GetExtraInfo(); // TODO Clone?
+		}
+
+		public IDigest Digest
+		{
+			get { return digest; }
+		}
+
+		public int GenerateBytes(
+			byte[]	outBytes,
+			int		outOff,
+			int		len)
+		{
+			if ((outBytes.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 ArgumentException("Output length too large");
+			}
+
+			int cThreshold = (int)((oBytes + outLen - 1) / outLen);
+
+			byte[] dig = new byte[digest.GetDigestSize()];
+
+			int counter = 1;
+
+			for (int i = 0; i < cThreshold; i++)
+			{
+				digest.BlockUpdate(z, 0, z.Length);
+
+				// KeySpecificInfo
+				DerSequence keyInfo = new DerSequence(
+					algorithm,
+					new DerOctetString(integerToBytes(counter)));
+
+				// OtherInfo
+				Asn1EncodableVector v1 = new Asn1EncodableVector(keyInfo);
+
+				if (partyAInfo != null)
+				{
+					v1.Add(new DerTaggedObject(true, 0, new DerOctetString(partyAInfo)));
+				}
+
+				v1.Add(new DerTaggedObject(true, 2, new DerOctetString(integerToBytes(keySize))));
+
+				byte[] other = new DerSequence(v1).GetDerEncoded();
+
+				digest.BlockUpdate(other, 0, other.Length);
+
+				digest.DoFinal(dig, 0);
+
+				if (len > outLen)
+				{
+					Array.Copy(dig, 0, outBytes, outOff, outLen);
+					outOff += outLen;
+					len -= outLen;
+				}
+				else
+				{
+					Array.Copy(dig, 0, outBytes, outOff, len);
+				}
+
+				counter++;
+			}
+
+			digest.Reset();
+
+			return len;
+		}
+
+		private byte[] integerToBytes(
+			int keySize)
+		{
+			byte[] val = new byte[4];
+
+			val[0] = (byte)(keySize >> 24);
+			val[1] = (byte)(keySize >> 16);
+			val[2] = (byte)(keySize >> 8);
+			val[3] = (byte)keySize;
+
+			return val;
+		}
+	}
+}