aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.Serialization/CryptographyHelper.cs
diff options
context:
space:
mode:
authorRoy Ben-Shabat <Roy@Twine-s.com>2017-12-04 14:15:48 +0200
committerRoy Ben-Shabat <Roy@Twine-s.com>2017-12-04 14:15:48 +0200
commita635302e9ae4a8ced135620e355697ccf2a27b52 (patch)
tree47b0cdebe8958833f45822970117160ce6c9d237 /Software/Visual_Studio/Tango.Serialization/CryptographyHelper.cs
parentc47075cc333329fc6bc93679d847cadcb050436f (diff)
downloadTango-a635302e9ae4a8ced135620e355697ccf2a27b52.tar.gz
Tango-a635302e9ae4a8ced135620e355697ccf2a27b52.zip
Added Tango.Serialization.
Added Tango.Settings.
Diffstat (limited to 'Software/Visual_Studio/Tango.Serialization/CryptographyHelper.cs')
-rw-r--r--Software/Visual_Studio/Tango.Serialization/CryptographyHelper.cs156
1 files changed, 156 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Tango.Serialization/CryptographyHelper.cs b/Software/Visual_Studio/Tango.Serialization/CryptographyHelper.cs
new file mode 100644
index 000000000..e072827fe
--- /dev/null
+++ b/Software/Visual_Studio/Tango.Serialization/CryptographyHelper.cs
@@ -0,0 +1,156 @@
+using System;
+using System.Text;
+using System.Security.Cryptography;
+using System.IO;
+using System.Linq;
+using System.Security;
+using System.Runtime.InteropServices;
+
+namespace Tango.Serialization
+{
+ /// <summary>
+ /// Represents a helper class for encryption and decryption of plain text.
+ /// </summary>
+ internal static class CryptographyHelper
+ {
+ private static SecureString passkey;
+
+ /// <summary>
+ /// Initializes the <see cref="CryptographyHelper"/> class.
+ /// </summary>
+ static CryptographyHelper()
+ {
+ passkey = new SecureString();
+ passkey.AppendChar('S');
+ passkey.AppendChar('@');
+ passkey.AppendChar('Y');
+ passkey.AppendChar('!');
+ }
+
+ // This constant is used to determine the keysize of the encryption algorithm in bits.
+ // We divide this by 8 within the code below to get the equivalent number of bytes.
+ private const int Keysize = 256;
+
+ // This constant determines the number of iterations for the password bytes generation function.
+ private const int DerivationIterations = 1000;
+
+ /// <summary>
+ /// Encrypts the specified plain text.
+ /// </summary>
+ /// <param name="plainText">The plain text.</param>
+ /// <returns></returns>
+ public static string Encrypt(string plainText)
+ {
+ // Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
+ // so that the same Salt and IV values can be used when decrypting.
+ var saltStringBytes = Generate256BitsOfRandomEntropy();
+ var ivStringBytes = Generate256BitsOfRandomEntropy();
+ var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
+ using (var password = new Rfc2898DeriveBytes(ConvertSecureStringToString(passkey), saltStringBytes, DerivationIterations))
+ {
+ var keyBytes = password.GetBytes(Keysize / 8);
+ using (var symmetricKey = new RijndaelManaged())
+ {
+ symmetricKey.BlockSize = 256;
+ symmetricKey.Mode = CipherMode.CBC;
+ symmetricKey.Padding = PaddingMode.PKCS7;
+ using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
+ {
+ using (var memoryStream = new MemoryStream())
+ {
+ using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
+ {
+ cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
+ cryptoStream.FlushFinalBlock();
+ // Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
+ var cipherTextBytes = saltStringBytes;
+ cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
+ cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
+ memoryStream.Close();
+ cryptoStream.Close();
+ return Convert.ToBase64String(cipherTextBytes);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Decrypts the specified cipher text.
+ /// </summary>
+ /// <param name="cipherText">The cipher text.</param>
+ /// <returns></returns>
+ public static string Decrypt(string cipherText)
+ {
+ // Get the complete stream of bytes that represent:
+ // [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
+ var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
+ // Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
+ var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
+ // Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
+ var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
+ // Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
+ var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
+
+ using (var password = new Rfc2898DeriveBytes(ConvertSecureStringToString(passkey), saltStringBytes, DerivationIterations))
+ {
+ var keyBytes = password.GetBytes(Keysize / 8);
+ using (var symmetricKey = new RijndaelManaged())
+ {
+ symmetricKey.BlockSize = 256;
+ symmetricKey.Mode = CipherMode.CBC;
+ symmetricKey.Padding = PaddingMode.PKCS7;
+ using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
+ {
+ using (var memoryStream = new MemoryStream(cipherTextBytes))
+ {
+ using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
+ {
+ var plainTextBytes = new byte[cipherTextBytes.Length];
+ var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
+ memoryStream.Close();
+ cryptoStream.Close();
+ return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Generate256s the bits of random entropy.
+ /// </summary>
+ /// <returns></returns>
+ private static byte[] Generate256BitsOfRandomEntropy()
+ {
+ var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
+ using (var rngCsp = new RNGCryptoServiceProvider())
+ {
+ // Fill the array with cryptographically secure random bytes.
+ rngCsp.GetBytes(randomBytes);
+ }
+ return randomBytes;
+ }
+
+ /// <summary>
+ /// Converts the secure string to string.
+ /// </summary>
+ /// <param name="value">The value.</param>
+ /// <returns></returns>
+ private static String ConvertSecureStringToString(SecureString value)
+ {
+ IntPtr valuePtr = IntPtr.Zero;
+ try
+ {
+ valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
+ return Marshal.PtrToStringUni(valuePtr);
+ }
+ finally
+ {
+ Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
+ }
+ }
+ }
+} \ No newline at end of file