8ea0629fb0f8c732aa98afaef256316c0a07517b
[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 let 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, false) // Uses PKCS#1 v1.5 padding.
33
34 let decryptRSA (privateKey: Key) (cipherdata: Data) : Data =
35 use rsa = new RSACryptoServiceProvider (rsaKeySize)
36 rsa.FromXmlString privateKey
37 rsa.Decrypt (cipherdata, false) // Uses PKCS#1 v1.5 padding.
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 let encryptor = aes.CreateEncryptor (key, iv)
57 new CryptoStream (outputStream, encryptor, CryptoStreamMode.Write)
58
59 /// Returns a decrypted input stream.
60 let decryptAES (key: byte[]) (iv: byte[]) (inputStream: Stream) : CryptoStream =
61 if key.Length <> aesKeySize / 8 then raise KeySizeError
62 if iv.Length <> 16 then raise IVSizeError
63 use aes = new AesCryptoServiceProvider (KeySize = aesKeySize)
64 let decryptor = aes.CreateDecryptor (key, iv)
65 new CryptoStream (inputStream, decryptor, CryptoStreamMode.Read)
66
67 // Create a stream to compute the HMAC-SHA256 against all data being written.
68 let HMACStream (key: byte[]) (outputStream: Stream) : Stream * HMACSHA256 =
69 if key.Length <> 32 then raise KeySizeError
70 let hmac = new HMACSHA256 (key)
71 new CryptoStream (outputStream, hmac, CryptoStreamMode.Write) :> Stream, hmac
72
73 let ComputeHMAC (key: byte[]) (inputStream: Stream) : byte[] =
74 if key.Length <> 32 then raise KeySizeError
75 let hmac = new HMACSHA256 (key)
76 hmac.ComputeHash inputStream