summary refs log tree commit diff
path: root/Crypto/src/crypto/engines/NoekeonEngine.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Crypto/src/crypto/engines/NoekeonEngine.cs')
-rw-r--r--Crypto/src/crypto/engines/NoekeonEngine.cs240
1 files changed, 240 insertions, 0 deletions
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));
+		}
+	}
+}