--- /dev/null
+module RUP.Crypto\r
+\r
+open System\r
+open System.Net\r
+open System.IO\r
+open System.Security.Cryptography\r
+open System.Text\r
+open System.Web\r
+\r
+let keySize = 128 // [bit].\r
+\r
+type Key = string\r
+\r
+let randBytes (nb : int) : byte array =\r
+ let result = Array.zeroCreate nb\r
+ use generator = new RNGCryptoServiceProvider ()\r
+ generator.GetBytes result\r
+ result\r
+\r
+let generateKey () : Key =\r
+ let bytes = randBytes (keySize / 8)\r
+ Convert.ToBase64String bytes |> WebUtility.UrlEncode\r
+\r
+let encrypt (key : Key) (name : string) : string =\r
+ let keyAsBytes = WebUtility.UrlDecode key |> Convert.FromBase64String\r
+ let iv = randBytes (keySize / 8)\r
+\r
+ use aes = new AesCryptoServiceProvider (KeySize = keySize) // Default mode is CBC.\r
+ use stream = new MemoryStream ()\r
+ use cryptoStream = new CryptoStream (stream, aes.CreateEncryptor (keyAsBytes, iv), CryptoStreamMode.Write)\r
+ let nameAsBytes = Encoding.UTF8.GetBytes name\r
+\r
+ use sha = SHA256.Create ()\r
+ let hash = sha.ComputeHash nameAsBytes\r
+\r
+ cryptoStream.Write (nameAsBytes, 0, nameAsBytes.Length)\r
+ cryptoStream.FlushFinalBlock ()\r
+ stream.Position <- 0L\r
+\r
+ let result = Array.zeroCreate (iv.Length + hash.Length + int stream.Length)\r
+\r
+ Array.blit iv 0 result 0 iv.Length\r
+ Array.blit hash 0 result iv.Length hash.Length\r
+\r
+ stream.Read (result, iv.Length + hash.Length, int stream.Length) |> ignore\r
+ "1" + Convert.ToBase64String result |> WebUtility.UrlEncode\r
+\r
+let decrypt (key : Key) (cipher : string) (urlDecode : bool) : string =\r
+ let version = cipher.Substring (0, 1) |> int\r
+ if version <> 1 then\r
+ failwithf "Version not supported: %i" version\r
+\r
+ let keyAsBytes = WebUtility.UrlDecode key |> Convert.FromBase64String\r
+ let bytes = cipher.Substring 1 |> (if urlDecode then WebUtility.UrlDecode else id) |> Convert.FromBase64String\r
+\r
+ let iv = Array.zeroCreate (keySize / 8)\r
+ Array.blit bytes 0 iv 0 iv.Length\r
+\r
+ let hash = Array.zeroCreate 32\r
+ Array.blit bytes iv.Length hash 0 hash.Length\r
+\r
+ use aes = new AesCryptoServiceProvider (KeySize = keySize)\r
+ use stream = new MemoryStream (bytes, iv.Length + hash.Length, bytes.Length - iv.Length - hash.Length)\r
+ use cryptoStream = new CryptoStream (stream, aes.CreateDecryptor (keyAsBytes, iv), CryptoStreamMode.Read)\r
+ use streamResult = new MemoryStream ()\r
+ cryptoStream.CopyTo streamResult\r
+ streamResult.Position <- 0L\r
+ let result = Array.zeroCreate (int streamResult.Length)\r
+ streamResult.Read (result, 0, result.Length) |> ignore\r
+\r
+ use sha = SHA256.Create ()\r
+ let computedHash = sha.ComputeHash result\r
+\r
+ if hash <> computedHash then\r
+ failwith "hash mismatch"\r
+\r
+ Encoding.UTF8.GetString result
\ No newline at end of file