diff options
author | mw <megan@cryptoworkshop.com> | 2020-10-28 15:49:41 +1100 |
---|---|---|
committer | mw <megan@cryptoworkshop.com> | 2020-10-28 15:49:41 +1100 |
commit | 64754bc98150efd15305a861a6b6c420db163635 (patch) | |
tree | 9b5173eee30c681923f190a595e8a7a37b277605 /crypto/src | |
parent | Merge branch 'master' of git.bouncycastle.org:bc-csharp into master (diff) | |
download | BouncyCastle.NET-ed25519-64754bc98150efd15305a861a6b6c420db163635.tar.xz |
Added CSHAKEDigest, KMac, removed unused import from NewTspTest
Diffstat (limited to 'crypto/src')
-rw-r--r-- | crypto/src/crypto/digests/CSHAKEDigest.cs | 115 | ||||
-rw-r--r-- | crypto/src/crypto/digests/XofUtils.cs | 54 | ||||
-rw-r--r-- | crypto/src/crypto/macs/KMac.cs | 184 |
3 files changed, 353 insertions, 0 deletions
diff --git a/crypto/src/crypto/digests/CSHAKEDigest.cs b/crypto/src/crypto/digests/CSHAKEDigest.cs new file mode 100644 index 000000000..5c42b4171 --- /dev/null +++ b/crypto/src/crypto/digests/CSHAKEDigest.cs @@ -0,0 +1,115 @@ +using Org.BouncyCastle.Utilities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /// <summary> + /// Customizable SHAKE function. + /// </summary> + public class CSHAKEDigest : ShakeDigest + { + private static readonly byte[] padding = new byte[100]; + private readonly byte[] diff; + + /// <summary> + /// Base constructor + /// </summary> + /// <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) + { + if ((N == null || N.Length == 0) && (S == null || S.Length == 0)) + { + diff = null; + } + else + { + diff = Arrays.ConcatenateAll(XofUtils.leftEncode(rate / 8), encodeString(N), encodeString(S)); + DiffPadAndAbsorb(); + } + } + + + // bytepad in SP 800-185 + private void DiffPadAndAbsorb() + { + int blockSize = rate / 8; + Absorb(diff, 0, diff.Length); + + int delta = diff.Length % blockSize; + + // only add padding if needed + if (delta != 0) + { + int required = blockSize - delta; + + while (required > padding.Length) + { + Absorb(padding, 0, padding.Length); + required -= padding.Length; + } + + Absorb(padding, 0, required); + } + } + + private byte[] encodeString(byte[] str) + { + if (str == null || str.Length == 0) + { + return XofUtils.leftEncode(0); + } + + return Arrays.Concatenate(XofUtils.leftEncode(str.Length * 8L), str); + } + + public override string AlgorithmName => "CSHAKE" + fixedOutputLength; + + public override int DoFinal(byte[] output, int outOff) + { + return DoFinal(output, outOff,GetDigestSize()); + } + + public override int DoFinal(byte[] output, int outOff, int outLen) + { + int length = DoOutput(output, outOff, outLen); + + Reset(); + + return length; + } + + public override int DoOutput(byte[] output, int outOff, int outLen) + { + if (diff != null) + { + if (!squeezing) + { + AbsorbBits(0x00, 2); + } + + Squeeze(output, outOff, ((long)outLen) * 8); + + return outLen; + } + else + { + return base.DoOutput(output, outOff, outLen); + } + } + + public void Reset() + { + base.Reset(); + + if (diff != null) + { + DiffPadAndAbsorb(); + } + } + } +} diff --git a/crypto/src/crypto/digests/XofUtils.cs b/crypto/src/crypto/digests/XofUtils.cs new file mode 100644 index 000000000..e4c893e01 --- /dev/null +++ b/crypto/src/crypto/digests/XofUtils.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Org.BouncyCastle.Crypto.Digests +{ + public class XofUtils + { + public static byte[] leftEncode(long strLen) + { + byte n = 1; + + long v = strLen; + while ((v >>= 8) != 0) + { + n++; + } + + byte[] b = new byte[n + 1]; + + b[0] = n; + + for (int i = 1; i <= n; i++) + { + b[i] = (byte)(strLen >> (8 * (n - i))); + } + + return b; + } + + public static byte[] rightEncode(long strLen) + { + byte n = 1; + + long v = strLen; + while ((v >>= 8) != 0) + { + n++; + } + + byte[] b = new byte[n + 1]; + + b[n] = n; + + for (int i = 0; i < n; i++) + { + b[i] = (byte)(strLen >> (8 * (n - i - 1))); + } + + return b; + } + } +} diff --git a/crypto/src/crypto/macs/KMac.cs b/crypto/src/crypto/macs/KMac.cs new file mode 100644 index 000000000..38697a9a9 --- /dev/null +++ b/crypto/src/crypto/macs/KMac.cs @@ -0,0 +1,184 @@ +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 + { + + private static readonly byte[] padding = new byte[100]; + + private readonly CSHAKEDigest cshake; + private readonly int bitLength; + private readonly int outputLength; + + private byte[] key; + private bool initialised; + private bool firstOutput; + + + public KMac(int bitLength, byte[] 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 void BlockUpdate(byte[] input, int inOff, int len) + { + if (!initialised) + { + throw new InvalidOperationException("KMAC not initialized"); + } + + cshake.BlockUpdate(input, inOff, len); + } + + public int DoFinal(byte[] output, int outOff) + { + if (firstOutput) + { + if (!initialised) + { + throw new InvalidOperationException("KMAC not initialized"); + } + + byte[] encOut = XofUtils.rightEncode(GetMacSize() * 8); + + cshake.BlockUpdate(encOut, 0, encOut.Length); + } + + int rv = cshake.DoFinal(output, outOff, GetMacSize()); + + Reset(); + + return rv; + } + + public int DoFinal(byte[] output, int outOff, int outLen) + { + if (firstOutput) + { + if (!initialised) + { + throw new InvalidOperationException("KMAC not initialized"); + } + + byte[] encOut = XofUtils.rightEncode(outLen * 8); + + cshake.BlockUpdate(encOut, 0, encOut.Length); + } + + int rv = cshake.DoFinal(output, outOff, outLen); + + Reset(); + + return rv; + } + + public int DoOutput(byte[] output, int outOff, int outLen) + { + if (firstOutput) + { + if (!initialised) + { + throw new InvalidOperationException("KMAC not initialized"); + } + + byte[] encOut = XofUtils.rightEncode(0); + + cshake.BlockUpdate(encOut, 0, encOut.Length); + + firstOutput = false; + } + + return cshake.DoOutput(output, outOff, outLen); + } + + public int GetByteLength() + { + return cshake.GetByteLength(); + } + + public int GetDigestSize() + { + return outputLength; + } + + public int GetMacSize() + { + return outputLength; + } + + public void Init(ICipherParameters parameters) + { + KeyParameter kParam = (KeyParameter)parameters; + this.key = Arrays.Clone(kParam.GetKey()); + this.initialised = true; + Reset(); + } + + public void Reset() + { + cshake.Reset(); + + if (key != null) + { + if (bitLength == 128) + { + bytePad(key, 168); + } + else + { + bytePad(key, 136); + } + } + + firstOutput = true; + } + + private void bytePad(byte[] X, int w) + { + byte[] bytes = XofUtils.leftEncode(w); + BlockUpdate(bytes, 0, bytes.Length); + byte[] encX = encode(X); + BlockUpdate(encX, 0, encX.Length); + + int required = w - ((bytes.Length + encX.Length) % w); + + if (required > 0 && required != w) + { + while (required > padding.Length) + { + BlockUpdate(padding, 0, padding.Length); + required -= padding.Length; + } + + BlockUpdate(padding, 0, required); + } + } + + private static byte[] encode(byte[] X) + { + return Arrays.Concatenate(XofUtils.leftEncode(X.Length * 8), X); + } + + public void Update(byte input) + { + if (!initialised) + { + throw new InvalidOperationException("KMAC not initialized"); + } + + cshake.Update(input); + } + } +} |