Clean up.
[crypto_lab2.git] / labo2-fsharp / CryptoFile / Crypto.fs
1 namespace CryptoFile
2
3 open System
4 open System.IO
5 open System.Security.Cryptography
6
7 // Some cryptography primitives specific to CryptoFile.
8 module internal Crypto =
9 type Data = byte[]
10
11 let rsaKeySize = 2048
12 let aesKeySize = 128
13
14 exception KeySizeError
15 exception IVSizeError
16
17 /// Returns a cryptographically strong sequence of bytes.
18 let rand size : byte[] =
19 let result = Array.zeroCreate size
20 use generator = new RNGCryptoServiceProvider ()
21 generator.GetBytes result
22 result
23
24 /// Generates a new RSA key pair: (public * private).
25 let generateRSAKeysPair : Key * Key =
26 use rsa = new RSACryptoServiceProvider (rsaKeySize)
27 rsa.ToXmlString false, rsa.ToXmlString true
28
29 let encryptRSA (publicKey: Key) (plaindata: Data) : Data =
30 use rsa = new RSACryptoServiceProvider (rsaKeySize)
31 rsa.FromXmlString publicKey
32 rsa.Encrypt (plaindata, true) // Uses padding OAEP (PKCS#1 v2).
33
34 let decryptRSA (privateKey: Key) (cipherdata: Data) : Data =
35 use rsa = new RSACryptoServiceProvider (rsaKeySize)
36 rsa.FromXmlString privateKey
37 rsa.Decrypt (cipherdata, true) // Uses padding OAEP (PKCS#1 v2).
38
39 /// Produces a signature from a given hash.
40 let signRSA (privKey: Key) (sha256: Data) : Data =
41 use rsa = new RSACryptoServiceProvider (rsaKeySize)
42 rsa.FromXmlString privKey
43 rsa.SignHash (sha256, CryptoConfig.MapNameToOID "SHA256")
44
45 /// Verify a signature against a given hash.
46 let verifySignRSA (pubKey: Key) (sha256: Data) (signature: Data) : bool =
47 use rsa = new RSACryptoServiceProvider (rsaKeySize)
48 rsa.FromXmlString pubKey
49 rsa.VerifyHash (sha256, CryptoConfig.MapNameToOID "SHA256", signature)
50
51 /// Returns an encrypted output stream.
52 let encryptAES (key: byte[]) (iv: byte[]) (outputStream: Stream) : CryptoStream =
53 if key.Length <> aesKeySize / 8 then raise KeySizeError
54 if iv.Length <> 16 then raise IVSizeError
55 use aes = new AesCryptoServiceProvider (KeySize = aesKeySize) // Default mode is CBC.
56 new CryptoStream (outputStream, aes.CreateEncryptor (key, iv), CryptoStreamMode.Write)
57
58 /// Returns a decrypted input stream.
59 let decryptAES (key: byte[]) (iv: byte[]) (inputStream: Stream) : CryptoStream =
60 if key.Length <> aesKeySize / 8 then raise KeySizeError
61 if iv.Length <> 16 then raise IVSizeError
62 use aes = new AesCryptoServiceProvider (KeySize = aesKeySize)
63 new CryptoStream (inputStream, aes.CreateDecryptor (key, iv), CryptoStreamMode.Read)
64
65 // Creates a stream to compute the HMAC-SHA256 against all data being written.
66 let HMACStream (key: byte[]) (outputStream: Stream) : Stream * HMACSHA256 =
67 if key.Length <> 32 then raise KeySizeError
68 let hmac = new HMACSHA256 (key)
69 new CryptoStream (outputStream, hmac, CryptoStreamMode.Write) :> Stream, hmac
70
71 let ComputeHMAC (key: byte[]) (inputStream: Stream) : byte[] =
72 if key.Length <> 32 then raise KeySizeError
73 use hmac = new HMACSHA256 (key)
74 hmac.ComputeHash inputStream