summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
authorDavid Hook <dgh@cryptoworkshop.com>2020-11-01 11:31:59 +1100
committerDavid Hook <dgh@cryptoworkshop.com>2020-11-01 11:31:59 +1100
commited09873b9aa9d5153daddb51dcc15178b37d6409 (patch)
tree65b450cfd8f450aa9a265a00b823991815848da3 /crypto/src
parentadded 1.8.8 donors (diff)
parentMerge branch 'BlackthornYugen-nist_ecc_test_pr' into master (diff)
downloadBouncyCastle.NET-ed25519-ed09873b9aa9d5153daddb51dcc15178b37d6409.tar.xz
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/asn1/nist/KMACwithSHAKE128_params.cs103
-rw-r--r--crypto/src/asn1/nist/KMACwithSHAKE256_params.cs102
-rw-r--r--crypto/src/crypto/digests/CSHAKEDigest.cs26
-rw-r--r--crypto/src/crypto/digests/XofUtils.cs9
-rw-r--r--crypto/src/crypto/macs/KMac.cs44
-rw-r--r--crypto/src/math/raw/Mod.cs165
6 files changed, 359 insertions, 90 deletions
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; } } }