Chapter 21 - Cryptography
Windows Data Protection
byte[] original = { 1, 2, 3, 4, 5 }; original.Dump ("Original"); DataProtectionScope scope = DataProtectionScope.CurrentUser; byte[] encrypted = ProtectedData.Protect (original, null, scope); encrypted.Dump("Encrypted"); byte[] decrypted = ProtectedData.Unprotect (encrypted, null, scope); // decrypted is now {1, 2, 3, 4, 5} decrypted.Dump("Decrypted");
Hashing files and strings
byte[] hash; // Compute hash from file: File.WriteAllText ("test.txt", @" The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog."); using (Stream fs = File.OpenRead ("test.txt")) hash = SHA1.Create().ComputeHash (fs); // SHA1 hash is 20 bytes long hash.Dump ("Hash from test.txt"); // Compute hash from string: byte[] data = System.Text.Encoding.UTF8.GetBytes ("stRhong%pword"); byte[] hash2 = SHA256.Create().ComputeHash (data); hash2.Dump ("Hash from string");
Hashing passwords with Pbkdf2
byte[] encrypted = KeyDerivation.Pbkdf2 ( password: "stRhong%pword", salt: Encoding.UTF8.GetBytes ("j78Y#p)/saREN!y3@"), prf: KeyDerivationPrf.HMACSHA512, iterationCount: 100, numBytesRequested: 64); encrypted.Dump();
AES Encrypt and Decrypt
byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9, 50 }; byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 }; byte[] data = { 1, 2, 3, 4, 5 }; // This is what we're encrypting. using (SymmetricAlgorithm algorithm = Aes.Create()) using (ICryptoTransform encryptor = algorithm.CreateEncryptor (key, iv)) using (Stream f = File.Create ("encrypted.bin")) using (Stream c = new CryptoStream (f, encryptor, CryptoStreamMode.Write)) c.Write (data, 0, data.Length); byte[] decrypted = new byte [5]; using (SymmetricAlgorithm algorithm = Aes.Create()) using (ICryptoTransform decryptor = algorithm.CreateDecryptor (key, iv)) using (Stream f = File.OpenRead ("encrypted.bin")) using (Stream c = new CryptoStream (f, decryptor, CryptoStreamMode.Read)) for (int b; (b = c.ReadByte()) > -1;) Console.Write (b + " "); // 1 2 3 4 5
AES In-Memory Cryptography
void Main() { byte[] key = new byte[16]; byte[] iv = new byte[16]; var cryptoRng = RandomNumberGenerator.Create(); cryptoRng.GetBytes (key); cryptoRng.GetBytes (iv); Console.WriteLine ($"Key: {string.Join ("", key.Select (b => b.ToString ("x2")))}"); Console.WriteLine ($"IV : {string.Join ("", iv.Select (b => b.ToString ("x2")))}"); string toEncrypt = "There are 10 kinds of people. Those that understand binary, and those that don't."; byte[] encrypted = MemCrypt.Encrypt(Encoding.UTF8.GetBytes(toEncrypt), key, iv); Console.WriteLine ($"Encrypted: {string.Join ("", encrypted.Select (b => b.ToString ("x2")))}"); byte[] decrypted = MemCrypt.Decrypt(encrypted, key, iv); Console.WriteLine ($"Decrypted: {Encoding.UTF8.GetString(decrypted)}"); string encrypted2 = MemCrypt.Encrypt ("Yeah!", key, iv); Console.WriteLine (encrypted2); // R1/5gYvcxyR2vzPjnT7yaQ== string decrypted2 = MemCrypt.Decrypt (encrypted2, key, iv); Console.WriteLine (decrypted2); // Yeah! Array.Clear (key, 0, key.Length); Array.Clear (iv, 0, iv.Length); Console.WriteLine ($"Key: {string.Join ("", key.Select (b => b.ToString ("x2")))}"); Console.WriteLine ($"IV : {string.Join ("", iv.Select (b => b.ToString ("x2")))}"); } class MemCrypt { public static byte[] Encrypt (byte[] data, byte[] key, byte[] iv) { using (Aes algorithm = Aes.Create()) using (ICryptoTransform encryptor = algorithm.CreateEncryptor (key, iv)) return Crypt (data, encryptor); } public static byte[] Decrypt (byte[] data, byte[] key, byte[] iv) { using (Aes algorithm = Aes.Create()) using (ICryptoTransform decryptor = algorithm.CreateDecryptor (key, iv)) return Crypt (data, decryptor); } public static string Encrypt (string data, byte[] key, byte[] iv) { return Convert.ToBase64String ( Encrypt (Encoding.UTF8.GetBytes (data), key, iv)); } public static string Decrypt (string data, byte[] key, byte[] iv) { return Encoding.UTF8.GetString ( Decrypt (Convert.FromBase64String (data), key, iv)); } static byte[] Crypt (byte[] data, ICryptoTransform cryptor) { MemoryStream m = new MemoryStream(); using (Stream c = new CryptoStream (m, cryptor, CryptoStreamMode.Write)) c.Write (data, 0, data.Length); return m.ToArray(); } }
Chaining Streams
byte[] key = new byte [16]; byte[] iv = new byte [16]; var cryptoRng = RandomNumberGenerator.Create(); cryptoRng.GetBytes (key); cryptoRng.GetBytes (iv); using (Aes algorithm = Aes.Create()) { using (ICryptoTransform encryptor = algorithm.CreateEncryptor(key, iv)) using (Stream f = File.Create ("serious.bin")) using (Stream c = new CryptoStream (f, encryptor, CryptoStreamMode.Write)) using (Stream d = new DeflateStream (c, CompressionMode.Compress)) using (StreamWriter w = new StreamWriter (d)) await w.WriteLineAsync ("Small and secure!"); using (ICryptoTransform decryptor = algorithm.CreateDecryptor(key, iv)) using (Stream f = File.OpenRead ("serious.bin")) using (Stream c = new CryptoStream (f, decryptor, CryptoStreamMode.Read)) using (Stream d = new DeflateStream (c, CompressionMode.Decompress)) using (StreamReader r = new StreamReader (d)) Console.WriteLine (await r.ReadLineAsync()); // Small and secure! }
RSA - Default KeySize
byte[] data = { 1, 2, 3, 4, 5 }; // This is what we're encrypting. using (var rsa = new RSACryptoServiceProvider()) { rsa.KeySize.Dump(); byte[] encrypted = rsa.Encrypt (data, true); byte[] decrypted = rsa.Decrypt (encrypted, true); }
RSA - Save Keys to XML
using (var rsa = new RSACryptoServiceProvider()) { File.WriteAllText ("PublicKeyOnly.xml", rsa.ToXmlString (false)); rsa.ToXmlString (false).Dump("PublicKeyOnly.xml"); File.WriteAllText ("PublicPrivate.xml", rsa.ToXmlString (true)); rsa.ToXmlString (true).Dump("PublicPrivate.xml"); }
RSA - Encrypting and Decrypting
// Create public/private keypair, and save to disk: using (var rsa = new RSACryptoServiceProvider()) { File.WriteAllText ("PublicKeyOnly.xml", rsa.ToXmlString (false)); File.WriteAllText ("PublicPrivate.xml", rsa.ToXmlString (true)); } // Encrypt. Note that we can directly encrypt only small messages. byte[] data = Encoding.UTF8.GetBytes ("Message to encrypt"); string publicKeyOnly = File.ReadAllText ("PublicKeyOnly.xml"); string publicPrivate = File.ReadAllText ("PublicPrivate.xml"); byte[] encrypted, decrypted; using (var rsaPublicOnly = new RSACryptoServiceProvider()) { rsaPublicOnly.FromXmlString (publicKeyOnly); encrypted = rsaPublicOnly.Encrypt (data, true); // The next line would throw an exception because you need the private // key in order to decrypt: // decrypted = rsaPublicOnly.Decrypt (encrypted, true); } // Decrypt: using (var rsaPublicPrivate = new RSACryptoServiceProvider()) { // With the private key we can successfully decrypt: rsaPublicPrivate.FromXmlString (publicPrivate); decrypted = rsaPublicPrivate.Decrypt (encrypted, true); Encoding.UTF8.GetString (decrypted).Dump ("decrypted"); }
RSA - Signing
byte[] data = Encoding.UTF8.GetBytes ("Message to sign"); byte[] publicKey; byte[] signature; object hasher = SHA1.Create(); // Our chosen hashing algorithm. // Generate a new key pair, then sign the data with it: using (var publicPrivate = new RSACryptoServiceProvider()) { signature = publicPrivate.SignData (data, hasher); publicKey = publicPrivate.ExportCspBlob (false); // get public key } // Create a fresh RSA using just the public key, then test the signature. using (var publicOnly = new RSACryptoServiceProvider()) { publicOnly.ImportCspBlob (publicKey); Console.WriteLine (publicOnly.VerifyData (data, hasher, signature)); // True // Let's now tamper with the data, and recheck the signature: data [0] = 0; Console.WriteLine (publicOnly.VerifyData (data, hasher, signature)); // False // The following throws an exception as we're lacking a private key: signature = publicOnly.SignData (data, hasher); }