summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Hook <dgh@bouncycastle.org>2017-07-06 18:51:02 +1000
committerDavid Hook <dgh@bouncycastle.org>2017-07-06 18:51:02 +1000
commitf83b8c09c6fe002c5fea009d8a9fb3e5c55856d1 (patch)
treee3a6965a86878334f1236b785bae39d7a4053b21
parentDSTU 7624 MAC (diff)
downloadBouncyCastle.NET-ed25519-f83b8c09c6fe002c5fea009d8a9fb3e5c55856d1.tar.xz
added KCTR
-rw-r--r--crypto/src/crypto/modes/KCtrBlockCipher.cs235
-rw-r--r--crypto/test/src/crypto/test/DSTU7624Test.cs9
-rw-r--r--crypto/test/src/crypto/test/StreamCipherVectorTest.cs12
3 files changed, 245 insertions, 11 deletions
diff --git a/crypto/src/crypto/modes/KCtrBlockCipher.cs b/crypto/src/crypto/modes/KCtrBlockCipher.cs
new file mode 100644
index 000000000..ff0249a6c
--- /dev/null
+++ b/crypto/src/crypto/modes/KCtrBlockCipher.cs
@@ -0,0 +1,235 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+    /**
+    * Implements a Gamming or Counter (CTR) mode on top of a DSTU 7624 block cipher.
+    */
+    public class KCtrBlockCipher : IStreamCipher, IBlockCipher
+    {
+        private byte[] IV;
+        private byte[] ofbV;
+        private byte[] ofbOutV;
+        private bool initialised;
+
+        private int byteCount;
+
+        private readonly int blockSize;
+        private readonly IBlockCipher cipher;
+
+        /**
+      * Basic constructor.
+      *
+      * @param cipher the block cipher to be used as the basis of the
+      * feedback mode.
+      */
+        public KCtrBlockCipher(IBlockCipher cipher)
+        {
+            this.cipher = cipher;
+            this.IV = new byte[cipher.GetBlockSize()];
+            this.blockSize = cipher.GetBlockSize();
+
+            this.ofbV = new byte[cipher.GetBlockSize()];
+            this.ofbOutV = new byte[cipher.GetBlockSize()];
+        }
+
+        /**
+        * return the underlying block cipher that we are wrapping.
+        *
+        * @return the underlying block cipher that we are wrapping.
+        */
+        public IBlockCipher GetUnderlyingCipher()
+        {
+            return cipher;
+        }
+        /**
+        * Initialise the cipher and, possibly, the initialisation vector (IV).
+        * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+        * An IV which is too short is handled in FIPS compliant fashion.
+        *
+        * @param forEncryption if true the cipher is initialised for
+        *  encryption, if false for decryption.
+        * @param param the key and other data required by the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool forEncryption,
+            ICipherParameters parameters)
+        {
+            this.initialised = true;
+            if (parameters is ParametersWithIV)
+            {
+                ParametersWithIV ivParam = (ParametersWithIV)parameters;
+                byte[] iv = ivParam.GetIV();
+                int diff = IV.Length - iv.Length;
+
+                Array.Clear(IV, 0, IV.Length);
+                Array.Copy(iv, 0, IV, diff, iv.Length);
+         
+                parameters = ivParam.Parameters;
+            }
+            else
+            {
+                throw new ArgumentException("Invalid parameter passed");
+            }
+
+            // if it's null, key is to be reused.
+            if (parameters != null)
+            {
+                cipher.Init(true, parameters);
+            }
+
+            Reset();
+        }
+
+        /**
+        * return the algorithm name and mode.
+        *
+        * @return the name of the underlying algorithm followed by "/KCTR"
+        * and the block size in bits.
+        */
+        public string AlgorithmName
+        {
+            get { return cipher.AlgorithmName + "/KCTR"; }
+        }
+
+        public bool IsPartialBlockOkay
+        {
+            get { return true; }
+        }
+
+        /**
+      * return the block size we are operating at.
+      *
+      * @return the block size we are operating at (in bytes).
+      */
+        public int GetBlockSize()
+        {
+            return cipher.GetBlockSize();
+        }
+
+        public byte ReturnByte(byte input)
+        {
+            return CalculateByte(input);
+        }
+
+        public void ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+        {
+            if (outOff + len > output.Length)
+            {
+               throw new DataLengthException("Output buffer too short");
+            }
+
+            if (inOff + len > input.Length)
+            {
+                    throw new DataLengthException("Input buffer too small");
+            }
+
+            int inStart = inOff;
+            int inEnd = inOff + len;
+            int outStart = outOff;
+
+            while (inStart<inEnd)
+            {
+                 output[outStart++] = CalculateByte(input[inStart++]);
+            }
+        }
+
+        protected byte CalculateByte(byte b)
+        {
+            if (byteCount == 0)
+            {
+                incrementCounterAt(0);
+
+                checkCounter();
+
+                cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
+
+                return (byte)(ofbOutV[byteCount++] ^ b);
+            }
+
+            byte rv = (byte)(ofbOutV[byteCount++] ^ b);
+
+            if (byteCount == ofbV.Length)
+            {
+                byteCount = 0;
+            }
+
+            return rv;
+        }
+
+        /**
+         * Process one block of input from the array in and write it to
+         * the out array.
+         *
+         * @param input the array containing the input data.
+         * @param inOff offset into the in array the data starts at.
+         * @param output the array the output data will be copied into.
+         * @param outOff the offset into the out array the output will start at.
+         * @exception DataLengthException if there isn't enough data in in, or
+         * space in out.
+         * @exception InvalidOperationException if the cipher isn't initialised.
+         * @return the number of bytes processed and produced.
+         */
+        public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
+        {
+            if (input.Length - inOff< GetBlockSize())
+            {
+                throw new DataLengthException("Input buffer too short");
+            }
+            if (output.Length - outOff< GetBlockSize())
+            {
+                throw new DataLengthException("Output buffer too short");
+            }
+
+            ProcessBytes(input, inOff, GetBlockSize(), output, outOff);
+
+            return GetBlockSize();
+        }
+
+        /**
+        * reset the chaining vector back to the IV and reset the underlying
+        * cipher.
+        */
+        public void Reset()
+        {
+            if (initialised)
+            {
+                cipher.ProcessBlock(IV, 0, ofbV, 0);
+            }
+            cipher.Reset();
+            byteCount = 0;
+        }
+
+        private void incrementCounterAt(int pos)
+        {
+            int i = pos;
+            while (i < ofbV.Length)
+            {
+                if (++ofbV[i++] != 0)
+                {
+                    break;
+                }
+            }
+        }
+
+        private void checkCounter()
+        {
+            // TODO:
+            // if the IV is the same as the blocksize we assume the user knows what they are doing
+            //        if (IV.length < ofbV.length)
+            //        {
+            //            for (int i = 0; i != IV.length; i++)
+            //            {
+            //                if (ofbV[i] != IV[i])
+            //                {
+            //                    throw new IllegalStateException("Counter in KCTR mode out of range.");
+            //                }
+            //            }
+            //        }
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/DSTU7624Test.cs b/crypto/test/src/crypto/test/DSTU7624Test.cs
index 6d55146a4..baced41fd 100644
--- a/crypto/test/src/crypto/test/DSTU7624Test.cs
+++ b/crypto/test/src/crypto/test/DSTU7624Test.cs
@@ -68,11 +68,12 @@ namespace Org.BouncyCastle.Crypto.Tests
                new BlockCipherVectorTest(29, new OfbBlockCipher(new Dstu7624Engine(256, 512), 256), new ParametersWithIV(new KeyParameter(Hex.Decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.Decode("5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746454443424140")), "98E122708FDABB1B1A5765C396DC79D7573221EC486ADDABD1770B147A6DD00B5FBC4F1EC68C59775B7AAA4D43C4CCE4F396D982DF64D30B03EF6C3B997BA0ED940BBC590BD30D64B5AE207147D71086B5", "BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F"),
                new BlockCipherVectorTest(30, new OfbBlockCipher(new Dstu7624Engine(512, 512), 512), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), Hex.Decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F")), "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0", "CAA761980599B3ED2E945C41891BAD95F72B11C73ED26536A6847458BC76C827357156B4B3FE0DC1877F5B9F17B866C37B21D89531DB48007D05DEC928B06766C014BB9080385EDF0677E48A0A39B5E7489E28E82FFFD1F84694F17296CB701656"),
                new BlockCipherVectorTest(31, new OfbBlockCipher(new Dstu7624Engine(512, 512), 512), new ParametersWithIV(new KeyParameter(Hex.Decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.Decode("7F7E7D7C7B7A797877767574737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746454443424140")), "06C061A4A66DFC0910034B3CFBDC4206D8908241C56BF41C4103CFD6DF322210B87F57EAE9F9AD815E606A7D1E8E6BD7CB1EBFBDBCB085C2D06BF3CC1586CB2EE1D81D38437F425131321647E42F5DE309D33F25B89DE37124683E4B44824FC56D", "EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F"),
-               
-               
-
-               
 
+               //CTR mode
+               new BlockCipherVectorTest(24, new KCtrBlockCipher(new Dstu7624Engine(128, 128)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748", "A90A6B9780ABDFDFF64D14F5439E88F266DC50EDD341528DD5E698E2F000CE21F872DAF9FE1811844A"),
+               new BlockCipherVectorTest(25, new KCtrBlockCipher(new Dstu7624Engine(128, 128)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F", "B91A7B8790BBCFCFE65D04E5538E98E216AC209DA33122FDA596E8928070BE51"),
+               new StreamCipherVectorTest(26, new KCtrBlockCipher(new Dstu7624Engine(128, 128)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748", "A90A6B9780ABDFDFF64D14F5439E88F266DC50EDD341528DD5E698E2F000CE21F872DAF9FE1811844A"),
+               new StreamCipherVectorTest(27, new KCtrBlockCipher(new Dstu7624Engine(128, 128)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F", "B91A7B8790BBCFCFE65D04E5538E98E216AC209DA33122FDA596E8928070BE51")
         };
 
         public override ITestResult Perform()
diff --git a/crypto/test/src/crypto/test/StreamCipherVectorTest.cs b/crypto/test/src/crypto/test/StreamCipherVectorTest.cs
index ead2f16c3..c807a6841 100644
--- a/crypto/test/src/crypto/test/StreamCipherVectorTest.cs
+++ b/crypto/test/src/crypto/test/StreamCipherVectorTest.cs
@@ -11,7 +11,7 @@ namespace Org.BouncyCastle.Crypto.Tests
      * a basic test that takes a stream cipher, key parameter, and an input
      * and output string.
      */
-    public class StreamCipherVectorTest: ITest
+    public class StreamCipherVectorTest: SimpleTest
     {
         int                 id;
         IStreamCipher       cipher;
@@ -33,12 +33,12 @@ namespace Org.BouncyCastle.Crypto.Tests
             this.output = Hex.Decode(output);
         }
 
-		public string Name
+		public override string Name
 		{
 			get { return cipher.AlgorithmName + " Vector Test " + id; }
 		}
 
-		public ITestResult Perform()
+		public override void PerformTest()
         {
             cipher.Init(true, param);
 
@@ -48,7 +48,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 
             if (!Arrays.AreEqual(outBytes, output))
             {
-                return new SimpleTestResult(false, Name + ": failed - "
+                Fail("failed - "
 					+ "expected " + Hex.ToHexString(output)
 					+ " got " + Hex.ToHexString(outBytes));
             }
@@ -59,10 +59,8 @@ namespace Org.BouncyCastle.Crypto.Tests
 
             if (!Arrays.AreEqual(input, outBytes))
             {
-                return new SimpleTestResult(false, Name + ": failed reversal");
+                Fail("failed reversal");
             }
-
-            return new SimpleTestResult(true, Name + ": OKAY");
         }
     }
 }