using System;
using System.Runtime.InteropServices;
using System.Text;

namespace digimoto
{
	public class Crypto
	{
		private class WinApi
		{
			private const int ALG_CLASS_HASH = 32768;

			private const int ALG_TYPE_ANY = 0;

			private const int ALG_CLASS_DATA_ENCRYPT = 24576;

			private const int ALG_TYPE_STREAM = 2048;

			private const int ALG_TYPE_BLOCK = 1536;

			private const int ALG_SID_DES = 1;

			private const int ALG_SID_RC4 = 1;

			private const int ALG_SID_RC2 = 2;

			private const int ALG_SID_MD5 = 3;

			public const string MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0";

			public const int PROV_RSA_FULL = 1;

			public const int CRYPT_VERIFYCONTEXT = -268435456;

			public const int CRYPT_EXPORTABLE = 1;

			public readonly static int CALG_MD5 = 32771;

			public readonly static int CALG_DES = 26113;

			public readonly static int CALG_RC2 = 26114;

			public readonly static int CALG_RC4 = 26625;

			private const string CryptDll = "advapi32.dll";

			private const string KernelDll = "kernel32.dll";

			public const int FORMAT_MESSAGE_FROM_SYSTEM = 4096;


			[DllImportAttribute("advapi32.dll")]
			public static extern bool CryptAcquireContext(ref IntPtr phProv, string pszContainer, string pszProvider, int dwProvType, int dwFlags);

			[DllImportAttribute("advapi32.dll")]
			public static extern bool CryptReleaseContext(IntPtr hProv, int dwFlags);

			[DllImportAttribute("advapi32.dll")]
			public static extern bool CryptDeriveKey(IntPtr hProv, int Algid, IntPtr hBaseData, int dwFlags, ref IntPtr phKey);

			[DllImportAttribute("advapi32.dll")]
			public static extern bool CryptCreateHash(IntPtr hProv, int Algid, IntPtr hKey, int dwFlags, ref IntPtr phHash);

			[DllImportAttribute("advapi32.dll")]
			public static extern bool CryptHashData(IntPtr hHash, byte[] pbData, int dwDataLen, int dwFlags);

			[DllImportAttribute("advapi32.dll")]
			public static extern bool CryptEncrypt(IntPtr hKey, IntPtr hHash, bool Final, int dwFlags, byte[] pbData, ref int pdwDataLen, int dwBufLen);

			[DllImportAttribute("advapi32.dll")]
			public static extern bool CryptDecrypt(IntPtr hKey, IntPtr hHash, bool Final, int dwFlags, byte[] pbData, ref int pdwDataLen);

			[DllImportAttribute("advapi32.dll")]
			public static extern bool CryptDestroyHash(IntPtr hHash);

			[DllImportAttribute("advapi32.dll")]
			public static extern bool CryptDestroyKey(IntPtr hKey);

			[DllImportAttribute("kernel32.dll")]
			public static extern int GetLastError();

			[DllImportAttribute("kernel32.dll")]
			public static extern int FormatMessage(int dwFlags, string lpSource, int dwMessageId, int dwLanguageId, StringBuilder lpBuffer, int nSize, string[] Arguments);
		}



		private Crypto()
		{
		}

		public static byte[] Encrypt(string passphrase, byte[] data)
		{
			byte[] bs1 = null;
			IntPtr j = IntPtr.Zero;
			IntPtr i1 = IntPtr.Zero;
			try
			{
				if (!WinApi.CryptAcquireContext(ref j, null, "Microsoft Base Cryptographic Provider v1.0", 1, -268435456))
				{
					Failed("CryptAcquireContext");
				}
				i1 = GetCryptoKey(j, passphrase);
				int i2 = data.Length;
				int k = data.Length;
				if (!WinApi.CryptEncrypt(i1, IntPtr.Zero, true, 0, null, ref i2, k))
				{
					Failed("CryptEncrypt");
				}
				bs1 = new byte[i2 - 1 + 1];
				Buffer.BlockCopy(data, 0, bs1, 0, data.Length);
				i2 = data.Length;
				k = bs1.Length;
				if (!WinApi.CryptEncrypt(i1, IntPtr.Zero, true, 0, bs1, ref i2, k))
				{
					Failed("CryptEncrypt");
				}
			}
			finally
			{
				if (!i1.Equals(IntPtr.Zero))
				{
					WinApi.CryptDestroyKey(i1);
				}
				if (!j.Equals(IntPtr.Zero))
				{
					WinApi.CryptReleaseContext(j, 0);
				}
			}
			return bs1;
		}

		public static byte[] Decrypt(string passphrase, byte[] data)
		{
			byte[] bs2 = (byte[])data.Clone();
			byte[] bs1 = null;
			IntPtr j = IntPtr.Zero;
			IntPtr i = IntPtr.Zero;
			try
			{
				if (!WinApi.CryptAcquireContext(ref j, null, "Microsoft Base Cryptographic Provider v1.0", 1, -268435456))
				{
					Failed("CryptAcquireContext");
				}
				i = GetCryptoKey(j, passphrase);
				int k = bs2.Length;
				if (!WinApi.CryptDecrypt(i, IntPtr.Zero, true, 0, bs2, ref k))
				{
					Failed("CryptDecrypt");
				}
				bs1 = new byte[k - 1 + 1];
				Buffer.BlockCopy(bs2, 0, bs1, 0, k);
			}
			finally
			{
				if (!i.Equals(IntPtr.Zero))
				{
					WinApi.CryptDestroyKey(i);
				}
				if (!j.Equals(IntPtr.Zero))
				{
					WinApi.CryptReleaseContext(j, 0);
				}
			}
			return bs1;
		}

		private static IntPtr GetCryptoKey(IntPtr hProv, string passphrase)
		{
			IntPtr j = IntPtr.Zero;
			IntPtr k = IntPtr.Zero;
			try
			{
				if (!WinApi.CryptCreateHash(hProv, WinApi.CALG_MD5, IntPtr.Zero, 0, ref j))
				{
					Failed("CryptCreateHash");
				}
				byte[] bs = Encoding.ASCII.GetBytes(passphrase);
				if (!WinApi.CryptHashData(j, bs, bs.Length, 0))
				{
					Failed("CryptHashData");
				}
				if (!WinApi.CryptDeriveKey(hProv, WinApi.CALG_RC2, j, 1, ref k))
				{
					Failed("CryptDeriveKey");
				}
			}
			finally
			{
				if (!j.Equals(IntPtr.Zero))
				{
					WinApi.CryptDestroyHash(j);
				}
			}
			return k;
		}

		private static void Failed(string command)
		{
			System.Windows.Forms.MessageBox.Show(command);
		}
	}

}
