summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
authormw <megan@cryptoworkshop.com>2020-10-28 15:49:41 +1100
committermw <megan@cryptoworkshop.com>2020-10-28 15:49:41 +1100
commit64754bc98150efd15305a861a6b6c420db163635 (patch)
tree9b5173eee30c681923f190a595e8a7a37b277605 /crypto/src
parentMerge branch 'master' of git.bouncycastle.org:bc-csharp into master (diff)
downloadBouncyCastle.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.cs115
-rw-r--r--crypto/src/crypto/digests/XofUtils.cs54
-rw-r--r--crypto/src/crypto/macs/KMac.cs184
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);
+        }
+    }
+}