Put the API in an seperate library assembly and create an assembly for testing.
[crypto_lab2.git] / labo2-fsharp / CryptoFile / Crypto.fs
diff --git a/labo2-fsharp/CryptoFile/Crypto.fs b/labo2-fsharp/CryptoFile/Crypto.fs
new file mode 100644 (file)
index 0000000..34d54fa
--- /dev/null
@@ -0,0 +1,75 @@
+namespace CryptoFile
+
+// Some cryptography primitives specific to CryptoFile.
+module internal Crypto =
+    open System.Security.Cryptography
+    open System.IO
+
+    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) : Stream =
+        assert (key.Length = 32 && iv.Length = 16)
+        use aes = new AesManaged ()
+        aes.KeySize <- 256
+        let encryptor = aes.CreateEncryptor (key, iv)
+        new CryptoStream (outputStream, encryptor, CryptoStreamMode.Write) :> Stream
+
+    /// Returns a decrypted input stream.
+    let decryptAES (key : byte[]) (iv : byte[]) (inputStream : Stream) : Stream =
+        assert (key.Length = 32 && iv.Length = 16)
+        use aes = new AesManaged ()
+        aes.KeySize <- 256
+        let decryptor = aes.CreateDecryptor (key, iv)
+        new CryptoStream (inputStream, decryptor, CryptoStreamMode.Read) :> Stream