// (c) 2006 Richard Grimes // www.grimes.demon.co.uk using System; using System.Security; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; using System.IO; // Make sure that you use a certificate with an exchange key // makecert -r -pe -n "CN=Richard Grimes" -sky exchange -sv cert.pvk cert.cer // cert2spc cert.cer cert.spc // pvkimprt -pfx cert.spc cert.pvk class App { static void Main(string[] args) { if (args.Length < 3) { Console.WriteLine("Usage: encrypt infile outfile certfile [e|d]"); return; } string inFile = args[0]; if (!File.Exists(inFile)) { Console.WriteLine("{0} does not exist", inFile); return; } string outFile = args[1]; if (File.Exists(outFile)) { File.Delete(outFile); } string certFile = args[2]; if (!File.Exists(certFile)) { Console.WriteLine("{0} does not exist", certFile); return; } bool encrypt = true; if (args.Length == 4) encrypt = (args[3][0] == 'e'); if (encrypt) { Encrypt(inFile, outFile, certFile); } else { Decrypt(inFile, outFile, certFile); } } static void Encrypt(string inFile, string outFile, string certFile) { using (FileStream fs = new FileStream(outFile, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { // Create Rijndael password Rijndael r = Rijndael.Create(); // Encrypt with public key X509Certificate2 cert = new X509Certificate2(certFile); RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PublicKey.Key; // The rsa key is bigger than the Rijndael key, we can only encrypt blocks // the size of the rsa key byte[] keyBuf = new byte[rsa.KeySize/8]; Buffer.BlockCopy(r.Key, 0, keyBuf, 0, r.Key.Length); // Write key size to file byte[] i32 = BitConverter.GetBytes(r.Key.Length); fs.Write(i32, 0, i32.Length); // Write IV length to file i32 = BitConverter.GetBytes(r.IV.Length); fs.Write(i32, 0, i32.Length); // Write encrypted password to out file byte[] buf = rsa.Encrypt(r.Key, false); fs.Write(buf, 0, buf.Length); // Write Rijndael IV to out file fs.Write(r.IV, 0, r.IV.Length); using (FileStream data = File.OpenRead(inFile)) { // Encrypt as it is read in CryptoStream cs = new CryptoStream( data, r.CreateEncryptor(), CryptoStreamMode.Read); byte[] databuf = new byte[r.BlockSize/8]; while (true) { int read = 0; read = cs.Read(databuf, 0, databuf.Length); if (read == 0) break; fs.Write(databuf, 0, read); } cs.Clear(); } } } static void Decrypt(string inFile, string outFile, string certFile) { // Decrypt with private key X509Certificate2 cert = null; Console.Write("Password for certificate file: "); using (SecureString ss = new SecureString()) { while (true) { ConsoleKeyInfo key = Console.ReadKey(true); if (key.Key == ConsoleKey.Enter || key.Key == ConsoleKey.Escape) break; Console.Write('*'); ss.AppendChar(key.KeyChar); } Console.WriteLine(); cert = new X509Certificate2(certFile, ss); } using (FileStream fs = new FileStream(inFile, FileMode.Open, FileAccess.Read, FileShare.None)) { byte[] i32 = new byte[4]; Rijndael r = Rijndael.Create(); // Read key length from file fs.Read(i32, 0, i32.Length); int keyLen = BitConverter.ToInt32(i32, 0); r.KeySize = keyLen * 8; // Read IV buffer length from file fs.Read(i32, 0, i32.Length); int ivBufLen = BitConverter.ToInt32(i32, 0); // Read Rijndael password from in file, must be a rsa key size RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey; // Read encrypted Rijndael key byte[] buf = new byte[rsa.KeySize / 8]; fs.Read(buf, 0, buf.Length); byte[] keyBuf = rsa.Decrypt(buf, false); byte[] key = new byte[keyLen]; Buffer.BlockCopy(keyBuf, 0, key, 0, key.Length); r.Key = key; // Read Rijndael IV from in file byte[] iv = new byte[ivBufLen]; fs.Read(iv, 0, iv.Length); r.IV = iv; CryptoStream cs = new CryptoStream( fs, r.CreateDecryptor(), CryptoStreamMode.Read); using (FileStream data = File.OpenWrite(outFile)) { byte[] databuf = new byte[r.BlockSize/8]; while (true) { int read = 0; read = cs.Read(databuf, 0, databuf.Length); if (read == 0) break; data.Write(databuf, 0, read); } } cs.Clear(); } } }