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 = 3072 // [bit]. For encrypting and signing. let aesKeySize = 128 // [bit]. exception KeySizeError exception IVSizeError /// Return a cryptographically strong sequence of bytes. let rand size : byte[] = let result = Array.zeroCreate size use generator = new RNGCryptoServiceProvider () generator.GetBytes result result /// Generate a new RSA key pair: (public * private). let generateRSAKeysPair () : Key * Key = use rsa = new RSACryptoServiceProvider (rsaKeySize) rsa.ToXmlString false, rsa.ToXmlString true let encryptRSA (publicKey: Key) (plaindata: Data) : Data = use rsa = new RSACryptoServiceProvider (rsaKeySize) rsa.FromXmlString publicKey rsa.Encrypt (plaindata, true) // Use padding OAEP (PKCS#1 v2). let decryptRSA (privateKey: Key) (cipherdata: Data) : Data = use rsa = new RSACryptoServiceProvider (rsaKeySize) rsa.FromXmlString privateKey rsa.Decrypt (cipherdata, true) // Use padding OAEP (PKCS#1 v2). /// Produce a signature from the given data. let signRSA (privKey: Key) (data: Data) : Data = use rsa = new RSACryptoServiceProvider (rsaKeySize) rsa.FromXmlString privKey rsa.SignHash (data, CryptoConfig.MapNameToOID "SHA256") /// Verify a signature against the given data. let verifySignRSA (pubKey: Key) (data: Data) (signature: Data) : bool = use rsa = new RSACryptoServiceProvider (rsaKeySize) rsa.FromXmlString pubKey rsa.VerifyHash (data, CryptoConfig.MapNameToOID "SHA256", signature) /// Return an encrypted output stream. let encryptAES (key: byte[]) (iv: byte[]) (outputStream: Stream) : CryptoStream = if key.Length <> aesKeySize / 8 then raise KeySizeError if iv.Length <> 16 then raise IVSizeError use aes = new AesCryptoServiceProvider (KeySize = aesKeySize) // Default mode is CBC. new CryptoStream (outputStream, aes.CreateEncryptor (key, iv), CryptoStreamMode.Write) /// Return a decrypted input stream. let decryptAES (key: byte[]) (iv: byte[]) (inputStream: Stream) : CryptoStream = if key.Length <> aesKeySize / 8 then raise KeySizeError if iv.Length <> 16 then raise IVSizeError use aes = new AesCryptoServiceProvider (KeySize = aesKeySize) new CryptoStream (inputStream, aes.CreateDecryptor (key, iv), CryptoStreamMode.Read) /// Create a stream to compute HMAC-SHA256 against all data being written. let HMACStream (key: byte[]) (outputStream: Stream) : Stream * HMACSHA256 = if key.Length <> 32 then raise KeySizeError let hmac = new HMACSHA256 (key) new CryptoStream (outputStream, hmac, CryptoStreamMode.Write) :> Stream, hmac /// Compute HMAC-SHA256 for all the data in the input stream. let ComputeHMAC (key: byte[]) (inputStream: Stream) : byte[] = if key.Length <> 32 then raise KeySizeError use hmac = new HMACSHA256 (key) hmac.ComputeHash inputStream