/Utilities/Tests/CryptographyTests.cs
C# | 225 lines | 144 code | 23 blank | 58 comment | 5 complexity | d488ab519c4bc9b58617ed742e15fb02 MD5 | raw file
Possible License(s): Apache-2.0
- using System;
- using System.IO;
- using System.Text;
- using Delta.Utilities.Cryptography;
- using Delta.Utilities.Helpers;
- using Delta.Utilities.Xml;
- using NUnit.Framework;
-
- namespace Delta.Utilities.Tests
- {
- /// <summary>
- /// Tests for the Cryptography classes.
- /// </summary>
- internal class CryptographyTests
- {
- #region EncryptAndDecryptData (LongRunning)
- /// <summary>
- /// Testing to encrypt and decrypt some data.
- /// </summary>
- [Test]
- [Category("LongRunning")]
- public static void EncryptAndDecryptData()
- {
- // Create a private key and 100 bytes of some boring data.
- byte[] privateKey = AES.CreatePrivateKey();
-
- // Write out generated AES key for copy and pasting into code :)
- Console.WriteLine("Generated AES key: " + privateKey.Write());
-
- MemoryStream someData = new MemoryStream();
- for (int num = 0; num < 100; num++)
- {
- someData.WriteByte((byte)num);
- }
-
- // Encrypting and decrypting is really easy :)
- MemoryStream encrypted = AES.Encrypt(someData, privateKey);
- MemoryStream decrypted = AES.Decrypt(encrypted, privateKey);
-
- // And finally check if we got all the original data back
- Assert.Equal(decrypted.Length, 100);
- for (int num = 0; num < 100; num++)
- {
- // Make sure the decrypted data is the same
- Assert.Equal(decrypted.ReadByte(), num);
- }
- }
- #endregion
-
- #region TestEncryptDecryptPerformance (LongRunning)
- /// <summary>
- /// Test encrypt and decrypt performance with the simple static methods
- /// and with the optimized instance methods that to be constructed
- /// first (and all their internals are kept around, no need to recreate)
- /// </summary>
- [Test]
- [Category("LongRunning")]
- public static void TestEncryptDecryptPerformance()
- {
- // Iterate 10000 times with 100 bytes of data = 1 MB! Takes ~100ms.
- // Note: Before we had a bit better performance with 60-70ms, but we
- // cached the encryptor and decryptor, which causes the next test to
- // fail: EncryptAndDecryptTwoStrings, so don't do that anymore!
- const int Iterations = 10000;
- // For 1000 the performance is almost the same, for 100 the instance,
- // but for small data arrays like 10 bytes instance methods are almost
- // 8 times faster :) The key thing here is not to send too much data
- // encrypted, keep it to a minimum, encrypting everything can be slow.
- // With instance methods we can encrypt 1 MB of data in about 50ms,
- // no matter how big or small each data packet is (for 10 byte packets
- // the overhead is slightly bigger with 100ms extra, but usually it
- // can be ignored). We can encrypt and decrypt about 20 MB per second,
- // which is more than most network connections can handle and we surely
- // do not need to encrypt every network message, only secure server
- // client stuff like authentication, passwords, shops, build data, etc.
- const int DataArraySize = 100; //10;//1000;
- byte[] privateKey = AES.CreatePrivateKey();
- MemoryStream someData = new MemoryStream();
- for (int num = 0; num < DataArraySize; num++)
- {
- someData.WriteByte((byte)num);
- }
- byte[] someDataArray = someData.ToArray();
-
- // Start the timer and iterate
- DateTime start = DateTime.Now;
- // Note: takes 14-15s for 1 million iterations, way too long!
- for (int count = 0; count < Iterations; count++)
- {
- MemoryStream encrypted = AES.Encrypt(someData, privateKey);
- MemoryStream decrypted = AES.Decrypt(encrypted, privateKey);
- }
- Console.WriteLine(Iterations + " iterations took " +
- (DateTime.Now - start).TotalMilliseconds +
- "ms for static calls.");
-
- // Now do the same with the instance methods, which is 1.2-10x faster.
- AES crypto = new AES(privateKey);
- start = DateTime.Now;
- byte[] encryptedBytes = null;
- byte[] decryptedBytes = null;
- for (int count = 0; count < Iterations; count++)
- {
- encryptedBytes = crypto.Encrypt(someDataArray);
- decryptedBytes = crypto.Decrypt(encryptedBytes,
- someDataArray.Length);
- }
- Console.WriteLine(Iterations + " iterations took " +
- (DateTime.Now - start).TotalMilliseconds +
- "ms for instance calls.");
-
- // Also check result, must still fit!
- Assert.Equal(someDataArray, decryptedBytes);
- }
- #endregion
-
- #region EncryptAndDecryptTwoStrings (LongRunning)
- /// <summary>
- /// Helper test to see if we can decrypt and encrypt multiple times.
- /// </summary>
- [Test]
- [Category("LongRunning")]
- public static void EncryptAndDecryptTwoStrings()
- {
- byte[] commonPrivateKey = AES.CreatePrivateKey();
- AES crypto = new AES(commonPrivateKey);
- // Create another instance of AES for decryption
- AES decryptor = new AES(commonPrivateKey, crypto.Seed);
-
- byte[] string1Array = StringHelper.StringToBytes("Hi there");
- byte[] encrypted1Bytes = crypto.Encrypt(string1Array);
- byte[] decrypted1Bytes = decryptor.Decrypt(encrypted1Bytes,
- string1Array.Length);
- Assert.Equal("Hi there", StringHelper.BytesToString(string1Array));
-
- byte[] string2Array = StringHelper.StringToBytes("What is up");
- byte[] encrypted2Bytes = crypto.Encrypt(string2Array);
- byte[] decrypted2Bytes = decryptor.Decrypt(encrypted2Bytes,
- string2Array.Length);
- Assert.Equal("What is up", StringHelper.BytesToString(string2Array));
- }
- #endregion
-
- #region TestRsaCrypto (LongRunning)
- /// <summary>
- /// Takes the RSA class for a test run.
- /// </summary>
- [Test]
- [Category("LongRunning")]
- public static void TestRsaCrypto()
- {
- DateTime start = DateTime.Now;
- RSA rsa = new RSA(null);
- Console.WriteLine("Done generating keys (took " +
- (DateTime.Now - start).TotalMilliseconds + "ms)");
-
- Console.WriteLine();
- Console.WriteLine("rsa.Save(false)=" +
- rsa.Save(false).GetWholeDocumentXmlText());
- Console.WriteLine();
- Console.WriteLine("rsa.Save(true)=" +
- rsa.Save(true).GetWholeDocumentXmlText());
- Console.WriteLine();
-
- // Save public and private keys to file (used in the tests below)
- rsa.Save(false).Save("Public.RSA.key");
- rsa.Save(true).Save("Private.RSA.key");
-
- string inputText = "abc123";
-
- //Convert your text to a byte array
- byte[] rawBytes = Encoding.UTF8.GetBytes(inputText);
- Console.WriteLine("rawBytes.Length=" + rawBytes.Length);
-
- //Encrypt your raw bytes and return the encrypted bytes
- byte[] encBytes = rsa.Encrypt(rawBytes);
- Console.WriteLine("encBytes.Length=" + encBytes.Length);
-
- //Now decrypt your encrypted bytes
- byte[] decBytes = rsa.Decrypt(encBytes);
- Console.WriteLine("decBytes.Length=" + decBytes.Length);
-
- //Convert your decrypted bytes back to a string
- Assert.Equal(inputText,
- Encoding.UTF8.GetString(decBytes, 0, decBytes.Length));
- }
- #endregion
-
- #region EncryptWithPublicRSAKey (LongRunning)
- /// <summary>
- /// Encrypt with public key and save result to file, which can be
- /// tested later with DecryptWithPrivateRSAKey (even using a different RSA
- /// implementation, which is the whole purpose of this test).
- /// </summary>
- [Test]
- [Category("LongRunning")]
- public static void EncryptWithPublicRSAKey()
- {
- RSA rsa = new RSA(XmlNode.FromFile("Public.RSA.key"));
- // Note: The resulting file is always 256 bytes long (2048 bits).
- FileHelper.CreateBinaryFile("EncryptedMessage.RSA",
- rsa.Encrypt(Encoding.UTF8.GetBytes("Hi there ;)")));
- Console.WriteLine("Wrote 'EncryptedMessage.RSA' file out.");
- }
- #endregion
-
- #region DecryptWithPrivateRSAKey (LongRunning)
- /// <summary>
- /// The opposite of EncryptWithPublicRSAKey, this one decrypts the
- /// message again and needs the matching "Private.RSA.key" file.
- /// </summary>
- [Test]
- [Category("LongRunning")]
- public static void DecryptWithPrivateRSAKey()
- {
- // First make sure we have the encrypted file!
- EncryptWithPublicRSAKey();
-
- RSA rsa = new RSA(XmlNode.FromFile("Private.RSA.key"));
- byte[] bytes = rsa.Decrypt(FileHelper.GetBytes("EncryptedMessage.RSA"));
- Console.WriteLine(Encoding.UTF8.GetString(bytes, 0, bytes.Length));
- }
- #endregion
- }
- }