diff --git a/Crypto/src/crypto/engines/NoekeonEngine.cs b/Crypto/src/crypto/engines/NoekeonEngine.cs
new file mode 100644
index 000000000..b73e696a9
--- /dev/null
+++ b/Crypto/src/crypto/engines/NoekeonEngine.cs
@@ -0,0 +1,240 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * A Noekeon engine, using direct-key mode.
+ */
+ public class NoekeonEngine
+ : IBlockCipher
+ {
+ private const int GenericSize = 16; // Block and key size, as well as the amount of rounds.
+
+ private static readonly uint[] nullVector =
+ {
+ 0x00, 0x00, 0x00, 0x00 // Used in decryption
+ };
+
+ private static readonly uint[] roundConstants =
+ {
+ 0x80, 0x1b, 0x36, 0x6c,
+ 0xd8, 0xab, 0x4d, 0x9a,
+ 0x2f, 0x5e, 0xbc, 0x63,
+ 0xc6, 0x97, 0x35, 0x6a,
+ 0xd4
+ };
+
+ private uint[] state = new uint[4], // a
+ subKeys = new uint[4], // k
+ decryptKeys = new uint[4];
+
+ private bool _initialised, _forEncryption;
+
+ /**
+ * Create an instance of the Noekeon encryption algorithm
+ * and set some defaults
+ */
+ public NoekeonEngine()
+ {
+ _initialised = false;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Noekeon"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int GetBlockSize()
+ {
+ return GenericSize;
+ }
+
+ /**
+ * initialise
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception ArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("Invalid parameters passed to Noekeon init - " + parameters.GetType().Name, "parameters");
+
+ _forEncryption = forEncryption;
+ _initialised = true;
+
+ KeyParameter p = (KeyParameter) parameters;
+
+ setKey(p.GetKey());
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (!_initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+ if ((inOff + GenericSize) > input.Length)
+ throw new DataLengthException("input buffer too short");
+ if ((outOff + GenericSize) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ return _forEncryption
+ ? encryptBlock(input, inOff, output, outOff)
+ : decryptBlock(input, inOff, output, outOff);
+ }
+
+ public void Reset()
+ {
+ // TODO This should do something in case the encryption is aborted
+ }
+
+ /**
+ * Re-key the cipher.
+ *
+ * @param key the key to be used
+ */
+ private void setKey(byte[] key)
+ {
+ subKeys[0] = Pack.BE_To_UInt32(key, 0);
+ subKeys[1] = Pack.BE_To_UInt32(key, 4);
+ subKeys[2] = Pack.BE_To_UInt32(key, 8);
+ subKeys[3] = Pack.BE_To_UInt32(key, 12);
+ }
+
+ private int encryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ state[0] = Pack.BE_To_UInt32(input, inOff);
+ state[1] = Pack.BE_To_UInt32(input, inOff+4);
+ state[2] = Pack.BE_To_UInt32(input, inOff+8);
+ state[3] = Pack.BE_To_UInt32(input, inOff+12);
+
+ int i;
+ for (i = 0; i < GenericSize; i++)
+ {
+ state[0] ^= roundConstants[i];
+ theta(state, subKeys);
+ pi1(state);
+ gamma(state);
+ pi2(state);
+ }
+
+ state[0] ^= roundConstants[i];
+ theta(state, subKeys);
+
+ Pack.UInt32_To_BE(state[0], output, outOff);
+ Pack.UInt32_To_BE(state[1], output, outOff+4);
+ Pack.UInt32_To_BE(state[2], output, outOff+8);
+ Pack.UInt32_To_BE(state[3], output, outOff+12);
+
+ return GenericSize;
+ }
+
+ private int decryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ state[0] = Pack.BE_To_UInt32(input, inOff);
+ state[1] = Pack.BE_To_UInt32(input, inOff+4);
+ state[2] = Pack.BE_To_UInt32(input, inOff+8);
+ state[3] = Pack.BE_To_UInt32(input, inOff+12);
+
+ Array.Copy(subKeys, 0, decryptKeys, 0, subKeys.Length);
+ theta(decryptKeys, nullVector);
+
+ int i;
+ for (i = GenericSize; i > 0; i--)
+ {
+ theta(state, decryptKeys);
+ state[0] ^= roundConstants[i];
+ pi1(state);
+ gamma(state);
+ pi2(state);
+ }
+
+ theta(state, decryptKeys);
+ state[0] ^= roundConstants[i];
+
+ Pack.UInt32_To_BE(state[0], output, outOff);
+ Pack.UInt32_To_BE(state[1], output, outOff+4);
+ Pack.UInt32_To_BE(state[2], output, outOff+8);
+ Pack.UInt32_To_BE(state[3], output, outOff+12);
+
+ return GenericSize;
+ }
+
+ private void gamma(uint[] a)
+ {
+ a[1] ^= ~a[3] & ~a[2];
+ a[0] ^= a[2] & a[1];
+
+ uint tmp = a[3];
+ a[3] = a[0];
+ a[0] = tmp;
+ a[2] ^= a[0]^a[1]^a[3];
+
+ a[1] ^= ~a[3] & ~a[2];
+ a[0] ^= a[2] & a[1];
+ }
+
+ private void theta(uint[] a, uint[] k)
+ {
+ uint tmp;
+ tmp = a[0]^a[2];
+ tmp ^= rotl(tmp,8)^rotl(tmp,24);
+ a[1] ^= tmp;
+ a[3] ^= tmp;
+
+ for (int i = 0; i < 4; i++)
+ {
+ a[i] ^= k[i];
+ }
+
+ tmp = a[1]^a[3];
+ tmp ^= rotl(tmp,8)^rotl(tmp,24);
+ a[0] ^= tmp;
+ a[2] ^= tmp;
+ }
+
+ private void pi1(uint[] a)
+ {
+ a[1] = rotl(a[1], 1);
+ a[2] = rotl(a[2], 5);
+ a[3] = rotl(a[3], 2);
+ }
+
+ private void pi2(uint[] a)
+ {
+ a[1] = rotl(a[1], 31);
+ a[2] = rotl(a[2], 27);
+ a[3] = rotl(a[3], 30);
+ }
+
+ // Helpers
+
+ private uint rotl(uint x, int y)
+ {
+ return (x << y) | (x >> (32-y));
+ }
+ }
+}
|