PageRenderTime 73ms CodeModel.GetById 40ms app.highlight 10ms RepoModel.GetById 20ms app.codeStats 0ms

/Utilities/Tests/CryptographyTests.cs

#
C# | 225 lines | 144 code | 23 blank | 58 comment | 5 complexity | d488ab519c4bc9b58617ed742e15fb02 MD5 | raw file
  1using System;
  2using System.IO;
  3using System.Text;
  4using Delta.Utilities.Cryptography;
  5using Delta.Utilities.Helpers;
  6using Delta.Utilities.Xml;
  7using NUnit.Framework;
  8
  9namespace Delta.Utilities.Tests
 10{
 11	/// <summary>
 12	/// Tests for the Cryptography classes.
 13	/// </summary>
 14	internal class CryptographyTests
 15	{
 16		#region EncryptAndDecryptData (LongRunning)
 17		/// <summary>
 18		/// Testing to encrypt and decrypt some data.
 19		/// </summary>
 20		[Test]
 21		[Category("LongRunning")]
 22		public static void EncryptAndDecryptData()
 23		{
 24			// Create a private key and 100 bytes of some boring data.
 25			byte[] privateKey = AES.CreatePrivateKey();
 26
 27			// Write out generated AES key for copy and pasting into code :)
 28			Console.WriteLine("Generated AES key: " + privateKey.Write());
 29
 30			MemoryStream someData = new MemoryStream();
 31			for (int num = 0; num < 100; num++)
 32			{
 33				someData.WriteByte((byte)num);
 34			}
 35
 36			// Encrypting and decrypting is really easy :)
 37			MemoryStream encrypted = AES.Encrypt(someData, privateKey);
 38			MemoryStream decrypted = AES.Decrypt(encrypted, privateKey);
 39
 40			// And finally check if we got all the original data back
 41			Assert.Equal(decrypted.Length, 100);
 42			for (int num = 0; num < 100; num++)
 43			{
 44				// Make sure the decrypted data is the same
 45				Assert.Equal(decrypted.ReadByte(), num);
 46			}
 47		}
 48		#endregion
 49
 50		#region TestEncryptDecryptPerformance (LongRunning)
 51		/// <summary>
 52		/// Test encrypt and decrypt performance with the simple static methods
 53		/// and with the optimized instance methods that to be constructed 
 54		/// first (and all their internals are kept around, no need to recreate)
 55		/// </summary>
 56		[Test]
 57		[Category("LongRunning")]
 58		public static void TestEncryptDecryptPerformance()
 59		{
 60			// Iterate 10000 times with 100 bytes of data = 1 MB! Takes ~100ms.
 61			// Note: Before we had a bit better performance with 60-70ms, but we
 62			// cached the encryptor and decryptor, which causes the next test to
 63			// fail: EncryptAndDecryptTwoStrings, so don't do that anymore!
 64			const int Iterations = 10000;
 65			// For 1000 the performance is almost the same, for 100 the instance,
 66			// but for small data arrays like 10 bytes instance methods are almost
 67			// 8 times faster :) The key thing here is not to send too much data
 68			// encrypted, keep it to a minimum, encrypting everything can be slow.
 69			// With instance methods we can encrypt 1 MB of data in about 50ms,
 70			// no matter how big or small each data packet is (for 10 byte packets
 71			// the overhead is slightly bigger with 100ms extra, but usually it
 72			// can be ignored). We can encrypt and decrypt about 20 MB per second,
 73			// which is more than most network connections can handle and we surely
 74			// do not need to encrypt every network message, only secure server
 75			// client stuff like authentication, passwords, shops, build data, etc.
 76			const int DataArraySize = 100; //10;//1000;
 77			byte[] privateKey = AES.CreatePrivateKey();
 78			MemoryStream someData = new MemoryStream();
 79			for (int num = 0; num < DataArraySize; num++)
 80			{
 81				someData.WriteByte((byte)num);
 82			}
 83			byte[] someDataArray = someData.ToArray();
 84
 85			// Start the timer and iterate
 86			DateTime start = DateTime.Now;
 87			// Note: takes 14-15s for 1 million iterations, way too long!
 88			for (int count = 0; count < Iterations; count++)
 89			{
 90				MemoryStream encrypted = AES.Encrypt(someData, privateKey);
 91				MemoryStream decrypted = AES.Decrypt(encrypted, privateKey);
 92			}
 93			Console.WriteLine(Iterations + " iterations took " +
 94			                  (DateTime.Now - start).TotalMilliseconds +
 95			                  "ms for static calls.");
 96
 97			// Now do the same with the instance methods, which is 1.2-10x faster.
 98			AES crypto = new AES(privateKey);
 99			start = DateTime.Now;
100			byte[] encryptedBytes = null;
101			byte[] decryptedBytes = null;
102			for (int count = 0; count < Iterations; count++)
103			{
104				encryptedBytes = crypto.Encrypt(someDataArray);
105				decryptedBytes = crypto.Decrypt(encryptedBytes,
106					someDataArray.Length);
107			}
108			Console.WriteLine(Iterations + " iterations took " +
109			                  (DateTime.Now - start).TotalMilliseconds +
110			                  "ms for instance calls.");
111
112			// Also check result, must still fit!
113			Assert.Equal(someDataArray, decryptedBytes);
114		}
115		#endregion
116
117		#region EncryptAndDecryptTwoStrings (LongRunning)
118		/// <summary>
119		/// Helper test to see if we can decrypt and encrypt multiple times.
120		/// </summary>
121		[Test]
122		[Category("LongRunning")]
123		public static void EncryptAndDecryptTwoStrings()
124		{
125			byte[] commonPrivateKey = AES.CreatePrivateKey();
126			AES crypto = new AES(commonPrivateKey);
127			// Create another instance of AES for decryption
128			AES decryptor = new AES(commonPrivateKey, crypto.Seed);
129
130			byte[] string1Array = StringHelper.StringToBytes("Hi there");
131			byte[] encrypted1Bytes = crypto.Encrypt(string1Array);
132			byte[] decrypted1Bytes = decryptor.Decrypt(encrypted1Bytes,
133				string1Array.Length);
134			Assert.Equal("Hi there", StringHelper.BytesToString(string1Array));
135
136			byte[] string2Array = StringHelper.StringToBytes("What is up");
137			byte[] encrypted2Bytes = crypto.Encrypt(string2Array);
138			byte[] decrypted2Bytes = decryptor.Decrypt(encrypted2Bytes,
139				string2Array.Length);
140			Assert.Equal("What is up", StringHelper.BytesToString(string2Array));
141		}
142		#endregion
143
144		#region TestRsaCrypto (LongRunning)
145		/// <summary>
146		/// Takes the RSA class for a test run.
147		/// </summary>
148		[Test]
149		[Category("LongRunning")]
150		public static void TestRsaCrypto()
151		{
152			DateTime start = DateTime.Now;
153			RSA rsa = new RSA(null);
154			Console.WriteLine("Done generating keys (took " +
155			                  (DateTime.Now - start).TotalMilliseconds + "ms)");
156
157			Console.WriteLine();
158			Console.WriteLine("rsa.Save(false)=" +
159			                  rsa.Save(false).GetWholeDocumentXmlText());
160			Console.WriteLine();
161			Console.WriteLine("rsa.Save(true)=" +
162			                  rsa.Save(true).GetWholeDocumentXmlText());
163			Console.WriteLine();
164
165			// Save public and private keys to file (used in the tests below)
166			rsa.Save(false).Save("Public.RSA.key");
167			rsa.Save(true).Save("Private.RSA.key");
168
169			string inputText = "abc123";
170
171			//Convert your  text to a byte array
172			byte[] rawBytes = Encoding.UTF8.GetBytes(inputText);
173			Console.WriteLine("rawBytes.Length=" + rawBytes.Length);
174
175			//Encrypt your raw bytes and return the encrypted bytes
176			byte[] encBytes = rsa.Encrypt(rawBytes);
177			Console.WriteLine("encBytes.Length=" + encBytes.Length);
178
179			//Now decrypt your encrypted bytes
180			byte[] decBytes = rsa.Decrypt(encBytes);
181			Console.WriteLine("decBytes.Length=" + decBytes.Length);
182
183			//Convert your decrypted bytes back to a string
184			Assert.Equal(inputText,
185				Encoding.UTF8.GetString(decBytes, 0, decBytes.Length));
186		}
187		#endregion
188
189		#region EncryptWithPublicRSAKey (LongRunning)
190		/// <summary>
191		/// Encrypt with public key and save result to file, which can be
192		/// tested later with DecryptWithPrivateRSAKey (even using a different RSA
193		/// implementation, which is the whole purpose of this test).
194		/// </summary>
195		[Test]
196		[Category("LongRunning")]
197		public static void EncryptWithPublicRSAKey()
198		{
199			RSA rsa = new RSA(XmlNode.FromFile("Public.RSA.key"));
200			// Note: The resulting file is always 256 bytes long (2048 bits).
201			FileHelper.CreateBinaryFile("EncryptedMessage.RSA",
202				rsa.Encrypt(Encoding.UTF8.GetBytes("Hi there ;)")));
203			Console.WriteLine("Wrote 'EncryptedMessage.RSA' file out.");
204		}
205		#endregion
206
207		#region DecryptWithPrivateRSAKey (LongRunning)
208		/// <summary>
209		/// The opposite of EncryptWithPublicRSAKey, this one decrypts the
210		/// message again and needs the matching "Private.RSA.key" file.
211		/// </summary>
212		[Test]
213		[Category("LongRunning")]
214		public static void DecryptWithPrivateRSAKey()
215		{
216			// First make sure we have the encrypted file!
217			EncryptWithPublicRSAKey();
218
219			RSA rsa = new RSA(XmlNode.FromFile("Private.RSA.key"));
220			byte[] bytes = rsa.Decrypt(FileHelper.GetBytes("EncryptedMessage.RSA"));
221			Console.WriteLine(Encoding.UTF8.GetString(bytes, 0, bytes.Length));
222		}
223		#endregion
224	}
225}