4b893b0bfeba9b6985508998432d00ae946e1aa5
[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 = 3072 // [bit]. For encrypting and signing.
12 let aesKeySize = 128 // [bit].
13
14 exception KeySizeError
15 exception IVSizeError
16
17 /// Return 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 /// Generate 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) // Use 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) // Use padding OAEP (PKCS#1 v2).
38
39 /// Produce a signature from the given data.
40 let signRSA (privKey: Key) (data: Data) : Data =
41 use rsa = new RSACryptoServiceProvider (rsaKeySize)
42 rsa.FromXmlString privKey
43 rsa.SignHash (data, CryptoConfig.MapNameToOID "SHA256")
44
45 /// Verify a signature against the given data.
46 let verifySignRSA (pubKey: Key) (data: Data) (signature: Data) : bool =
47 use rsa = new RSACryptoServiceProvider (rsaKeySize)
48 rsa.FromXmlString pubKey
49 rsa.VerifyHash (data, CryptoConfig.MapNameToOID "SHA256", signature)
50
51 /// Return 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 /// Return 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 // Create 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