f85825faaad12687ff600e06f1f06cbbd13b73bf
6 open System.Security.Cryptography
10 let keySize = 128 // [bit].
14 let randBytes (nb
: int) : byte
array =
15 let result = Array.zeroCreate
nb
16 use generator = new RNGCryptoServiceProvider ()
17 generator.GetBytes result
20 let generateKey () : Key =
21 let bytes = randBytes (keySize / 8)
22 Convert.ToBase64String bytes |> WebUtility.UrlEncode
24 // TODO: return a Result<string, EncryptError>
25 let encrypt (key
: Key) (name
: string) : string =
26 let keyAsBytes = WebUtility.UrlDecode key |> Convert.FromBase64String
27 let iv = randBytes (keySize / 8)
29 use aes = new AesCryptoServiceProvider (KeySize = keySize) // Default mode is CBC.
30 use stream = new MemoryStream ()
31 use cryptoStream = new CryptoStream (stream, aes.CreateEncryptor (keyAsBytes, iv), CryptoStreamMode.Write)
32 let nameAsBytes = Encoding.UTF8.GetBytes name
34 use sha = SHA256.Create ()
35 let hash = sha.ComputeHash nameAsBytes
37 cryptoStream.Write (nameAsBytes, 0, nameAsBytes.Length)
38 cryptoStream.FlushFinalBlock ()
41 let result = Array.zeroCreate
(iv.Length + hash.Length + int stream.Length)
43 Array.blit
iv 0 result 0 iv.Length
44 Array.blit
hash 0 result iv.Length hash.Length
46 stream.Read (result, iv.Length + hash.Length, int stream.Length) |> ignore
47 "1" + Convert.ToBase64String result |> WebUtility.UrlEncode
49 // TODO: return a Result<string, DecryptError>
50 let decrypt (key : Key) (cipher
: string) (urlDecode
: bool) : string =
51 let version = cipher
.Substring (0, 1) |> int
53 failwithf
"Version not supported: %i" version
55 let keyAsBytes = WebUtility.UrlDecode key |> Convert.FromBase64String
56 let bytes = cipher
.Substring 1 |> (if urlDecode
then WebUtility.UrlDecode else id
) |> Convert.FromBase64String
58 let iv = Array.zeroCreate
(keySize / 8)
59 Array.blit
bytes 0 iv 0 iv.Length
61 let hash = Array.zeroCreate
32
62 Array.blit
bytes iv.Length hash 0 hash.Length
64 use aes = new AesCryptoServiceProvider (KeySize = keySize)
65 use stream = new MemoryStream (bytes, iv.Length + hash.Length, bytes.Length - iv.Length - hash.Length)
66 use cryptoStream = new CryptoStream (stream, aes.CreateDecryptor (keyAsBytes, iv), CryptoStreamMode.Read)
67 use streamResult = new MemoryStream ()
68 cryptoStream.CopyTo streamResult
69 streamResult.Position <- 0L
70 let result = Array.zeroCreate
(int streamResult.Length)
71 streamResult.Read (result, 0, result.Length) |> ignore
73 use sha = SHA256.Create ()
74 let computedHash = sha.ComputeHash result
76 if hash <> computedHash then
77 failwith
"hash mismatch"
79 Encoding.UTF8.GetString result