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;
+ }
+ }
+}
|