+++ /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
-// TODO: return a Result<string, EncryptError>\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
-// TODO: return a Result<string, DecryptError>\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