diff --git a/crypto/src/asn1/nist/KMACwithSHAKE128_params.cs b/crypto/src/asn1/nist/KMACwithSHAKE128_params.cs
new file mode 100644
index 000000000..a1fd8f403
--- /dev/null
+++ b/crypto/src/asn1/nist/KMACwithSHAKE128_params.cs
@@ -0,0 +1,103 @@
+using Org.BouncyCastle.Utilities;
+using System;
+
+
+namespace Org.BouncyCastle.Asn1.Nist
+{
+ /// <summary>
+ /// KMACwithSHAKE128-params ::= SEQUENCE {
+ /// kMACOutputLength INTEGER DEFAULT 256, -- Output length in bits
+ /// customizationString OCTET STRING DEFAULT ''H
+ /// }
+ /// </summary>
+public class KMacWithShake128Params : Asn1Encodable
+{
+ private static readonly byte[] EMPTY_STRING = new byte[0];
+ private static readonly int DEF_LENGTH = 256;
+
+ private readonly int outputLength;
+ private readonly byte[] customizationString;
+
+ public KMacWithShake128Params(int outputLength)
+ {
+ this.outputLength = outputLength;
+ this.customizationString = EMPTY_STRING;
+ }
+
+ public KMacWithShake128Params(int outputLength, byte[] customizationString)
+ {
+ this.outputLength = outputLength;
+ this.customizationString = Arrays.Clone(customizationString);
+ }
+
+ public static KMacWithShake128Params GetInstance(object o)
+ {
+ if (o is KMacWithShake128Params)
+ {
+ return (KMacWithShake128Params)o;
+ }
+ else if (o != null)
+ {
+ return new KMacWithShake128Params(Asn1Sequence.GetInstance(o));
+ }
+
+ return null;
+ }
+
+ private KMacWithShake128Params(Asn1Sequence seq)
+ {
+ if (seq.Count > 2)
+ throw new InvalidOperationException("sequence size greater than 2");
+
+ if (seq.Count == 2)
+ {
+ this.outputLength = DerInteger.GetInstance(seq[0]).IntValueExact;
+ this.customizationString = Arrays.Clone(Asn1OctetString.GetInstance(seq[1]).GetOctets());
+ }
+ else if (seq.Count == 1)
+ {
+ if (seq[0] is DerInteger)
+ {
+ this.outputLength = DerInteger.GetInstance(seq[0]).IntValueExact;
+ this.customizationString = EMPTY_STRING;
+ }
+ else
+ {
+ this.outputLength = DEF_LENGTH;
+ this.customizationString = Arrays.Clone(Asn1OctetString.GetInstance(seq[0]).GetOctets());
+ }
+ }
+ else
+ {
+ this.outputLength = DEF_LENGTH;
+ this.customizationString = EMPTY_STRING;
+ }
+ }
+
+ public int OutputLength
+ {
+ get { return outputLength; }
+ }
+
+ public byte[] CustomizationString
+ {
+ get { return Arrays.Clone(customizationString); }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+ if (outputLength != DEF_LENGTH)
+ {
+ v.Add(new DerInteger(outputLength));
+ }
+
+ if (customizationString.Length != 0)
+ {
+ v.Add(new DerOctetString(CustomizationString));
+ }
+
+ return new DerSequence(v);
+ }
+}
+}
diff --git a/crypto/src/asn1/nist/KMACwithSHAKE256_params.cs b/crypto/src/asn1/nist/KMACwithSHAKE256_params.cs
new file mode 100644
index 000000000..fa7471913
--- /dev/null
+++ b/crypto/src/asn1/nist/KMACwithSHAKE256_params.cs
@@ -0,0 +1,102 @@
+using Org.BouncyCastle.Utilities;
+using System;
+
+namespace Org.BouncyCastle.Asn1.Nist
+{
+ /// <summary>
+ /// KMACwithSHAKE256-params ::= SEQUENCE {
+ /// kMACOutputLength INTEGER DEFAULT 512, -- Output length in bits
+ /// customizationString OCTET STRING DEFAULT ''H
+ /// }
+ /// </summary>
+public class KMacWithShake256Params : Asn1Encodable
+{
+ private static readonly byte[] EMPTY_STRING = new byte[0];
+ private static readonly int DEF_LENGTH = 512;
+
+ private readonly int outputLength;
+ private readonly byte[] customizationString;
+
+ public KMacWithShake256Params(int outputLength)
+ {
+ this.outputLength = outputLength;
+ this.customizationString = EMPTY_STRING;
+ }
+
+ public KMacWithShake256Params(int outputLength, byte[] customizationString)
+ {
+ this.outputLength = outputLength;
+ this.customizationString = Arrays.Clone(customizationString);
+ }
+
+ public static KMacWithShake256Params GetInstance(Object o)
+ {
+ if (o is KMacWithShake256Params)
+ {
+ return (KMacWithShake256Params)o;
+ }
+ else if (o != null)
+ {
+ return new KMacWithShake256Params(Asn1Sequence.GetInstance(o));
+ }
+
+ return null;
+ }
+
+ private KMacWithShake256Params(Asn1Sequence seq)
+ {
+ if (seq.Count > 2)
+ throw new InvalidOperationException("sequence size greater than 2");
+
+ if (seq.Count == 2)
+ {
+ this.outputLength = DerInteger.GetInstance(seq[0]).IntValueExact;
+ this.customizationString = Arrays.Clone(Asn1OctetString.GetInstance(seq[1]).GetOctets());
+ }
+ else if (seq.Count == 1)
+ {
+ if (seq[0] is DerInteger)
+ {
+ this.outputLength = DerInteger.GetInstance(seq[0]).IntValueExact;
+ this.customizationString = EMPTY_STRING;
+ }
+ else
+ {
+ this.outputLength = DEF_LENGTH;
+ this.customizationString = Arrays.Clone(Asn1OctetString.GetInstance(seq[0]).GetOctets());
+ }
+ }
+ else
+ {
+ this.outputLength = DEF_LENGTH;
+ this.customizationString = EMPTY_STRING;
+ }
+ }
+
+ public int OutputLength
+ {
+ get { return outputLength; }
+ }
+
+ public byte[] CustomizationString
+ {
+ get { return Arrays.Clone(customizationString); }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+ if (outputLength != DEF_LENGTH)
+ {
+ v.Add(new DerInteger(outputLength));
+ }
+
+ if (customizationString.Length != 0)
+ {
+ v.Add(new DerOctetString(CustomizationString));
+ }
+
+ return new DerSequence(v);
+ }
+}
+}
diff --git a/crypto/src/crypto/digests/CSHAKEDigest.cs b/crypto/src/crypto/digests/CSHAKEDigest.cs
index 5c42b4171..c070a47c2 100644
--- a/crypto/src/crypto/digests/CSHAKEDigest.cs
+++ b/crypto/src/crypto/digests/CSHAKEDigest.cs
@@ -1,15 +1,13 @@
-using Org.BouncyCastle.Utilities;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using System;
+
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Digests
{
/// <summary>
/// Customizable SHAKE function.
/// </summary>
- public class CSHAKEDigest : ShakeDigest
+ public class CShakeDigest : ShakeDigest
{
private static readonly byte[] padding = new byte[100];
private readonly byte[] diff;
@@ -20,7 +18,7 @@ namespace Org.BouncyCastle.Crypto.Digests
/// <param name="bitLength">bit length of the underlying SHAKE function, 128 or 256.</param>
/// <param name="N">the function name string, note this is reserved for use by NIST. Avoid using it if not required.</param>
/// <param name="S">the customization string - available for local use.</param>
- public CSHAKEDigest(int bitLength, byte[] N, byte[] S) : base(bitLength)
+ public CShakeDigest(int bitLength, byte[] N, byte[] S) : base(bitLength)
{
if ((N == null || N.Length == 0) && (S == null || S.Length == 0))
{
@@ -28,12 +26,11 @@ namespace Org.BouncyCastle.Crypto.Digests
}
else
{
- diff = Arrays.ConcatenateAll(XofUtils.leftEncode(rate / 8), encodeString(N), encodeString(S));
+ diff = Arrays.ConcatenateAll(XofUtilities.LeftEncode(rate / 8), encodeString(N), encodeString(S));
DiffPadAndAbsorb();
}
}
-
// bytepad in SP 800-185
private void DiffPadAndAbsorb()
{
@@ -61,13 +58,16 @@ namespace Org.BouncyCastle.Crypto.Digests
{
if (str == null || str.Length == 0)
{
- return XofUtils.leftEncode(0);
+ return XofUtilities.LeftEncode(0);
}
- return Arrays.Concatenate(XofUtils.leftEncode(str.Length * 8L), str);
+ return Arrays.Concatenate(XofUtilities.LeftEncode(str.Length * 8L), str);
}
- public override string AlgorithmName => "CSHAKE" + fixedOutputLength;
+ public override string AlgorithmName
+ {
+ get { return "CSHAKE" + fixedOutputLength; }
+ }
public override int DoFinal(byte[] output, int outOff)
{
@@ -102,7 +102,7 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
- public void Reset()
+ public override void Reset()
{
base.Reset();
diff --git a/crypto/src/crypto/digests/XofUtils.cs b/crypto/src/crypto/digests/XofUtils.cs
index e4c893e01..5c197e0e6 100644
--- a/crypto/src/crypto/digests/XofUtils.cs
+++ b/crypto/src/crypto/digests/XofUtils.cs
@@ -1,13 +1,10 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
namespace Org.BouncyCastle.Crypto.Digests
{
- public class XofUtils
+ internal class XofUtilities
{
- public static byte[] leftEncode(long strLen)
+ internal static byte[] LeftEncode(long strLen)
{
byte n = 1;
@@ -29,7 +26,7 @@ namespace Org.BouncyCastle.Crypto.Digests
return b;
}
- public static byte[] rightEncode(long strLen)
+ internal static byte[] RightEncode(long strLen)
{
byte n = 1;
diff --git a/crypto/src/crypto/macs/KMac.cs b/crypto/src/crypto/macs/KMac.cs
index 38697a9a9..889131d8c 100644
--- a/crypto/src/crypto/macs/KMac.cs
+++ b/crypto/src/crypto/macs/KMac.cs
@@ -1,19 +1,18 @@
-using Org.BouncyCastle.Crypto.Digests;
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
namespace Org.BouncyCastle.Crypto.Macs
{
- public class KMac : IMac, IXof
+ public class KMac
+ : IMac, IXof
{
-
private static readonly byte[] padding = new byte[100];
- private readonly CSHAKEDigest cshake;
+ private readonly CShakeDigest cshake;
private readonly int bitLength;
private readonly int outputLength;
@@ -21,23 +20,22 @@ namespace Org.BouncyCastle.Crypto.Macs
private bool initialised;
private bool firstOutput;
-
public KMac(int bitLength, byte[] S)
{
- this.cshake = new CSHAKEDigest(bitLength, Encoding.ASCII.GetBytes("KMAC"),S);
+ this.cshake = new CShakeDigest(bitLength, Encoding.ASCII.GetBytes("KMAC"), S);
this.bitLength = bitLength;
this.outputLength = bitLength * 2 / 8;
}
-
- public string AlgorithmName => "KMAC" + cshake.AlgorithmName.Substring(6);
+ public string AlgorithmName
+ {
+ get { return "KMAC" + cshake.AlgorithmName.Substring(6); }
+ }
public void BlockUpdate(byte[] input, int inOff, int len)
{
if (!initialised)
- {
throw new InvalidOperationException("KMAC not initialized");
- }
cshake.BlockUpdate(input, inOff, len);
}
@@ -47,11 +45,9 @@ namespace Org.BouncyCastle.Crypto.Macs
if (firstOutput)
{
if (!initialised)
- {
throw new InvalidOperationException("KMAC not initialized");
- }
- byte[] encOut = XofUtils.rightEncode(GetMacSize() * 8);
+ byte[] encOut = XofUtilities.RightEncode(GetMacSize() * 8);
cshake.BlockUpdate(encOut, 0, encOut.Length);
}
@@ -68,11 +64,9 @@ namespace Org.BouncyCastle.Crypto.Macs
if (firstOutput)
{
if (!initialised)
- {
throw new InvalidOperationException("KMAC not initialized");
- }
- byte[] encOut = XofUtils.rightEncode(outLen * 8);
+ byte[] encOut = XofUtilities.RightEncode(outLen * 8);
cshake.BlockUpdate(encOut, 0, encOut.Length);
}
@@ -89,11 +83,9 @@ namespace Org.BouncyCastle.Crypto.Macs
if (firstOutput)
{
if (!initialised)
- {
throw new InvalidOperationException("KMAC not initialized");
- }
- byte[] encOut = XofUtils.rightEncode(0);
+ byte[] encOut = XofUtilities.RightEncode(0);
cshake.BlockUpdate(encOut, 0, encOut.Length);
@@ -147,7 +139,7 @@ namespace Org.BouncyCastle.Crypto.Macs
private void bytePad(byte[] X, int w)
{
- byte[] bytes = XofUtils.leftEncode(w);
+ byte[] bytes = XofUtilities.LeftEncode(w);
BlockUpdate(bytes, 0, bytes.Length);
byte[] encX = encode(X);
BlockUpdate(encX, 0, encX.Length);
@@ -168,15 +160,13 @@ namespace Org.BouncyCastle.Crypto.Macs
private static byte[] encode(byte[] X)
{
- return Arrays.Concatenate(XofUtils.leftEncode(X.Length * 8), X);
+ return Arrays.Concatenate(XofUtilities.LeftEncode(X.Length * 8), X);
}
public void Update(byte input)
{
if (!initialised)
- {
throw new InvalidOperationException("KMAC not initialized");
- }
cshake.Update(input);
}
diff --git a/crypto/src/math/raw/Mod.cs b/crypto/src/math/raw/Mod.cs
index 41977f9d8..a3435ea80 100644
--- a/crypto/src/math/raw/Mod.cs
+++ b/crypto/src/math/raw/Mod.cs
@@ -82,15 +82,18 @@ namespace Org.BouncyCastle.Math.Raw
Debug.Assert(-1 == signF | 0 == signF);
CNegate30(len30, signF, F);
- CNegate30(len30, signF, D);
- Decode30(bits, D, 0, z, 0);
-
- int signD = D[len30 - 1] >> 31;
+ int signD = CNegate30(len30, signF, D);
Debug.Assert(-1 == signD | 0 == signD);
- signD += (int)Nat.CAdd(len32, signD, z, m, z);
- Debug.Assert(0 == signD & 0 != Nat.LessThan(len32, z, m));
+ // TODO 'D' should already be in [P, -P), but absent a proof we support [-2P, 2P)
+ signD = CSub30(len30, ~signD, D, M);
+ signD = CAdd30(len30, signD, D, M);
+ signD = CAdd30(len30, signD, D, M);
+ Debug.Assert(0 == signD);
+
+ Decode30(bits, D, 0, z, 0);
+ Debug.Assert(0 != Nat.LessThan(len32, z, m));
return (uint)(EqualTo(len30, F, 1) & EqualToZero(len30, G));
}
@@ -162,16 +165,26 @@ namespace Org.BouncyCastle.Math.Raw
if (!IsOne(lenFG, F))
return false;
- Decode30(bits, D, 0, z, 0);
-
int signD = D[lenDE - 1] >> 31;
Debug.Assert(-1 == signD | 0 == signD);
+ // TODO 'D' should already be in [P, -P), but absent a proof we support [-2P, 2P)
+ if (signD < 0)
+ {
+ signD = Add30(len30, D, M);
+ }
+ else
+ {
+ signD = Sub30(len30, D, M);
+ }
if (signD < 0)
{
- signD += (int)Nat.AddTo(len32, m, z);
+ signD = Add30(len30, D, M);
}
- Debug.Assert(0 == signD && !Nat.Gte(len32, z, m));
+ Debug.Assert(0 == signD);
+
+ Decode30(bits, D, 0, z, 0);
+ Debug.Assert(!Nat.Gte(len32, z, m));
return true;
}
@@ -200,22 +213,71 @@ namespace Org.BouncyCastle.Math.Raw
return s;
}
- private static void CNegate30(int len, int cond, int[] D)
+ private static int Add30(int len30, int[] D, int[] M)
{
- Debug.Assert(len > 0);
- Debug.Assert(D.Length >= len);
+ Debug.Assert(len30 > 0);
+ Debug.Assert(D.Length >= len30);
+ Debug.Assert(M.Length >= len30);
+
+ int c = 0, last = len30 - 1;
+ for (int i = 0; i < last; ++i)
+ {
+ c += D[i] + M[i];
+ D[i] = c & M30; c >>= 30;
+ }
+ c += D[last] + M[last];
+ D[last] = c; c >>= 30;
+ return c;
+ }
- int last = len - 1;
- long cd = 0L;
+ private static int CAdd30(int len30, int cond, int[] D, int[] M)
+ {
+ Debug.Assert(len30 > 0);
+ Debug.Assert(D.Length >= len30);
+ Debug.Assert(M.Length >= len30);
+ int c = 0, last = len30 - 1;
for (int i = 0; i < last; ++i)
{
- cd += (D[i] ^ cond) - cond;
- D[i] = (int)cd & M30; cd >>= 30;
+ c += D[i] + (M[i] & cond);
+ D[i] = c & M30; c >>= 30;
}
+ c += D[last] + (M[last] & cond);
+ D[last] = c; c >>= 30;
+ return c;
+ }
- cd += (D[last] ^ cond) - cond;
- D[last] = (int)cd;
+ private static int CNegate30(int len30, int cond, int[] D)
+ {
+ Debug.Assert(len30 > 0);
+ Debug.Assert(D.Length >= len30);
+
+ int c = 0, last = len30 - 1;
+ for (int i = 0; i < last; ++i)
+ {
+ c += (D[i] ^ cond) - cond;
+ D[i] = c & M30; c >>= 30;
+ }
+ c += (D[last] ^ cond) - cond;
+ D[last] = c; c >>= 30;
+ return c;
+ }
+
+ private static int CSub30(int len30, int cond, int[] D, int[] M)
+ {
+ Debug.Assert(len30 > 0);
+ Debug.Assert(D.Length >= len30);
+ Debug.Assert(M.Length >= len30);
+
+ int c = 0, last = len30 - 1;
+ for (int i = 0; i < last; ++i)
+ {
+ c += D[i] - (M[i] & cond);
+ D[i] = c & M30; c >>= 30;
+ }
+ c += D[last] - (M[last] & cond);
+ D[last] = c; c >>= 30;
+ return c;
}
private static void Decode30(int bits, int[] x, int xOff, uint[] z, int zOff)
@@ -424,30 +486,45 @@ namespace Org.BouncyCastle.Math.Raw
return true;
}
- private static void Negate30(int len, int[] D)
+ private static int Negate30(int len30, int[] D)
{
- Debug.Assert(len > 0);
- Debug.Assert(D.Length >= len);
-
- int last = len - 1;
- long cd = 0L;
+ Debug.Assert(len30 > 0);
+ Debug.Assert(D.Length >= len30);
+ int c = 0, last = len30 - 1;
for (int i = 0; i < last; ++i)
{
- cd -= D[i];
- D[i] = (int)cd & M30; cd >>= 30;
+ c -= D[i];
+ D[i] = c & M30; c >>= 30;
}
+ c -= D[last];
+ D[last] = c; c >>= 30;
+ return c;
+ }
- cd -= D[last];
- D[last] = (int)cd;
+ private static int Sub30(int len30, int[] D, int[] M)
+ {
+ Debug.Assert(len30 > 0);
+ Debug.Assert(D.Length >= len30);
+ Debug.Assert(M.Length >= len30);
+
+ int c = 0, last = len30 - 1;
+ for (int i = 0; i < last; ++i)
+ {
+ c += D[i] - M[i];
+ D[i] = c & M30; c >>= 30;
+ }
+ c += D[last] - M[last];
+ D[last] = c; c >>= 30;
+ return c;
}
- private static void UpdateDE30(int len, int[] D, int[] E, int[] t, int m0Inv30x4, int[] M)
+ private static void UpdateDE30(int len30, int[] D, int[] E, int[] t, int m0Inv30x4, int[] M)
{
- Debug.Assert(len > 0);
- Debug.Assert(D.Length >= len);
- Debug.Assert(E.Length >= len);
- Debug.Assert(M.Length >= len);
+ Debug.Assert(len30 > 0);
+ Debug.Assert(D.Length >= len30);
+ Debug.Assert(E.Length >= len30);
+ Debug.Assert(M.Length >= len30);
Debug.Assert(m0Inv30x4 * M[0] == -1 << 2);
int u = t[0], v = t[1], q = t[2], r = t[3];
@@ -472,7 +549,7 @@ namespace Org.BouncyCastle.Math.Raw
cd >>= 30;
ce >>= 30;
- for (i = 1; i < len; ++i)
+ for (i = 1; i < len30; ++i)
{
di = D[i];
ei = E[i];
@@ -487,15 +564,15 @@ namespace Org.BouncyCastle.Math.Raw
E[i - 1] = (int)ce & M30; ce >>= 30;
}
- D[len - 1] = (int)cd;
- E[len - 1] = (int)ce;
+ D[len30 - 1] = (int)cd;
+ E[len30 - 1] = (int)ce;
}
- private static void UpdateFG30(int len, int[] F, int[] G, int[] t)
+ private static void UpdateFG30(int len30, int[] F, int[] G, int[] t)
{
- Debug.Assert(len > 0);
- Debug.Assert(F.Length >= len);
- Debug.Assert(G.Length >= len);
+ Debug.Assert(len30 > 0);
+ Debug.Assert(F.Length >= len30);
+ Debug.Assert(G.Length >= len30);
int u = t[0], v = t[1], q = t[2], r = t[3];
int fi, gi, i;
@@ -513,7 +590,7 @@ namespace Org.BouncyCastle.Math.Raw
cf >>= 30;
cg >>= 30;
- for (i = 1; i < len; ++i)
+ for (i = 1; i < len30; ++i)
{
fi = F[i];
gi = G[i];
@@ -525,8 +602,8 @@ namespace Org.BouncyCastle.Math.Raw
G[i - 1] = (int)cg & M30; cg >>= 30;
}
- F[len - 1] = (int)cf;
- G[len - 1] = (int)cg;
+ F[len30 - 1] = (int)cf;
+ G[len30 - 1] = (int)cg;
}
}
}
|