using System;
using System.Text;

using Lidgren.Network;
using System.Security;

namespace UnitTests
{
	public static class EncryptionTests
	{
		public static void Run(NetPeer peer)
		{
			//
			// Test XTEA
			//
			NetXtea xtea = new NetXtea("TopSecret");

			byte[] original = new byte[16];
			NetRandom.Instance.NextBytes(original);

			byte[] encrypted = new byte[original.Length];
			xtea.EncryptBlock(original, 0, encrypted, 0);
			xtea.EncryptBlock(original, 8, encrypted, 8);

			byte[] decrypted = new byte[original.Length];
			xtea.DecryptBlock(encrypted, 0, decrypted, 0);
			xtea.DecryptBlock(encrypted, 8, decrypted, 8);

			// compare!
			for (int i = 0; i < original.Length; i++)
				if (original[i] != decrypted[i])
					throw new NetException("XTEA fail!");

			Console.WriteLine("XTEA OK");

			NetOutgoingMessage om = peer.CreateMessage();
			om.Write("Hallon");
			om.Write(42);
			om.Write(5, 5);
			om.Write(true);
			om.Write("kokos");
			om.Encrypt(xtea);

			// convert to incoming message
			NetIncomingMessage im = Program.CreateIncomingMessage(om.PeekDataBuffer(), om.LengthBits);
			im.Decrypt(xtea);

			if (im.ReadString() != "Hallon")
				throw new NetException("fail");
			if (im.ReadInt32() != 42)
				throw new NetException("fail");
			if (im.ReadInt32(5) != 5)
				throw new NetException("fail");
			if (im.ReadBoolean() != true)
				throw new NetException("fail");
			if (im.ReadString() != "kokos")
				throw new NetException("fail");

			Console.WriteLine("Message encryption OK");

			/*
			Console.WriteLine("x = " + NetUtility.ToHexString(x));
			Console.WriteLine("v = " + NetUtility.ToHexString(verifier));
			Console.WriteLine("");

			byte[] a = NetUtility.ToByteArray("d378cc3b09d12cfca5130e22df3f2f3bcf8ecfaddeae6af7f8b3e9f8b4fc9749"); // random
			Console.WriteLine("a = " + NetUtility.ToHexString(a));
			byte[] A = NetSRP.ComputeClientChallenge(a);
			Console.WriteLine("A = " + NetUtility.ToHexString(A));
			Console.WriteLine("");

			byte[] b = NetUtility.ToByteArray("8394bdaebe1709124f4c1221707053440b30e270d457ece02818da63b53c2482"); // random
			Console.WriteLine("b = " + NetUtility.ToHexString(b)); 
			byte[] B = NetSRP.ComputeServerChallenge(b, verifier);
			Console.WriteLine("B = " + NetUtility.ToHexString(B));
			Console.WriteLine("");

			byte[] u = NetSRP.ComputeU(A, B);
			Console.WriteLine("u = " + NetUtility.ToHexString(u));

			byte[] serverCompareValue; // Ss
			serverCompareValue = NetSRP.ComputeServerCompareValue(A, verifier, u, b);
			Console.WriteLine("Ss = " + NetUtility.ToHexString(serverCompareValue));

			byte[] clientCompareValue; // Ss
			clientCompareValue = NetSRP.ComputeClientCompareValue(B, x, u, a);
			Console.WriteLine("Sc = " + NetUtility.ToHexString(clientCompareValue));
			*/

			//
			// Pre-step:
			//
			// Server must store { Username, salt, verifier }
			//byte[] salt = NetSRP.CreateRandomSalt();
			byte[] salt = NetUtility.ToByteArray("D016E5A43F0E2A1C8FF8");
			Console.WriteLine("s = " + NetUtility.ToHexString(salt));
			byte[] serverVerifier;
			byte[] clientVerifier;
			NetSRP.ComputePasswordVerifier("user", "password", salt, out serverVerifier, out clientVerifier);
			//
			Console.WriteLine("x = " + NetUtility.ToHexString(clientVerifier));
			Console.WriteLine("v = " + NetUtility.ToHexString(serverVerifier));

			// CLIENT:
			// Step 1: Client creates session private/public key pair
			//byte[] clientPrivateKey = NetSRP.CreateRandomKey();
			byte[] clientPrivateKey = NetUtility.ToByteArray("EFDBE24D15173DC1FBA22A8D51077AE932841CB2DBA8B09B2CFC5543983B2C7A");
			Console.WriteLine("a = " + NetUtility.ToHexString(clientPrivateKey));
			byte[] clientPublicKey = NetSRP.ComputeClientPublicKey(clientPrivateKey);
			// Step 2: Client sends username and client public key to server

			// SERVER:
			// Step 3: Server creates session private/public key pair
			//byte[] serverPrivateKey = NetSRP.CreateRandomKey();
			byte[] serverPrivateKey = NetUtility.ToByteArray("FB1D472CD89EAF323DB0F7DE80A01CC51DD5A0D1AFC8B79F3CF5A2FC88529ADC");
			Console.WriteLine("b = " + NetUtility.ToHexString(serverPrivateKey));
			byte[] serverPublicKey = NetSRP.ComputeServerPublicKey(serverPrivateKey, serverVerifier);
			// Step 4: Server sends salt and server public key to client

			// CLIENT:
			// Step 5: Client computes u and compare value
			byte[] u = NetSRP.ComputeU(clientPublicKey, serverPublicKey);
			Console.WriteLine("u = " + NetUtility.ToHexString(u));
			byte[] clientSessionKey = NetSRP.ComputeClientSessionKey(serverPublicKey, clientVerifier, u, clientPrivateKey); // this is where client proves it has x (and thus the password)
			Console.WriteLine("Sc = " + NetUtility.ToHexString(clientSessionKey));

			// SERVER:
			// Step 6: Server computes u and compare value
			// byte[] u = NetSRP.ComputeU(clientPublicKey, serverPublicKey);
			byte[] serverSessionKey = NetSRP.ComputeServerSessionKey(clientPublicKey, serverVerifier, u, serverPrivateKey);
			Console.WriteLine("Ss = " + NetUtility.ToHexString(serverSessionKey));

			if (!NetUtility.CompareElements(clientSessionKey, serverSessionKey))
				Console.WriteLine("BAD!!!!!!!");

			// Console.WriteLine("SRP test OK");
/*
C ==> S  C, A  
C <== S  s, B  
C ==> S  M[1]  
C <== S  M[2] 
			*/

		}
	}
}
