1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
module String = Core.String module AES = Nocrypto.Cipher_block.AES.CBC let __kdf key = let aes_salt = Entropy.min_bits (32 * 8) in let mac_salt = Entropy.max_bits (32 * 8) in let aes_key = Hardening.kdf ~size:32l ~salt:aes_salt key in let mac_key = Hardening.kdf ~size:32l ~salt:mac_salt key in (aes_key, mac_key) let hash data = Cstruct.of_hex @@ Hashing.hash @@ Cstruct.to_string data let mac ~key data = let key', data' = (Cstruct.to_string key, Cstruct.to_string data) in Cstruct.of_hex @@ Hashing.mac ~key:key' data' let encrypt ~key ~iv ~metadata ~message:msg = let aes_key, mac_key = __kdf key in let aes_key' = AES.of_secret aes_key in let plaintext = Helpers.pad ~basis:16 @@ Cstruct.to_string msg in let ciphertext = AES.encrypt ~iv ~key:aes_key' @@ Cstruct.of_string plaintext in let secret = hash mac_key in let payload = Cstruct.concat [ metadata; iv; ciphertext ] in let tag = mac ~key:secret payload in (ciphertext, tag) let decrypt ~reason ~key ~iv ~metadata ~cipher ~tag = let aes_key, mac_key = __kdf key in let secret = hash mac_key in let payload = Cstruct.concat [ metadata; iv; cipher ] in let tag' = mac ~key:secret payload in if Cstruct.equal tag tag' then let aes_key' = AES.of_secret aes_key in let plaintext = AES.decrypt ~iv ~key:aes_key' cipher in Cstruct.of_string @@ Helpers.unpad @@ Cstruct.to_string plaintext else raise reason