summary refs log tree commit diff
path: root/crypto
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
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')
-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
-rw-r--r--crypto/test/src/crypto/test/CSHAKETest.cs205
-rw-r--r--crypto/test/src/crypto/test/KMACTest.cs245
-rw-r--r--crypto/test/src/tsp/test/NewTspTest.cs1
6 files changed, 803 insertions, 1 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);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/CSHAKETest.cs b/crypto/test/src/crypto/test/CSHAKETest.cs
new file mode 100644
index 000000000..80f0eb1f7
--- /dev/null
+++ b/crypto/test/src/crypto/test/CSHAKETest.cs
@@ -0,0 +1,205 @@
+using NUnit.Framework;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    public class CSHAKETest
+    {
+        [Test]
+        public void PerformTest()
+        {
+            CSHAKEDigest cshake = new CSHAKEDigest(128, new byte[0], Strings.ToByteArray("Email Signature"));
+           
+            cshake.BlockUpdate(Hex.Decode("00010203"), 0, 4);
+
+            byte[] res = new byte[32];
+
+            cshake.DoOutput(res, 0, res.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("c1c36925b6409a04f1b504fcbca9d82b4017277cb5ed2b2065fc1d3814d5aaf5"), res));
+
+            cshake = new CSHAKEDigest(128, new byte[0], Strings.ToByteArray("Email Signature"));
+
+            cshake.BlockUpdate(Hex.Decode(
+          "000102030405060708090A0B0C0D0E0F" +
+              "101112131415161718191A1B1C1D1E1F" +
+              "202122232425262728292A2B2C2D2E2F" +
+              "303132333435363738393A3B3C3D3E3F" +
+              "404142434445464748494A4B4C4D4E4F" +
+              "505152535455565758595A5B5C5D5E5F" +
+              "606162636465666768696A6B6C6D6E6F" +
+              "707172737475767778797A7B7C7D7E7F" +
+              "808182838485868788898A8B8C8D8E8F" +
+              "909192939495969798999A9B9C9D9E9F" +
+              "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF" +
+              "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF" +
+              "C0C1C2C3C4C5C6C7"), 0, 1600 / 8);
+
+            res = new byte[32];
+
+            cshake.DoOutput(res, 0, res.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("C5221D50E4F822D96A2E8881A961420F294B7B24FE3D2094BAED2C6524CC166B "), res));
+
+            cshake = new CSHAKEDigest(256, new byte[0], Strings.ToByteArray("Email Signature"));
+
+            cshake.BlockUpdate(Hex.Decode("00010203"), 0, 4);
+
+            res = new byte[64];
+
+            cshake.DoOutput(res, 0, res.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode(
+       "D008828E2B80AC9D2218FFEE1D070C48" +
+           "B8E4C87BFF32C9699D5B6896EEE0EDD1" +
+           "64020E2BE0560858D9C00C037E34A969" +
+           "37C561A74C412BB4C746469527281C8C"), res));
+
+            cshake = new CSHAKEDigest(256, new byte[0], Strings.ToByteArray("Email Signature"));
+
+            cshake.BlockUpdate(Hex.Decode(
+                "000102030405060708090A0B0C0D0E0F" +
+                    "101112131415161718191A1B1C1D1E1F" +
+                    "202122232425262728292A2B2C2D2E2F" +
+                    "303132333435363738393A3B3C3D3E3F" +
+                    "404142434445464748494A4B4C4D4E4F" +
+                    "505152535455565758595A5B5C5D5E5F" +
+                    "606162636465666768696A6B6C6D6E6F" +
+                    "707172737475767778797A7B7C7D7E7F" +
+                    "808182838485868788898A8B8C8D8E8F" +
+                    "909192939495969798999A9B9C9D9E9F" +
+                    "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF" +
+                    "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF" +
+                    "C0C1C2C3C4C5C6C7"), 0, 1600 / 8);
+
+            res = new byte[64];
+
+            cshake.DoOutput(res, 0, res.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode(
+                    "07DC27B11E51FBAC75BC7B3C1D983E8B" +
+                        "4B85FB1DEFAF218912AC864302730917" +
+                        "27F42B17ED1DF63E8EC118F04B23633C" +
+                        "1DFB1574C8FB55CB45DA8E25AFB092BB"), res));
+
+            doFinalTest();
+            longBlockTest();
+            checkZeroPadZ();
+
+            checkSHAKE(128, new CSHAKEDigest(128, new byte[0], new byte[0]), Hex.Decode("eeaabeef"));
+            checkSHAKE(256, new CSHAKEDigest(256, new byte[0], null), Hex.Decode("eeaabeef"));
+            checkSHAKE(128, new CSHAKEDigest(128, null, new byte[0]), Hex.Decode("eeaabeef"));
+            checkSHAKE(128, new CSHAKEDigest(128, null, null), Hex.Decode("eeaabeef"));
+            checkSHAKE(256, new CSHAKEDigest(256, null, null), Hex.Decode("eeaabeef"));
+        }
+
+        private void checkZeroPadZ()
+        {
+            byte[] buf = new byte[20];
+
+            CSHAKEDigest cshake1 = new CSHAKEDigest(256, new byte[0], new byte[265]);
+            cshake1.DoOutput(buf, 0, buf.Length);
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("6e393540387004f087c4180db008acf6825190cf"), buf));
+
+            CSHAKEDigest cshake2 = new CSHAKEDigest(128, new byte[0], new byte[329]);
+            cshake2.DoOutput(buf, 0, buf.Length);
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("309bd7c285fcf8b839c9686b2cc00bd578947bee"), buf));
+
+            cshake2 = new CSHAKEDigest(128, new byte[29], new byte[300]);
+            cshake2.DoOutput(buf, 0, buf.Length);
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("ff6aafd83b8d22fc3e2e9b9948b581967ed9c5e7"), buf));
+        }
+
+        private void doFinalTest()
+        {
+            CSHAKEDigest cshake = new CSHAKEDigest(128, new byte[0], Strings.ToByteArray("Email Signature"));
+
+            cshake.BlockUpdate(Hex.Decode("00010203"), 0, 4);
+
+            byte[] res = new byte[32];
+
+            cshake.DoOutput(res, 0, res.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("c1c36925b6409a04f1b504fcbca9d82b4017277cb5ed2b2065fc1d3814d5aaf5"), res));
+
+            cshake.DoOutput(res, 0, res.Length);
+
+           Assert.IsTrue(!Arrays.AreEqual(Hex.Decode("c1c36925b6409a04f1b504fcbca9d82b4017277cb5ed2b2065fc1d3814d5aaf5"), res));
+
+            cshake.DoFinal(res, 0, res.Length);
+
+            cshake.BlockUpdate(Hex.Decode("00010203"), 0, 4);
+
+            cshake.DoFinal(res, 0, res.Length);
+
+            var s = Hex.ToHexString(res);
+
+            Console.WriteLine(s);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("c1c36925b6409a04f1b504fcbca9d82b4017277cb5ed2b2065fc1d3814d5aaf5"), res));
+
+            cshake.BlockUpdate(Hex.Decode("00010203"), 0, 4);
+
+            cshake.DoOutput(res, 0, res.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("c1c36925b6409a04f1b504fcbca9d82b4017277cb5ed2b2065fc1d3814d5aaf5"), res));
+
+            cshake.DoFinal(res, 0, res.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("9cbce830079c452abdeb875366a49ebfe75b89ef17396e34898e904830b0e136"), res));
+        }
+
+        private void longBlockTest()
+        {
+            byte[] data = new byte[16000];
+            byte[] res = new byte[32];
+
+            for (int i = 0; i != data.Length; i++)
+            {
+                data[i] = (byte)i;
+            }
+            
+                for (int i = 10000; i != data.Length; i++)
+                {
+                    CSHAKEDigest cshake_ = new CSHAKEDigest(128, new byte[0], Arrays.CopyOfRange(data, 0, i));
+
+                    cshake_.BlockUpdate(Hex.Decode("00010203"), 0, 4);
+
+                    cshake_.DoFinal(res, 0);
+                }
+            
+
+            CSHAKEDigest cshake = new CSHAKEDigest(256, new byte[0], new byte[200]);
+
+            cshake.BlockUpdate(Arrays.CopyOfRange(data, 0, 200), 0, 200);
+
+            cshake.DoFinal(res, 0);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("4a899b5be460d85a9789215bc17f88b8f8ac049bd3b519f561e7b5d3870dafa3"), res));
+        }
+
+        private void checkSHAKE(int bitSize, CSHAKEDigest cshake, byte[] msg)
+        {
+            
+            ShakeDigest ref_ = new ShakeDigest(bitSize);
+
+            ref_.BlockUpdate(msg, 0, msg.Length);
+            cshake.BlockUpdate(msg, 0, msg.Length);
+
+            byte[] res1 = new byte[32];
+            byte[] res2 = new byte[32];
+
+            ref_.DoFinal(res1, 0, res1.Length);
+            cshake.DoFinal(res2, 0, res2.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(res1, res2));
+        }
+
+    }
+}
diff --git a/crypto/test/src/crypto/test/KMACTest.cs b/crypto/test/src/crypto/test/KMACTest.cs
new file mode 100644
index 000000000..c7f3843c1
--- /dev/null
+++ b/crypto/test/src/crypto/test/KMACTest.cs
@@ -0,0 +1,245 @@
+using NUnit.Framework;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    public class KMACTest
+    {
+        [Test]
+        public void performTest()
+        {
+            KMac kmac = new KMac(128,  new byte[0] { });
+
+            Assert.AreEqual("KMAC128", kmac.AlgorithmName);
+
+            kmac.Init(new KeyParameter(Hex.Decode(
+                "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")));
+
+            kmac.BlockUpdate(Hex.Decode("00010203"), 0, 4);
+
+            byte[] res = new byte[32];
+
+            kmac.DoFinal(res, 0, res.Length);
+
+            Assert.IsTrue( Arrays.AreEqual(Hex.Decode("E5780B0D3EA6F7D3A429C5706AA43A00FADBD7D49628839E3187243F456EE14E"), res), "oops: " + Hex.ToHexString(res));
+
+            kmac = new KMac(128, Encoding.ASCII.GetBytes("My Tagged Application"));
+
+            kmac.Init(new KeyParameter(Hex.Decode(
+                "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")));
+
+            kmac.BlockUpdate(Hex.Decode("00010203"), 0, 4);
+
+            res = new byte[32];
+
+            kmac.DoFinal(res, 0, res.Length);
+
+            Assert.IsTrue( Arrays.AreEqual(Hex.Decode("3B1FBA963CD8B0B59E8C1A6D71888B7143651AF8BA0A7070C0979E2811324AA5"), res), "oops: " + Hex.ToHexString(res));
+
+            kmac = new KMac(128, Encoding.ASCII.GetBytes("My Tagged Application"));
+
+            kmac.Init(new KeyParameter(Hex.Decode(
+                "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")));
+
+            byte[] data = Hex.Decode(
+                "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1" +
+                    "F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3" +
+                    "E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5" +
+                    "D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7" +
+                    "C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9" +
+                    "B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9B" +
+                    "ABBBCBDBEBFC0C1C2C3C4C5C6C7");
+            kmac.BlockUpdate(data, 0, data.Length);
+
+            res = new byte[32];
+
+            kmac.DoFinal(res, 0, res.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("1F5B4E6CCA02209E0DCB5CA635B89A15E271ECC760071DFD805FAA38F9729230"), res), "oops:" + Hex.ToHexString(res));
+
+            kmac = new KMac(256, Encoding.ASCII.GetBytes("My Tagged Application"));
+
+            Assert.AreEqual("KMAC256", kmac.AlgorithmName);
+
+            kmac.Init(new KeyParameter(Hex.Decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")));
+
+            data = Hex.Decode("00 01 02 03");
+            kmac.BlockUpdate(data, 0, data.Length);
+
+            res = new byte[64];
+
+            kmac.DoFinal(res, 0, res.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("20C570C31346F703C9AC36C61C03CB64C3970D0CFC787E9B79599D273A68D2F7F69D4CC3DE9D104A351689F27CF6F5951F0103F33F4F24871024D9C27773A8DD"), res), "oops:" + Hex.ToHexString(res));
+
+            kmac = new KMac(256, new byte[] { });
+
+            kmac.Init(new KeyParameter(Hex.Decode(
+                "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")));
+
+            data = Hex.Decode(
+                "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1" +
+                    "F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3" +
+                    "E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5" +
+                    "D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7" +
+                    "C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9" +
+                    "B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9B" +
+                    "ABBBCBDBEBFC0C1C2C3C4C5C6C7");
+            kmac.BlockUpdate(data, 0, data.Length);
+
+            res = new byte[64];
+
+            kmac.DoFinal(res, 0, res.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("75358CF39E41494E949707927CEE0AF20A3FF553904C86B08F21CC414BCFD691589D27CF5E15369CBBFF8B9A4C2EB17800855D0235FF635DA82533EC6B759B69"), res), "oops:" + Hex.ToHexString(res));
+
+            kmac = new KMac(256, Encoding.ASCII.GetBytes("My Tagged Application"));
+
+            kmac.Init(new KeyParameter(Hex.Decode(
+                "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")));
+
+            data = Hex.Decode(
+                "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1" +
+                    "F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3" +
+                    "E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5" +
+                    "D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7" +
+                    "C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9" +
+                    "B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9B" +
+                    "ABBBCBDBEBFC0C1C2C3C4C5C6C7");
+            kmac.BlockUpdate(data, 0, data.Length);
+
+            res = new byte[64];
+
+            kmac.DoFinal(res, 0, res.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("B58618F71F92E1D56C1B8C55DDD7CD188B97B4CA4D99831EB2699A837DA2E4D970FBACFDE50033AEA585F1A2708510C32D07880801BD182898FE476876FC8965"), res), "oops:" + Hex.ToHexString(res));
+
+            doFinalTest();
+            longBlockTest();
+            paddingCheckTest();
+
+            checkKMAC(128, new KMac(128, new byte[0]), Hex.Decode("eeaabeef"));
+            checkKMAC(256, new KMac(256, null), Hex.Decode("eeaabeef"));
+            checkKMAC(128, new KMac(128, new byte[0]), Hex.Decode("eeaabeef"));
+            checkKMAC(128, new KMac(128, null), Hex.Decode("eeaabeef"));
+            checkKMAC(256, new KMac(256, null), Hex.Decode("eeaabeef"));
+
+        }
+
+        public void doFinalTest()
+        {
+            KMac kmac = new KMac(128, Encoding.ASCII.GetBytes("My Tagged Application"));
+
+            kmac.Init(new KeyParameter(Hex.Decode(
+                "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")));
+
+            kmac.BlockUpdate(Hex.Decode("00010203"), 0, 4);
+
+            byte[] res = new byte[32];
+
+            kmac.DoOutput(res, 0, res.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("31a44527b4ed9f5c6101d11de6d26f0620aa5c341def41299657fe9df1a3b16c"), res), Hex.ToHexString(res));
+
+            kmac.DoOutput(res, 0, res.Length);
+
+            Assert.IsTrue(!Arrays.AreEqual(Hex.Decode("31a44527b4ed9f5c6101d11de6d26f0620aa5c341def41299657fe9df1a3b16c"), res));
+
+            kmac.DoFinal(res, 0, res.Length);
+
+            kmac.BlockUpdate(Hex.Decode("00010203"), 0, 4);
+
+            kmac.DoFinal(res, 0, res.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("3B1FBA963CD8B0B59E8C1A6D71888B7143651AF8BA0A7070C0979E2811324AA5"), res));
+
+            kmac.BlockUpdate(Hex.Decode("00010203"), 0, 4);
+
+            kmac.DoOutput(res, 0, res.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("31a44527b4ed9f5c6101d11de6d26f0620aa5c341def41299657fe9df1a3b16c"), res));
+
+            kmac.DoFinal(res, 0, res.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("ffcb48c7620ccd67d1c83224186892cef2f2a99278d5cfdde10e48bdc89718c2"), res), Hex.ToHexString(res));
+        }
+
+        private void longBlockTest()
+        {
+            byte[] data = new byte[16000];
+            byte[] res = new byte[64];
+
+            for (int i = 0; i != data.Length; i++)
+            {
+                data[i] = (byte)i;
+            }
+
+            for (int i = 10000; i != data.Length; i++)
+            {
+                KMac kmac_ = new KMac(128, Arrays.CopyOfRange(data, 0, i));
+
+                kmac_.Init(new KeyParameter(new byte[0]));
+
+                kmac_.BlockUpdate(Hex.Decode("00010203"), 0, 4);
+
+                kmac_.DoFinal(res, 0);
+            }
+
+            KMac kmac = new KMac(256, new byte[200]);
+
+            kmac.Init(new KeyParameter(new byte[0]));
+
+            kmac.BlockUpdate(Arrays.CopyOfRange(data, 0, 200), 0, 200);
+
+            kmac.DoFinal(res, 0);
+
+            Assert.IsTrue(Arrays.AreEqual(Hex.Decode("f9476d9b3e42bf23307af5ccb5287fd6f033b23c400566a2ebc5829bd119aa545cd9b6bde76ef61cd31c3c0f0aaf0945f44481e863b19e9c26fb46c8b2a8a9bb"), res), Hex.ToHexString(res));
+        }
+
+        private void paddingCheckTest()
+        {
+            byte[] data = Hex.Decode("01880204187B3E43EDA8D51EC181D37DDE5B17ECCDD8BE84C268DC6C9500700857");
+            byte[] out_ = new byte[32];
+
+            KMac k128 = new KMac(128, new byte[0]);
+            k128.Init(new KeyParameter(new byte[163]));
+            k128.BlockUpdate(data, 0, data.Length);
+            k128.DoOutput(out_, 0, out_.Length);
+
+            Assert.IsTrue( Arrays.AreEqual(out_, Hex.Decode("6e6ab56468c7445f81c679f89f45c90a95a9c01afbaab5f7065b7e2e96f7d2bb")),"128 failed");
+
+            KMac k256 = new KMac(256, new byte[0]);
+            k256.Init(new KeyParameter(new byte[131]));
+            k256.BlockUpdate(data, 0, data.Length);
+            k256.DoOutput(out_, 0, out_.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(out_, Hex.Decode("f6302d4f854b4872e811b37993b6bfe027258089b6a9fbb26a755b1ebfc0d830")), "256 failed");
+        }
+
+        private void checkKMAC(int bitSize, KMac kmac, byte[] msg)
+        {
+            KMac ref_ = new KMac(bitSize, null);
+
+            ref_.Init(new KeyParameter(new byte[0]));
+            kmac.Init(new KeyParameter(new byte[0]));
+
+            ref_.BlockUpdate(msg, 0, msg.Length);
+            kmac.BlockUpdate(msg, 0, msg.Length);
+
+            byte[] res1 = new byte[32];
+            byte[] res2 = new byte[32];
+
+            ref_.DoFinal(res1, 0, res1.Length);
+            kmac.DoFinal(res2, 0, res2.Length);
+
+            Assert.IsTrue(Arrays.AreEqual(res1, res2));
+        }
+    }
+}
diff --git a/crypto/test/src/tsp/test/NewTspTest.cs b/crypto/test/src/tsp/test/NewTspTest.cs
index 6437064c1..dd2f084f2 100644
--- a/crypto/test/src/tsp/test/NewTspTest.cs
+++ b/crypto/test/src/tsp/test/NewTspTest.cs
@@ -10,7 +10,6 @@ using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Cms;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Operators;
-using Org.BouncyCastle.Crypto.Tls;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Date;