Code Listings
Chapter 18: Security
Permission subsets:
PrincipalPermission jay = new PrincipalPermission ("Jay", null); PrincipalPermission sue = new PrincipalPermission ("Sue", null); PrincipalPermission jayOrSue = (PrincipalPermission) jay.Union (sue); Console.WriteLine (jay.IsSubsetOf (jayOrSue)); // True
PermissionSet:
PermissionSet ps = new PermissionSet (PermissionState.None); ps.AddPermission (new UIPermission (PermissionState.Unrestricted)); ps.AddPermission (new SecurityPermission ( SecurityPermissionFlag.UnmanagedCode)); ps.AddPermission (new FileIOPermission ( FileIOPermissionAccess.Read, @"c:\docs")); ps.Demand();
Sandboxing another assembly:
using System; using System.IO; using System.Net; using System.Reflection; using System.Security; using System.Security.Policy; using System.Security.Permissions; class Program { static void Main() { string pluginFolder = AppDomain.CurrentDomain.BaseDirectory; string plugInPath = Path.Combine (pluginFolder, "plugin.exe"); PermissionSet ps = new PermissionSet (PermissionState.None); ps.AddPermission (new SecurityPermission (SecurityPermissionFlag.Execution)); ps.AddPermission (new FileIOPermission (FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, plugInPath)); ps.AddPermission (new UIPermission (PermissionState.Unrestricted)); AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation; AppDomain sandbox = AppDomain.CreateDomain ("sbox", null, setup, ps); sandbox.ExecuteAssembly (plugInPath); AppDomain.Unload (sandbox); } }
Making assertions:
public class Utils { public static void WriteLog (string msg) { FileIOPermission f = new FileIOPermission (PermissionState.None); f.AllLocalFiles = FileIOPermissionAccess.AllAccess; f.Assert(); // Write to log ... } }
static void Main() { string pluginFolder = AppDomain.CurrentDomain.BaseDirectory; string plugInPath = Path.Combine (pluginFolder, "plugin.exe"); PermissionSet ps = new PermissionSet (PermissionState.None); ps.AddPermission (new SecurityPermission (SecurityPermissionFlag.Execution)); ps.AddPermission (new FileIOPermission (FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, plugInPath)); ps.AddPermission (new UIPermission (PermissionState.Unrestricted)); AssemblyName utilAssembly = typeof (Utils).Assembly.GetName(); StrongName utils = new StrongName ( new StrongNamePublicKeyBlob (utilAssembly.GetPublicKey()), utilAssembly.Name, utilAssembly.Version); AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation; AppDomain sandbox = AppDomain.CreateDomain ("sbox", null, setup, ps, utils); sandbox.ExecuteAssembly (plugInPath); AppDomain.Unload (sandbox); }
Administrative elevation and virtualization:
<?xml version="1.0" encoding="utf-8"?> <assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> <security> <requestedPrivileges> <requestedExecutionLevel level="requireAdministrator" /> </requestedPrivileges> </security> </trustInfo> </assembly>
Cryptography: Windows data protection:
byte[] original = {1, 2, 3, 4, 5}; DataProtectionScope scope = DataProtectionScope.CurrentUser; byte[] encrypted = ProtectedData.Protect (original, null, scope); byte[] decrypted = ProtectedData.Unprotect (encrypted, null, scope); // decrypted is now {1, 2, 3, 4, 5}
Hashing:
byte[] hash; using (Stream fs = File.OpenRead ("checkme.doc")) hash = MD5.Create().ComputeHash (fs); // hash is 16 bytes long
or:
byte[] data = System.Text.Encoding.UTF8.GetBytes ("stRhong%pword"); byte[] hash = SHA256.Create().ComputeHash (data);
Symmetric encryption to a file:
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 = Rijndael.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);
Symmetric decryption from a file:
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[] decrypted = new byte[5]; using (SymmetricAlgorithm algorithm = Rijndael.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
RandomNumberGenerator:
byte[] key = new byte [16]; byte[] iv = new byte [16]; RandomNumberGenerator rand = RandomNumberGenerator.Create(); rand.GetBytes (key); rand.GetBytes (iv);
Encrypting in memory:
public static byte[] Encrypt (byte[] data, byte[] key, byte[] iv) { using (Rijndael algorithm = Rijndael.Create()) using (ICryptoTransform encryptor = algorithm.CreateEncryptor (key, iv)) return Crypt (data, key, iv, encryptor); } public static byte[] Decrypt (byte[] data, byte[] key, byte[] iv) { using (Rijndael algorithm = Rijndael.Create()) using (ICryptoTransform decryptor = algorithm.CreateDecryptor (key, iv)) return Crypt (data, key, iv, decryptor); } static byte[] Crypt (byte[] data, byte[] key, byte[] iv, ICryptoTransform cryptor) { MemoryStream m = new MemoryStream(); using (Stream c = new CryptoStream (m, cryptor, CryptoStreamMode.Write)) c.Write (data, 0, data.Length); return m.ToArray(); }
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)); }
Chaining encryption streams:
// Use default key/iv for demo. using (Rijndael algorithm = Rijndael.Create()) { using (ICryptoTransform encryptor = algorithm.CreateEncryptor()) 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)) w.WriteLine ("Small and secure!"); using (ICryptoTransform decryptor = algorithm.CreateDecryptor()) 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 (r.ReadLine()); // Small and secure! }
The RSA class:
byte[] data = { 1, 2, 3, 4, 5 }; // This is what we're encrypting. using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) { byte[] encrypted = rsa.Encrypt (data, true); byte[] decrypted = rsa.Decrypt (encrypted, true); }
Manufacturing an RSA key pair:
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) { File.WriteAllText ("PublicKeyOnly.xml", rsa.ToXmlString (false)); File.WriteAllText ("PublicPrivate.xml", rsa.ToXmlString (true)); }
Public key encryption and decryption:
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); } using (var rsaPublicPrivate = new RSACryptoServiceProvider()) { // With the private key we can successfully decrypt: rsaPublicPrivate.FromXmlString (publicPrivate); decrypted = rsaPublicPrivate.Decrypt (encrypted, true); }
Digital 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.Write (publicOnly.VerifyData (data, hasher, signature)); // True // Let's now tamper with the data, and recheck the signature: data[0] = 0; Console.Write (publicOnly.VerifyData (data, hasher, signature)); // False // The following throws an exception as we're lacking a private key: signature = publicOnly.SignData (data, hasher); }
© 2007, O'Reilly Media, Inc. All rights reserved