summary refs log tree commit diff
path: root/Crypto/src/crypto/engines/Cast6Engine.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Crypto/src/crypto/engines/Cast6Engine.cs')
-rw-r--r--Crypto/src/crypto/engines/Cast6Engine.cs279
1 files changed, 279 insertions, 0 deletions
diff --git a/Crypto/src/crypto/engines/Cast6Engine.cs b/Crypto/src/crypto/engines/Cast6Engine.cs
new file mode 100644
index 000000000..c5c419b78
--- /dev/null
+++ b/Crypto/src/crypto/engines/Cast6Engine.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+     * A class that provides CAST6 key encryption operations,
+     * such as encoding data and generating keys.
+     *
+     * All the algorithms herein are from the Internet RFC
+     *
+     * RFC2612 - CAST6 (128bit block, 128-256bit key)
+     *
+     * and implement a simplified cryptography interface.
+     */
+    public sealed class Cast6Engine
+		: Cast5Engine
+    {
+        //====================================
+        // Useful constants
+        //====================================
+        private const int ROUNDS = 12;
+        private const int BLOCK_SIZE = 16;  // bytes = 128 bits
+
+		/*
+        * Put the round and mask keys into an array.
+        * Kr0[i] => _Kr[i*4 + 0]
+        */
+        private int []_Kr = new int[ROUNDS*4]; // the rotating round key(s)
+        private uint []_Km = new uint[ROUNDS*4]; // the masking round key(s)
+
+		/*
+        * Key setup
+        */
+        private int []_Tr = new int[24 * 8];
+        private uint []_Tm = new uint[24 * 8];
+        private uint[] _workingKey = new uint[8];
+
+		public Cast6Engine()
+        {
+        }
+
+		public override string AlgorithmName
+        {
+            get { return "CAST6"; }
+        }
+
+		public override void Reset()
+        {
+        }
+
+		public override int GetBlockSize()
+        {
+            return BLOCK_SIZE;
+        }
+
+		//==================================
+        // Private Implementation
+        //==================================
+        /*
+        * Creates the subkeys using the same nomenclature
+        * as described in RFC2612.
+        *
+        * See section 2.4
+        */
+        internal override void SetKey(
+			byte[] key)
+        {
+            uint Cm = 0x5a827999;
+            uint Mm = 0x6ed9eba1;
+            int Cr = 19;
+            int Mr = 17;
+            /*
+            * Determine the key size here, if required
+            *
+            * if keysize < 256 bytes, pad with 0
+            *
+            * Typical key sizes => 128, 160, 192, 224, 256
+            */
+            for (int i=0; i< 24; i++)
+            {
+                for (int j=0; j< 8; j++)
+                {
+                    _Tm[i*8 + j] = Cm;
+                    Cm += Mm; //mod 2^32;
+                    _Tr[i*8 + j] = Cr;
+                    Cr = (Cr + Mr) & 0x1f;            // mod 32
+                }
+            }
+
+			byte[] tmpKey = new byte[64];
+			key.CopyTo(tmpKey, 0);
+
+			// now create ABCDEFGH
+            for (int i = 0; i < 8; i++)
+            {
+                _workingKey[i] = Pack.BE_To_UInt32(tmpKey, i*4);
+            }
+
+			// Generate the key schedule
+            for (int i = 0; i < 12; i++)
+            {
+                // KAPPA <- W2i(KAPPA)
+                int i2 = i*2 *8;
+                _workingKey[6] ^= F1(_workingKey[7], _Tm[i2], _Tr[i2]);
+                _workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]);
+                _workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]);
+                _workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]);
+                _workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]);
+                _workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]);
+                _workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]);
+                _workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]);
+                // KAPPA <- W2i+1(KAPPA)
+                i2 = (i*2 + 1)*8;
+                _workingKey[6] ^= F1(_workingKey[7], _Tm[i2], _Tr[i2]);
+                _workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]);
+                _workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]);
+                _workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]);
+                _workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]);
+                _workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]);
+                _workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]);
+                _workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]);
+                // Kr_(i) <- KAPPA
+                _Kr[i*4] = (int)(_workingKey[0] & 0x1f);
+                _Kr[i*4 + 1] = (int)(_workingKey[2] & 0x1f);
+                _Kr[i*4 + 2] = (int)(_workingKey[4] & 0x1f);
+                _Kr[i*4 + 3] = (int)(_workingKey[6] & 0x1f);
+                // Km_(i) <- KAPPA
+                _Km[i*4] = _workingKey[7];
+                _Km[i*4 + 1] = _workingKey[5];
+                _Km[i*4 + 2] = _workingKey[3];
+                _Km[i*4 + 3] = _workingKey[1];
+            }
+        }
+
+		/**
+        * Encrypt the given input starting at the given offset and place
+        * the result in the provided buffer starting at the given offset.
+        *
+        * @param src        The plaintext buffer
+        * @param srcIndex    An offset into src
+        * @param dst        The ciphertext buffer
+        * @param dstIndex    An offset into dst
+        */
+        internal override int EncryptBlock(
+            byte[]	src,
+            int		srcIndex,
+            byte[]	dst,
+            int		dstIndex)
+        {
+            // process the input block
+            // batch the units up into 4x32 bit chunks and go for it
+            uint A = Pack.BE_To_UInt32(src, srcIndex);
+            uint B = Pack.BE_To_UInt32(src, srcIndex + 4);
+            uint C = Pack.BE_To_UInt32(src, srcIndex + 8);
+            uint D = Pack.BE_To_UInt32(src, srcIndex + 12);
+            uint[] result = new uint[4];
+            CAST_Encipher(A, B, C, D, result);
+            // now stuff them into the destination block
+            Pack.UInt32_To_BE(result[0], dst, dstIndex);
+            Pack.UInt32_To_BE(result[1], dst, dstIndex + 4);
+            Pack.UInt32_To_BE(result[2], dst, dstIndex + 8);
+            Pack.UInt32_To_BE(result[3], dst, dstIndex + 12);
+            return BLOCK_SIZE;
+        }
+
+		/**
+        * Decrypt the given input starting at the given offset and place
+        * the result in the provided buffer starting at the given offset.
+        *
+        * @param src        The plaintext buffer
+        * @param srcIndex    An offset into src
+        * @param dst        The ciphertext buffer
+        * @param dstIndex    An offset into dst
+        */
+        internal override int DecryptBlock(
+            byte[]	src,
+            int		srcIndex,
+            byte[]	dst,
+            int		dstIndex)
+        {
+            // process the input block
+            // batch the units up into 4x32 bit chunks and go for it
+            uint A = Pack.BE_To_UInt32(src, srcIndex);
+            uint B = Pack.BE_To_UInt32(src, srcIndex + 4);
+            uint C = Pack.BE_To_UInt32(src, srcIndex + 8);
+            uint D = Pack.BE_To_UInt32(src, srcIndex + 12);
+            uint[] result = new uint[4];
+            CAST_Decipher(A, B, C, D, result);
+            // now stuff them into the destination block
+            Pack.UInt32_To_BE(result[0], dst, dstIndex);
+            Pack.UInt32_To_BE(result[1], dst, dstIndex + 4);
+            Pack.UInt32_To_BE(result[2], dst, dstIndex + 8);
+            Pack.UInt32_To_BE(result[3], dst, dstIndex + 12);
+            return BLOCK_SIZE;
+        }
+
+		/**
+        * Does the 12 quad rounds rounds to encrypt the block.
+        *
+        * @param A    the 00-31  bits of the plaintext block
+        * @param B    the 32-63  bits of the plaintext block
+        * @param C    the 64-95  bits of the plaintext block
+        * @param D    the 96-127 bits of the plaintext block
+        * @param result the resulting ciphertext
+        */
+        private void CAST_Encipher(
+			uint	A,
+			uint	B,
+			uint	C,
+			uint	D,
+			uint[]	result)
+        {
+            for (int i = 0; i < 6; i++)
+            {
+                int x = i*4;
+                // BETA <- Qi(BETA)
+                C ^= F1(D, _Km[x], _Kr[x]);
+                B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+                A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+                D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+            }
+            for (int i = 6; i < 12; i++)
+            {
+                int x = i*4;
+                // BETA <- QBARi(BETA)
+                D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+                A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+                B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+                C ^= F1(D, _Km[x], _Kr[x]);
+            }
+            result[0] = A;
+            result[1] = B;
+            result[2] = C;
+            result[3] = D;
+        }
+
+		/**
+        * Does the 12 quad rounds rounds to decrypt the block.
+        *
+        * @param A    the 00-31  bits of the ciphertext block
+        * @param B    the 32-63  bits of the ciphertext block
+        * @param C    the 64-95  bits of the ciphertext block
+        * @param D    the 96-127 bits of the ciphertext block
+        * @param result the resulting plaintext
+        */
+        private void CAST_Decipher(
+			uint	A,
+			uint	B,
+			uint	C,
+			uint	D,
+			uint[]	result)
+        {
+            for (int i = 0; i < 6; i++)
+            {
+                int x = (11-i)*4;
+                // BETA <- Qi(BETA)
+                C ^= F1(D, _Km[x], _Kr[x]);
+                B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+                A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+                D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+            }
+            for (int i=6; i<12; i++)
+            {
+                int x = (11-i)*4;
+                // BETA <- QBARi(BETA)
+                D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+                A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+                B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+                C ^= F1(D, _Km[x], _Kr[x]);
+            }
+            result[0] = A;
+            result[1] = B;
+            result[2] = C;
+            result[3] = D;
+        }
+    }
+}