namespace CryptoFile open System open System.IO open System.Security.Cryptography // Some cryptography primitives specific to CryptoFile. module internal Crypto = type Data = byte[] let rsaKeySize = 2048 /// Returns a cryptographically strong sequence of bytes. let rand size : byte[] = let result = Array.zeroCreate size let generator = new RNGCryptoServiceProvider () generator.GetBytes result result /// Generate a new RSA key pair: (public * private). let generateRSAKeysPair : Key * Key = use rsa = new RSACryptoServiceProvider (rsaKeySize) try rsa.ToXmlString false, rsa.ToXmlString true finally rsa.PersistKeyInCsp <- false let encryptRSA (publicKey: Key) (plaindata: Data) : Data = use rsa = new RSACryptoServiceProvider (rsaKeySize) try rsa.FromXmlString publicKey rsa.Encrypt (plaindata, false) // Uses PKCS#1 v1.5 padding. finally rsa.PersistKeyInCsp <- false let decryptRSA (privateKey: Key) (cipherdata: Data) : Data = use rsa = new RSACryptoServiceProvider (rsaKeySize) try rsa.FromXmlString privateKey rsa.Decrypt (cipherdata, false) // Uses PKCS#1 v1.5 padding. finally rsa.PersistKeyInCsp <- false /// Produces a signature from a given hash. let signRSA (privKey: Key) (sha256: Data) : Data = use rsa = new RSACryptoServiceProvider (rsaKeySize) try rsa.FromXmlString privKey rsa.SignHash (sha256, CryptoConfig.MapNameToOID "SHA256") finally rsa.PersistKeyInCsp <- false /// Verify a signature against a given hash. let verifySignRSA (pubKey: Key) (sha256: Data) (signature: Data) : bool = use rsa = new RSACryptoServiceProvider (rsaKeySize) try rsa.FromXmlString pubKey rsa.VerifyHash (sha256, CryptoConfig.MapNameToOID "SHA256", signature) finally rsa.PersistKeyInCsp <- false /// Returns an encrypted output stream. let encryptAES (key: byte[]) (iv: byte[]) (outputStream: Stream) : CryptoStream = assert (key.Length = 32 && iv.Length = 16) use aes = new AesCryptoServiceProvider () // Default mode is CBC. aes.KeySize <- 256 let encryptor = aes.CreateEncryptor (key, iv) new CryptoStream (outputStream, encryptor, CryptoStreamMode.Write) /// Returns a decrypted input stream. let decryptAES (key: byte[]) (iv: byte[]) (inputStream: Stream) : CryptoStream = assert (key.Length = 32 && iv.Length = 16) use aes = new AesCryptoServiceProvider () aes.KeySize <- 256 let decryptor = aes.CreateDecryptor (key, iv) new CryptoStream (inputStream, decryptor, CryptoStreamMode.Read) // Create a stream to compute the HMAC-SHA256 against all data being written. let HMACStream (key: byte[]) (outputStream: Stream) : Stream * HMACSHA256 = assert (key.Length = 32) let hmac = new HMACSHA256 (key) new CryptoStream (outputStream, hmac, CryptoStreamMode.Write) :> Stream, hmac let ComputeHMAC (key: byte[]) (inputStream: Stream) : byte[] = assert (key.Length = 32) let hmac = new HMACSHA256 (key) hmac.ComputeHash inputStream