diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2019-05-06 17:43:55 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2019-05-06 17:43:55 +0700 |
commit | 7d2352460a63a1e7764c7083d8e82f68599637a2 (patch) | |
tree | 411d60a69a749e8e99e90f245397d1dafcf8f61f /crypto/src | |
parent | TLS: Clone in GetPsk since TlsPskKeyExchange will clear after use (diff) | |
parent | Merge branch 'master' of git.bouncycastle.org:bc-csharp (diff) | |
download | BouncyCastle.NET-ed25519-7d2352460a63a1e7764c7083d8e82f68599637a2.tar.xz |
Merge branch 'master' of git.bouncycastle.org:bc-csharp
Diffstat (limited to 'crypto/src')
7 files changed, 789 insertions, 0 deletions
diff --git a/crypto/src/crypto/IMacDerivationFunction.cs b/crypto/src/crypto/IMacDerivationFunction.cs new file mode 100644 index 000000000..7297cd854 --- /dev/null +++ b/crypto/src/crypto/IMacDerivationFunction.cs @@ -0,0 +1,7 @@ +namespace Org.BouncyCastle.Crypto +{ + public interface IMacDerivationFunction:IDerivationFunction + { + IMac GetMac(); + } +} \ No newline at end of file diff --git a/crypto/src/crypto/generators/KDFCounterBytesGenerator.cs b/crypto/src/crypto/generators/KDFCounterBytesGenerator.cs new file mode 100644 index 000000000..470d7567b --- /dev/null +++ b/crypto/src/crypto/generators/KDFCounterBytesGenerator.cs @@ -0,0 +1,158 @@ +using System; +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Generators +{ + public class KDFCounterBytesGenerator : IMacDerivationFunction + { + + private static readonly BigInteger IntegerMax = BigInteger.ValueOf(0x7fffffff); + private static readonly BigInteger Two = BigInteger.Two; + + + private readonly IMac prf; + private readonly int h; + + private byte[] fixedInputDataCtrPrefix; + private byte[] fixedInputData_afterCtr; + private int maxSizeExcl; + // ios is i defined as an octet string (the binary representation) + private byte[] ios; + + // operational + private int generatedBytes; + // k is used as buffer for all K(i) values + private byte[] k; + + public KDFCounterBytesGenerator(IMac prf) + { + this.prf = prf; + this.h = prf.GetMacSize(); + this.k = new byte[h]; + } + + public void Init(IDerivationParameters param) + { + KDFCounterParameters kdfParams = param as KDFCounterParameters; + if (kdfParams == null) + { + throw new ArgumentException("Wrong type of arguments given"); + } + + + + // --- init mac based PRF --- + + this.prf.Init(new KeyParameter(kdfParams.Ki)); + + // --- set arguments --- + + this.fixedInputDataCtrPrefix = kdfParams.FixedInputDataCounterPrefix; + this.fixedInputData_afterCtr = kdfParams.FixedInputDataCounterSuffix; + + int r = kdfParams.R; + this.ios = new byte[r / 8]; + + BigInteger maxSize = Two.Pow(r).Multiply(BigInteger.ValueOf(h)); + this.maxSizeExcl = maxSize.CompareTo(IntegerMax) == 1 ? + Int32.MaxValue : maxSize.IntValue; + + // --- set operational state --- + + generatedBytes = 0; + } + + + public IMac GetMac() + { + return prf; + } + + + public IDigest Digest + { + get + { + HMac hmac = (prf as HMac); + return hmac?.GetUnderlyingDigest(); + } + } + + public int GenerateBytes(byte[] output, int outOff, int length) + { + int generatedBytesAfter = generatedBytes + length; + if (generatedBytesAfter < 0 || generatedBytesAfter >= maxSizeExcl) + { + throw new DataLengthException( + "Current KDFCTR may only be used for " + maxSizeExcl + " bytes"); + } + + if (generatedBytes % h == 0) + { + generateNext(); + } + + // copy what is left in the currentT (1..hash + int toGenerate = length; + int posInK = generatedBytes % h; + int leftInK = h - generatedBytes % h; + int toCopy = System.Math.Min(leftInK, toGenerate); + Array.Copy(k, posInK, output, outOff, toCopy); + generatedBytes += toCopy; + toGenerate -= toCopy; + outOff += toCopy; + + while (toGenerate > 0) + { + generateNext(); + toCopy = System.Math.Min(h, toGenerate); + Array.Copy(k, 0, output, outOff, toCopy); + generatedBytes += toCopy; + toGenerate -= toCopy; + outOff += toCopy; + } + + return length; + + } + + private void generateNext() + { + + int i = generatedBytes / h + 1; + + // encode i into counter buffer + switch (ios.Length) + { + case 4: + ios[0] = (byte)(i >> 24); + goto case 3; + // fall through + case 3: + ios[ios.Length - 3] = (byte)(i >> 16); + // fall through + goto case 2; + case 2: + ios[ios.Length - 2] = (byte)(i >> 8); + // fall through + goto case 1; + case 1: + ios[ios.Length - 1] = (byte)i; + break; + default: + throw new InvalidOperationException("Unsupported size of counter i"); + } + + + + // special case for K(0): K(0) is empty, so no update + prf.BlockUpdate(fixedInputDataCtrPrefix, 0, fixedInputDataCtrPrefix.Length); + prf.BlockUpdate(ios, 0, ios.Length); + prf.BlockUpdate(fixedInputData_afterCtr, 0, fixedInputData_afterCtr.Length); + prf.DoFinal(k, 0); + } + } +} \ No newline at end of file diff --git a/crypto/src/crypto/generators/KDFDoublePipelineIterationBytesGenerator.cs b/crypto/src/crypto/generators/KDFDoublePipelineIterationBytesGenerator.cs new file mode 100644 index 000000000..57e0b2ae0 --- /dev/null +++ b/crypto/src/crypto/generators/KDFDoublePipelineIterationBytesGenerator.cs @@ -0,0 +1,185 @@ +using System; +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Generators +{ + public class KDFDoublePipelineIterationBytesGenerator : IMacDerivationFunction + { + private static readonly BigInteger IntegerMax = BigInteger.ValueOf(0x7fffffff); + private static readonly BigInteger Two = BigInteger.Two; + + // fields set by the constructor + private readonly IMac prf; + private readonly int h; + + // fields set by init + private byte[] fixedInputData; + private int maxSizeExcl; + // ios is i defined as an octet string (the binary representation) + private byte[] ios; + private bool useCounter; + + // operational + private int generatedBytes; + // k is used as buffer for all K(i) values + private byte[] a; + private byte[] k; + + + public KDFDoublePipelineIterationBytesGenerator(IMac prf) + { + this.prf = prf; + this.h = prf.GetMacSize(); + this.a = new byte[h]; + this.k = new byte[h]; + } + + + public void Init(IDerivationParameters parameters) + { + KDFDoublePipelineIterationParameters dpiParams = parameters as KDFDoublePipelineIterationParameters; + if (dpiParams == null) + { + throw new ArgumentException("Wrong type of arguments given"); + } + + + + // --- init mac based PRF --- + + this.prf.Init(new KeyParameter(dpiParams.Ki)); + + // --- set arguments --- + + this.fixedInputData = dpiParams.FixedInputData; + + int r = dpiParams.R; + this.ios = new byte[r / 8]; + + if (dpiParams.UseCounter) + { + // this is more conservative than the spec + BigInteger maxSize = Two.Pow(r).Multiply(BigInteger.ValueOf(h)); + this.maxSizeExcl = maxSize.CompareTo(IntegerMax) == 1 ? + Int32.MaxValue : maxSize.IntValue; + } + else + { + this.maxSizeExcl = IntegerMax.IntValue; + } + + this.useCounter = dpiParams.UseCounter; + + // --- set operational state --- + + generatedBytes = 0; + } + + + + + private void generateNext() + { + + if (generatedBytes == 0) + { + // --- step 4 --- + prf.BlockUpdate(fixedInputData, 0, fixedInputData.Length); + prf.DoFinal(a, 0); + } + else + { + // --- step 5a --- + prf.BlockUpdate(a, 0, a.Length); + prf.DoFinal(a, 0); + } + + // --- step 5b --- + prf.BlockUpdate(a, 0, a.Length); + + if (useCounter) + { + int i = generatedBytes / h + 1; + + // encode i into counter buffer + switch (ios.Length) + { + case 4: + ios[0] = (byte)(i >> 24); + // fall through + goto case 3; + case 3: + ios[ios.Length - 3] = (byte)(i >> 16); + // fall through + goto case 2; + case 2: + ios[ios.Length - 2] = (byte)(i >> 8); + // fall through + goto case 1; + case 1: + ios[ios.Length - 1] = (byte)i; + break; + default: + throw new InvalidOperationException("Unsupported size of counter i"); + } + prf.BlockUpdate(ios, 0, ios.Length); + } + + prf.BlockUpdate(fixedInputData, 0, fixedInputData.Length); + prf.DoFinal(k, 0); + } + + + public IDigest Digest + { + get + { + HMac hmac = (prf as HMac); + return hmac?.GetUnderlyingDigest(); + } + } + public int GenerateBytes(byte[] output, int outOff, int length) + { + int generatedBytesAfter = generatedBytes + length; + if (generatedBytesAfter < 0 || generatedBytesAfter >= maxSizeExcl) + { + throw new DataLengthException( + "Current KDFCTR may only be used for " + maxSizeExcl + " bytes"); + } + + if (generatedBytes % h == 0) + { + generateNext(); + } + + // copy what is left in the currentT (1..hash + int toGenerate = length; + int posInK = generatedBytes % h; + int leftInK = h - generatedBytes % h; + int toCopy = System.Math.Min(leftInK, toGenerate); + Array.Copy(k, posInK, output, outOff, toCopy); + generatedBytes += toCopy; + toGenerate -= toCopy; + outOff += toCopy; + + while (toGenerate > 0) + { + generateNext(); + toCopy = System.Math.Min(h, toGenerate); + Array.Copy(k, 0, output, outOff, toCopy); + generatedBytes += toCopy; + toGenerate -= toCopy; + outOff += toCopy; + } + + return length; + } + + public IMac GetMac() + { + return prf; + } + } +} \ No newline at end of file diff --git a/crypto/src/crypto/generators/KDFFeedbackBytesGenerator.cs b/crypto/src/crypto/generators/KDFFeedbackBytesGenerator.cs new file mode 100644 index 000000000..106cd0125 --- /dev/null +++ b/crypto/src/crypto/generators/KDFFeedbackBytesGenerator.cs @@ -0,0 +1,179 @@ +using System; +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Generators +{ + public class KDFFeedbackBytesGenerator : IMacDerivationFunction + { + private static readonly BigInteger IntegerMax = BigInteger.ValueOf(0x7fffffff); + private static readonly BigInteger Two = BigInteger.Two; + + // please refer to the standard for the meaning of the variable names + // all field lengths are in bytes, not in bits as specified by the standard + + // fields set by the constructor + private readonly IMac prf; + private readonly int h; + + // fields set by init + private byte[] fixedInputData; + private int maxSizeExcl; + // ios is i defined as an octet string (the binary representation) + private byte[] ios; + private byte[] iv; + private bool useCounter; + + // operational + private int generatedBytes; + // k is used as buffer for all K(i) values + private byte[] k; + + public KDFFeedbackBytesGenerator(IMac prf) + { + this.prf = prf; + this.h = prf.GetMacSize(); + this.k = new byte[h]; + } + + + public void Init(IDerivationParameters parameters) + { + KDFFeedbackParameters feedbackParams = parameters as KDFFeedbackParameters; + if (feedbackParams == null) + { + throw new ArgumentException("Wrong type of arguments given"); + } + + + // --- init mac based PRF --- + + this.prf.Init(new KeyParameter(feedbackParams.Ki)); + + // --- set arguments --- + + this.fixedInputData = feedbackParams.FixedInputData; + + int r = feedbackParams.R; + this.ios = new byte[r / 8]; + + if (feedbackParams.UseCounter) + { + // this is more conservative than the spec + BigInteger maxSize = Two.Pow(r).Multiply(BigInteger.ValueOf(h)); + this.maxSizeExcl = maxSize.CompareTo(IntegerMax) == 1 ? + Int32.MaxValue : maxSize.IntValue; + } + else + { + this.maxSizeExcl = Int32.MaxValue; + } + + this.iv = feedbackParams.Iv; + this.useCounter = feedbackParams.UseCounter; + + // --- set operational state --- + + generatedBytes = 0; + } + + public IDigest Digest + { + get + { + HMac hmac = (prf as HMac); + return hmac?.GetUnderlyingDigest(); + } + } + public int GenerateBytes(byte[] output, int outOff, int length) + { + int generatedBytesAfter = generatedBytes + length; + if (generatedBytesAfter < 0 || generatedBytesAfter >= maxSizeExcl) + { + throw new DataLengthException( + "Current KDFCTR may only be used for " + maxSizeExcl + " bytes"); + } + + if (generatedBytes % h == 0) + { + generateNext(); + } + + // copy what is left in the currentT (1..hash + int toGenerate = length; + int posInK = generatedBytes % h; + int leftInK = h - generatedBytes % h; + + + int toCopy = System.Math.Min(leftInK, toGenerate); + Array.Copy(k, posInK, output, outOff, toCopy); + + generatedBytes += toCopy; + toGenerate -= toCopy; + outOff += toCopy; + + while (toGenerate > 0) + { + generateNext(); + toCopy = System.Math.Min(h, toGenerate); + Array.Copy(k, 0, output, outOff, toCopy); + generatedBytes += toCopy; + toGenerate -= toCopy; + outOff += toCopy; + } + + return length; + } + + private void generateNext() + { + + // TODO enable IV + if (generatedBytes == 0) + { + prf.BlockUpdate(iv, 0, iv.Length); + } + else + { + prf.BlockUpdate(k, 0, k.Length); + } + + if (useCounter) + { + int i = generatedBytes / h + 1; + + // encode i into counter buffer + switch (ios.Length) + { + case 4: + ios[0] = (byte)(i >> 24); + goto case 3; + // fall through + case 3: + ios[ios.Length - 3] = (byte)(i >> 16); + // fall through + goto case 2; + case 2: + ios[ios.Length - 2] = (byte)(i >> 8); + // fall through + goto case 1; + case 1: + ios[ios.Length - 1] = (byte)i; + break; + default: + throw new InvalidOperationException("Unsupported size of counter i"); + } + prf.BlockUpdate(ios, 0, ios.Length); + } + + prf.BlockUpdate(fixedInputData, 0, fixedInputData.Length); + prf.DoFinal(k, 0); + } + + public IMac GetMac() + { + return prf; + } + } +} \ No newline at end of file diff --git a/crypto/src/crypto/parameters/KDFCounterParameters.cs b/crypto/src/crypto/parameters/KDFCounterParameters.cs new file mode 100644 index 000000000..79e0e5f53 --- /dev/null +++ b/crypto/src/crypto/parameters/KDFCounterParameters.cs @@ -0,0 +1,91 @@ +using System; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class KDFCounterParameters : IDerivationParameters + { + private byte[] ki; + private byte[] fixedInputDataCounterPrefix; + private byte[] fixedInputDataCounterSuffix; + private int r; + + /// <summary> + /// Base constructor - suffix fixed input data only. + /// </summary> + /// <param name="ki">the KDF seed</param> + /// <param name="fixedInputDataCounterSuffix">fixed input data to follow counter.</param> + /// <param name="r">length of the counter in bits</param> + public KDFCounterParameters(byte[] ki, byte[] fixedInputDataCounterSuffix, int r) : this(ki, null, fixedInputDataCounterSuffix, r) + { + } + + + + /// <summary> + /// Base constructor - prefix and suffix fixed input data. + /// </summary> + /// <param name="ki">the KDF seed</param> + /// <param name="fixedInputDataCounterPrefix">fixed input data to precede counter</param> + /// <param name="fixedInputDataCounterSuffix">fixed input data to follow counter.</param> + /// <param name="r">length of the counter in bits.</param> + public KDFCounterParameters(byte[] ki, byte[] fixedInputDataCounterPrefix, byte[] fixedInputDataCounterSuffix, int r) + { + if (ki == null) + { + throw new ArgumentException("A KDF requires Ki (a seed) as input"); + } + this.ki = Arrays.Clone(ki); + + if (fixedInputDataCounterPrefix == null) + { + this.fixedInputDataCounterPrefix = new byte[0]; + } + else + { + this.fixedInputDataCounterPrefix = Arrays.Clone(fixedInputDataCounterPrefix); + } + + if (fixedInputDataCounterSuffix == null) + { + this.fixedInputDataCounterSuffix = new byte[0]; + } + else + { + this.fixedInputDataCounterSuffix = Arrays.Clone(fixedInputDataCounterSuffix); + } + + if (r != 8 && r != 16 && r != 24 && r != 32) + { + throw new ArgumentException("Length of counter should be 8, 16, 24 or 32"); + } + this.r = r; + } + + public byte[] Ki + { + get { return ki; } + } + + public byte[] FixedInputData + { + get { return Arrays.Clone(fixedInputDataCounterSuffix); } + } + + public byte[] FixedInputDataCounterPrefix + { + get { return Arrays.Clone(fixedInputDataCounterPrefix); } + + } + + public byte[] FixedInputDataCounterSuffix + { + get { return Arrays.Clone(fixedInputDataCounterSuffix); } + } + + public int R + { + get { return r; } + } + } +} \ No newline at end of file diff --git a/crypto/src/crypto/parameters/KDFDoublePipelineIterationParameters.cs b/crypto/src/crypto/parameters/KDFDoublePipelineIterationParameters.cs new file mode 100644 index 000000000..d7995cb41 --- /dev/null +++ b/crypto/src/crypto/parameters/KDFDoublePipelineIterationParameters.cs @@ -0,0 +1,78 @@ +using System; +using Org.BouncyCastle.Asn1.Tests; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + + public class KDFDoublePipelineIterationParameters : IDerivationParameters + { + // could be any valid value, using 32, don't know why + private static readonly int UNUSED_R = 32; + + private readonly byte[] ki; + private readonly bool useCounter; + private readonly int r; + private readonly byte[] fixedInputData; + + private KDFDoublePipelineIterationParameters(byte[] ki, byte[] fixedInputData, int r, bool useCounter) + { + if (ki == null) + { + throw new ArgumentException("A KDF requires Ki (a seed) as input"); + } + + this.ki = Arrays.Clone(ki); + + if (fixedInputData == null) + { + this.fixedInputData = new byte[0]; + } + else + { + this.fixedInputData = Arrays.Clone(fixedInputData); + } + + if (r != 8 && r != 16 && r != 24 && r != 32) + { + throw new ArgumentException("Length of counter should be 8, 16, 24 or 32"); + } + + this.r = r; + + this.useCounter = useCounter; + } + + public static KDFDoublePipelineIterationParameters CreateWithCounter( + byte[] ki, byte[] fixedInputData, int r) + { + return new KDFDoublePipelineIterationParameters(ki, fixedInputData, r, true); + } + + public static KDFDoublePipelineIterationParameters CreateWithoutCounter( + byte[] ki, byte[] fixedInputData) + { + return new KDFDoublePipelineIterationParameters(ki, fixedInputData, UNUSED_R, false); + } + + public byte[] Ki + { + get { return Arrays.Clone(ki); } + } + + public bool UseCounter + { + get { return useCounter; } + } + + public int R + { + get { return r; } + } + + public byte[] FixedInputData + { + get { return Arrays.Clone(fixedInputData); } + } + } +} \ No newline at end of file diff --git a/crypto/src/crypto/parameters/KDFFeedbackParameters.cs b/crypto/src/crypto/parameters/KDFFeedbackParameters.cs new file mode 100644 index 000000000..87187dbdb --- /dev/null +++ b/crypto/src/crypto/parameters/KDFFeedbackParameters.cs @@ -0,0 +1,91 @@ +using System; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class KDFFeedbackParameters : IDerivationParameters + { + // could be any valid value, using 32, don't know why + private static readonly int UNUSED_R = -1; + + private readonly byte[] ki; + private readonly byte[] iv; + private readonly bool useCounter; + private readonly int r; + private readonly byte[] fixedInputData; + + private KDFFeedbackParameters(byte[] ki, byte[] iv, byte[] fixedInputData, int r, bool useCounter) + { + if (ki == null) + { + throw new ArgumentException("A KDF requires Ki (a seed) as input"); + } + + this.ki = Arrays.Clone(ki); + + if (fixedInputData == null) + { + this.fixedInputData = new byte[0]; + } + else + { + this.fixedInputData = Arrays.Clone(fixedInputData); + } + + this.r = r; + + if (iv == null) + { + this.iv = new byte[0]; + } + else + { + this.iv = Arrays.Clone(iv); + } + + this.useCounter = useCounter; + } + + public static KDFFeedbackParameters CreateWithCounter( + byte[] ki, byte[] iv, byte[] fixedInputData, int r) + { + if (r != 8 && r != 16 && r != 24 && r != 32) + { + throw new ArgumentException("Length of counter should be 8, 16, 24 or 32"); + } + + return new KDFFeedbackParameters(ki, iv, fixedInputData, r, true); + } + + public static KDFFeedbackParameters CreateWithoutCounter( + byte[] ki, byte[] iv, byte[] fixedInputData) + { + return new KDFFeedbackParameters(ki, iv, fixedInputData, UNUSED_R, false); + } + + public byte[] Ki + { + get { return Arrays.Clone(ki); } + } + + public byte[] Iv + { + get { return Arrays.Clone(iv); } + } + + public bool UseCounter + { + get { return useCounter; } + } + + public int R + { + get { return r; } + } + + public byte[] FixedInputData + { + get { return Arrays.Clone(fixedInputData); } + } + } +} \ No newline at end of file |