diff --git a/.merlin b/.merlin index be75143..f25bfb0 100644 --- a/.merlin +++ b/.merlin @@ -5,3 +5,4 @@ PKG bytes PKG ctypes.stubs PKG ocamlbuild PKG oUnit +PKG memcpy \ No newline at end of file diff --git a/lib/META b/lib/META index bd3f414..d03b7c7 100644 --- a/lib/META +++ b/lib/META @@ -1,6 +1,6 @@ version = "0.5.0" description = "Binding to libsodium, a shared library wrapper for djb's NaCl" -requires = "bigarray bytes ctypes.stubs" +requires = "bigarray bytes ctypes.stubs memcpy" archive(byte) = "sodium.cma" archive(native) = "sodium.cmxa" exists_if = "sodium.cma" diff --git a/lib/_tags b/lib/_tags index 8ddabef..a7abbcd 100644 --- a/lib/_tags +++ b/lib/_tags @@ -1,4 +1,4 @@ -<*.{ml,mli}>: package(bytes), package(bigarray), package(ctypes.stubs) +<*.{ml,mli}>: package(bytes), package(bigarray), package(ctypes.stubs), package(memcpy) <*.{cma,cmxa}>: use_sodium_stubs : use_sodium <*.c>: use_ctypes, use_sodium diff --git a/lib/sodium.ml b/lib/sodium.ml index 6b3a03e..e2e557b 100644 --- a/lib/sodium.ml +++ b/lib/sodium.ml @@ -34,10 +34,78 @@ type bigbytes = Storage.bigbytes module C = Sodium_bindings.C(Sodium_generated) module Type = Sodium_types.C(Sodium_types_detected) module Sodium_bytes = C.Make(Storage.Bytes) +module Sodium_bigbytes = C.Make(Storage.Bigbytes) -let wipe str = - Sodium_bytes.memzero - (Storage.Bytes.to_ptr str) (Storage.Bytes.len_size_t str) +module type MEMPROTECT = sig + type storage + + val wipe : storage -> unit + val protect : storage -> unit + + val protected_copy_of_bigbytes : bigbytes -> storage + val protected_copy_to_bigbytes : storage -> bigbytes +end + +module Memprotect_bigbytes = struct + type storage = bigbytes + + let wipe str = + Sodium_bigbytes.memzero + (Storage.Bigbytes.to_ptr str) (Storage.Bigbytes.len_size_t str) + + let protect str = + let ret = + C.mlock + (Storage.Bigbytes.to_ptr str) + (Storage.Bigbytes.len_size_t str) in + assert (ret = 0); (* always returns 0 *) + Gc.finalise (fun str -> + let ret = + C.munlock + (Storage.Bigbytes.to_ptr str) + (Storage.Bigbytes.len_size_t str) in + assert (ret = 0) (* always returns 0 *)) + str + + let protected_copy_to_bigbytes str = + let len = Storage.Bigbytes.length str in + let res = Storage.Bigbytes.create len in + protect res ; + Storage.Bigbytes.blit_bigbytes str 0 res 0 len ; + res + + let protected_copy_of_bigbytes = + protected_copy_to_bigbytes + +end + +let protect_bigbytes = Memprotect_bigbytes.protect +let wipe_bigbytes = Memprotect_bigbytes.wipe + +module Memprotect_bytes = struct + type storage = Bytes.t + + let wipe str = + Sodium_bytes.memzero + (Storage.Bytes.to_ptr str) (Storage.Bytes.len_size_t str) + + let protect str = + Gc.finalise wipe str + + let protected_copy_to_bigbytes str = + let len = Bytes.length str in + let res = Storage.Bigbytes.create len in + Memprotect_bigbytes.protect res ; + Storage.Bytes.blit_to_bigbytes str 0 res 0 len ; + res + + let protected_copy_of_bigbytes str = + let len = Storage.Bigbytes.length str in + let res = Bytes.create len in + Storage.Bytes.blit_bigbytes str 0 res 0 len ; + res + +end let memcpy ~dest ~src typ = let size = sizeof typ in @@ -59,15 +127,28 @@ let increment_be_bytes ?(step=1) b = module Verify = struct module C = C.Verify - let equal_fn size = - match size with - | 16 -> fun a b -> (C.verify_16 (Storage.Bytes.to_ptr a) - (Storage.Bytes.to_ptr b)) = 0 - | 32 -> fun a b -> (C.verify_32 (Storage.Bytes.to_ptr a) - (Storage.Bytes.to_ptr b)) = 0 - | 64 -> fun a b -> (C.verify_64 (Storage.Bytes.to_ptr a) - (Storage.Bytes.to_ptr b)) = 0 - | _ -> assert false + module type S = sig + type storage + val equal_fn : int -> storage -> storage + end + + module Make(T: Storage.S) = struct + module C = C.Make(T) + type storage = T.t + + let equal_fn size = + match size with + | 16 -> fun a b -> (C.verify_16 (T.to_ptr a) + (T.to_ptr b)) = 0 + | 32 -> fun a b -> (C.verify_32 (T.to_ptr a) + (T.to_ptr b)) = 0 + | 64 -> fun a b -> (C.verify_64 (T.to_ptr a) + (T.to_ptr b)) = 0 + | _ -> assert false + end + + module Bytes = Make(Storage.Bytes) + module Bigbytes = Make(Storage.Bigbytes) end module Random = struct @@ -98,6 +179,26 @@ module Random = struct module Bigbytes = Make(Storage.Bigbytes) end +module Padding(T: Storage.S)(M: MEMPROTECT with type storage = T.t) : sig + val padded_exec : T.t -> int -> int -> (bigbytes -> bigbytes -> unit) -> T.t +end = struct + let padded_exec a apad bpad f = + let len = apad + T.length a in + let a' = Storage.Bigbytes.create len in + let b' = Storage.Bigbytes.create len in + Memprotect_bigbytes.protect a' ; + Memprotect_bigbytes.protect b' ; + let res = T.create (len - bpad) in + M.protect res ; + Storage.Bigbytes.zero a' 0 apad; + T.blit_to_bigbytes a 0 a' apad (T.length a); + f a' b'; + Memprotect_bigbytes.wipe a' ; + T.blit_bigbytes b' bpad res 0 (len - bpad) ; + Memprotect_bigbytes.wipe b' ; + res +end + module Box = struct module C = C.Box let primitive = C.primitive @@ -110,7 +211,10 @@ module Box = struct let box_zero_size = Size_t.to_int (C.boxzerobytes ()) (* Invariant: a key is {public,secret,channel}_key_size bytes long. *) - type 'a key = Bytes.t + type 'a key = + | Pk : Bytes.t -> public key + | Sk : bigbytes -> secret key + | Ck : bigbytes -> channel key type secret_key = secret key type public_key = public key type channel_key = channel key @@ -121,21 +225,31 @@ module Box = struct let random_keypair () = let pk, sk = Storage.Bytes.create public_key_size, - Storage.Bytes.create secret_key_size in + Storage.Bigbytes.create secret_key_size in + Memprotect_bigbytes.protect sk ; let ret = - C.box_keypair (Storage.Bytes.to_ptr pk) (Storage.Bytes.to_ptr sk) in + C.box_keypair (Storage.Bytes.to_ptr pk) (Storage.Bigbytes.to_ptr sk) in assert (ret = 0); (* always returns 0 *) - sk, pk + Sk sk, Pk pk let random_nonce () = Random.Bytes.generate nonce_size - let wipe_key = wipe - - let equal_public_keys = Verify.equal_fn public_key_size - let equal_secret_keys = Verify.equal_fn secret_key_size - let equal_channel_keys = Verify.equal_fn channel_key_size - let compare_public_keys = Bytes.compare + let wipe_key + : type t. t key -> unit + = function + | Sk sk -> Memprotect_bigbytes.wipe sk + | Ck ck -> Memprotect_bigbytes.wipe ck + | Pk pk -> Memprotect_bytes.wipe pk + + let equal_public_keys (Pk pka) (Pk pkb) = + Verify.Bytes.equal_fn public_key_size pka pkb + let equal_secret_keys (Sk ska) (Sk skb) = + Verify.Bigbytes.equal_fn secret_key_size ska skb + let equal_channel_keys (Ck cka) (Ck ckb) = + Verify.Bigbytes.equal_fn channel_key_size cka ckb + let compare_public_keys (Pk pka) (Pk pkb) = + Bytes.compare pka pkb let nonce_of_bytes b = if Bytes.length b <> nonce_size then @@ -144,13 +258,14 @@ module Box = struct let increment_nonce = increment_be_bytes - let precompute skey pkey = - let params = Storage.Bytes.create channel_key_size in - let ret = C.box_beforenm (Storage.Bytes.to_ptr params) + let precompute (Sk skey) (Pk pkey) = + let params = Storage.Bigbytes.create channel_key_size in + Memprotect_bigbytes.protect params ; + let ret = C.box_beforenm (Storage.Bigbytes.to_ptr params) (Storage.Bytes.to_ptr pkey) - (Storage.Bytes.to_ptr skey) in + (Storage.Bigbytes.to_ptr skey) in assert (ret = 0); (* always returns 0 *) - params + Ck params module type S = sig type storage @@ -174,33 +289,33 @@ module Box = struct val fast_box_open : channel key -> storage -> nonce -> storage end - module Make(T: Storage.S) = struct - module C = C.Make(T) + module Make(T: Storage.S)(M: MEMPROTECT with type storage = T.t) = struct + module C = C.Make(Storage.Bigbytes) type storage = T.t let verify_length str len fn_name = if T.length str <> len then raise (Size_mismatch fn_name) - let of_public_key key = + let of_public_key (Pk key) = T.of_bytes key let to_public_key str = verify_length str public_key_size "Box.to_public_key"; - T.to_bytes str + Pk (T.to_bytes str) - let of_secret_key key = - T.of_bytes key + let of_secret_key (Sk key) = + M.protected_copy_of_bigbytes key let to_secret_key str = verify_length str secret_key_size "Box.to_secret_key"; - T.to_bytes str + Sk (M.protected_copy_to_bigbytes str) - let of_channel_key key = - T.of_bytes key + let of_channel_key (Ck key) = + M.protected_copy_of_bigbytes key let to_channel_key str = verify_length str channel_key_size "Box.to_channel_key"; - T.to_bytes str + Ck (M.protected_copy_to_bigbytes str) let of_nonce nonce = T.of_bytes nonce @@ -209,51 +324,51 @@ module Box = struct verify_length str nonce_size "Box.to_nonce"; T.to_bytes str - let pad a apad bpad f = - let a' = T.create (apad + T.length a) in - let b' = T.create (T.length a') in - T.zero a' 0 apad; - T.blit a 0 a' apad (T.length a); - f a' b'; - T.sub b' bpad ((T.length b') - bpad) + let pad = + let module P = Padding(T)(M) in + P.padded_exec - let box skey pkey message nonce = + let box (Sk skey) (Pk pkey) message nonce = pad message zero_size box_zero_size (fun cleartext ciphertext -> - let ret = C.box (T.to_ptr ciphertext) (T.to_ptr cleartext) - (T.len_ullong cleartext) + let ret = C.box (Storage.Bigbytes.to_ptr ciphertext) + (Storage.Bigbytes.to_ptr cleartext) + (Storage.Bigbytes.len_ullong cleartext) (Storage.Bytes.to_ptr nonce) (Storage.Bytes.to_ptr pkey) - (Storage.Bytes.to_ptr skey) in + (Storage.Bigbytes.to_ptr skey) in assert (ret = 0) (* always returns 0 *)) - let box_open skey pkey ciphertext nonce = + let box_open (Sk skey) (Pk pkey) ciphertext nonce = pad ciphertext box_zero_size zero_size (fun ciphertext cleartext -> - let ret = C.box_open (T.to_ptr cleartext) (T.to_ptr ciphertext) - (T.len_ullong ciphertext) + let ret = C.box_open (Storage.Bigbytes.to_ptr cleartext) + (Storage.Bigbytes.to_ptr ciphertext) + (Storage.Bigbytes.len_ullong ciphertext) (Storage.Bytes.to_ptr nonce) (Storage.Bytes.to_ptr pkey) - (Storage.Bytes.to_ptr skey) in + (Storage.Bigbytes.to_ptr skey) in if ret <> 0 then raise Verification_failure) - let fast_box params message nonce = + let fast_box (Ck params) message nonce = pad message zero_size box_zero_size (fun cleartext ciphertext -> - let ret = C.box_afternm (T.to_ptr ciphertext) (T.to_ptr cleartext) - (T.len_ullong cleartext) + let ret = C.box_afternm (Storage.Bigbytes.to_ptr ciphertext) + (Storage.Bigbytes.to_ptr cleartext) + (Storage.Bigbytes.len_ullong cleartext) (Storage.Bytes.to_ptr nonce) - (Storage.Bytes.to_ptr params) in + (Storage.Bigbytes.to_ptr params) in assert (ret = 0) (* always returns 0 *)) - let fast_box_open params ciphertext nonce = + let fast_box_open (Ck params) ciphertext nonce = pad ciphertext box_zero_size zero_size (fun ciphertext cleartext -> - let ret = C.box_open_afternm (T.to_ptr cleartext) (T.to_ptr ciphertext) - (T.len_ullong ciphertext) + let ret = C.box_open_afternm (Storage.Bigbytes.to_ptr cleartext) + (Storage.Bigbytes.to_ptr ciphertext) + (Storage.Bigbytes.len_ullong ciphertext) (Storage.Bytes.to_ptr nonce) - (Storage.Bytes.to_ptr params) in + (Storage.Bigbytes.to_ptr params) in if ret <> 0 then raise Verification_failure) end - module Bytes = Make(Storage.Bytes) - module Bigbytes = Make(Storage.Bigbytes) + module Bytes = Make(Storage.Bytes)(Memprotect_bytes) + module Bigbytes = Make(Storage.Bigbytes)(Memprotect_bigbytes) end module Sign = struct @@ -267,7 +382,9 @@ module Sign = struct let seed_size = Size_t.to_int (C.seedbytes ()) (* Invariant: a key is {public,secret}_key_size bytes long. *) - type 'a key = Bytes.t + type 'a key = + | Pk : Bytes.t -> public key + | Sk : bigbytes -> secret key type secret_key = secret key type public_key = public key type keypair = secret key * public key @@ -276,58 +393,69 @@ module Sign = struct type signature = Bytes.t (* Invariant: a seed is seed_size bytes long. *) - type seed = Bytes.t + type seed = bigbytes let random_keypair () = let pk, sk = Storage.Bytes.create public_key_size, - Storage.Bytes.create secret_key_size in + Storage.Bigbytes.create secret_key_size in + Memprotect_bigbytes.protect sk; let ret = - C.sign_keypair (Storage.Bytes.to_ptr pk) (Storage.Bytes.to_ptr sk) in + C.sign_keypair (Storage.Bytes.to_ptr pk) (Storage.Bigbytes.to_ptr sk) in assert (ret = 0); (* always returns 0 *) - sk, pk + Sk sk, Pk pk let seed_keypair seed = let pk, sk = Storage.Bytes.create public_key_size, - Storage.Bytes.create secret_key_size in + Storage.Bigbytes.create secret_key_size in + Memprotect_bigbytes.protect sk; let ret = - C.sign_seed_keypair (Storage.Bytes.to_ptr pk) (Storage.Bytes.to_ptr sk) - (Storage.Bytes.to_ptr seed) in + C.sign_seed_keypair (Storage.Bytes.to_ptr pk) (Storage.Bigbytes.to_ptr sk) + (Storage.Bigbytes.to_ptr seed) in assert (ret = 0); - sk, pk + Sk sk, Pk pk - let secret_key_to_seed sk = - let seed = Storage.Bytes.create seed_size in + let secret_key_to_seed (Sk sk) = + let seed = Storage.Bigbytes.create seed_size in + Memprotect_bigbytes.protect seed; let ret = - C.sign_sk_to_seed (Storage.Bytes.to_ptr seed) (Storage.Bytes.to_ptr sk) in + C.sign_sk_to_seed (Storage.Bigbytes.to_ptr seed) (Storage.Bigbytes.to_ptr sk) in assert (ret = 0); seed - let secret_key_to_public_key sk = + let secret_key_to_public_key (Sk sk) = let pk = Storage.Bytes.create public_key_size in let ret = - C.sign_sk_to_pk (Storage.Bytes.to_ptr pk) (Storage.Bytes.to_ptr sk) in + C.sign_sk_to_pk (Storage.Bytes.to_ptr pk) (Storage.Bigbytes.to_ptr sk) in assert (ret = 0); - pk - - let wipe_key = wipe - - let equal_public_keys = Verify.equal_fn public_key_size - let equal_secret_keys = Verify.equal_fn secret_key_size - let compare_public_keys = Bytes.compare - - let box_public_key pk = + Pk pk + + let wipe_key + : type t. t key -> unit + = function + | Sk sk -> Memprotect_bigbytes.wipe sk + | Pk pk -> Memprotect_bytes.wipe pk + + let equal_public_keys (Pk pka) (Pk pkb) = + Verify.Bytes.equal_fn public_key_size pka pkb + let equal_secret_keys (Sk ska) (Sk skb) = + Verify.Bigbytes.equal_fn secret_key_size ska skb + let compare_public_keys (Pk pka) (Pk pkb) = + Bytes.compare pka pkb + + let box_public_key (Pk pk) = let pk' = Bytes.create Box.public_key_size in let ret = C.sign_pk_to_curve25519 (Storage.Bytes.to_ptr pk') (Storage.Bytes.to_ptr pk) in assert (ret = 0); - pk' + Box.Pk pk' - let box_secret_key sk = - let sk' = Bytes.create Box.secret_key_size in + let box_secret_key (Sk sk) = + let sk' = Storage.Bigbytes.create Box.secret_key_size in + Memprotect_bigbytes.protect sk' ; let ret = C.sign_sk_to_curve25519 - (Storage.Bytes.to_ptr sk') (Storage.Bytes.to_ptr sk) in + (Storage.Bigbytes.to_ptr sk') (Storage.Bigbytes.to_ptr sk) in assert (ret = 0); - sk' + Box.Sk sk' let box_keypair (sk, pk) = (box_secret_key sk, box_public_key pk) @@ -353,26 +481,26 @@ module Sign = struct val verify : public key -> signature -> storage -> unit end - module Make(T: Storage.S) = struct + module Make(T: Storage.S)(M: MEMPROTECT with type storage = T.t) = struct module C = C.Make(T) type storage = T.t let verify_length str len fn_name = if T.length str <> len then raise (Size_mismatch fn_name) - let of_public_key key = + let of_public_key (Pk key) = T.of_bytes key let to_public_key str = verify_length str public_key_size "Sign.to_public_key"; - T.to_bytes str + Pk (T.to_bytes str) - let of_secret_key key = - T.of_bytes key + let of_secret_key (Sk key) = + M.protected_copy_of_bigbytes key let to_secret_key str = verify_length str secret_key_size "Sign.to_secret_key"; - T.to_bytes str + Sk (M.protected_copy_to_bigbytes str) let of_signature sign = T.of_bytes sign @@ -382,22 +510,22 @@ module Sign = struct T.to_bytes str let of_seed seed = - T.of_bytes seed + M.protected_copy_of_bigbytes seed let to_seed str = verify_length str seed_size "Sign.to_seed"; - T.to_bytes str + M.protected_copy_to_bigbytes str - let sign skey message = + let sign (Sk skey) message = let signed_msg = T.create ((T.length message) + reserved_size) in let signed_len = allocate ullong (Unsigned.ULLong.of_int 0) in let ret = C.sign (T.to_ptr signed_msg) signed_len (T.to_ptr message) (T.len_ullong message) - (Storage.Bytes.to_ptr skey) in + (Storage.Bigbytes.to_ptr skey) in assert (ret = 0); (* always returns 0 *) T.sub signed_msg 0 (Unsigned.ULLong.to_int (!@ signed_len)) - let sign_open pkey signed_msg = + let sign_open (Pk pkey) signed_msg = let message = T.create (T.length signed_msg) in let msg_len = allocate ullong (Unsigned.ULLong.of_int 0) in let ret = C.sign_open (T.to_ptr message) msg_len @@ -406,22 +534,22 @@ module Sign = struct if ret <> 0 then raise Verification_failure; T.sub message 0 (Unsigned.ULLong.to_int (!@ msg_len)) - let sign_detached skey message = + let sign_detached (Sk skey) message = let signature = T.create signature_size in let ret = C.sign_detached (T.to_ptr signature) None (T.to_ptr message) (T.len_ullong message) - (Storage.Bytes.to_ptr skey) in + (Storage.Bigbytes.to_ptr skey) in assert (ret = 0); (* always returns 0 *) T.to_bytes signature - let verify pkey (signature:signature) message = + let verify (Pk pkey) (signature:signature) message = let ret = C.sign_verify (Storage.Bytes.to_ptr signature) (T.to_ptr message) (T.len_ullong message) (Storage.Bytes.to_ptr pkey) in if ret <> 0 then raise Verification_failure end - module Bytes = Make(Storage.Bytes) - module Bigbytes = Make(Storage.Bigbytes) + module Bytes = Make(Storage.Bytes)(Memprotect_bytes) + module Bigbytes = Make(Storage.Bigbytes)(Memprotect_bigbytes) end module Scalar_mult = struct @@ -437,8 +565,8 @@ module Scalar_mult = struct (* Invariant: an integer is integer_size bytes long. *) type integer = Bytes.t - let equal_group_elt = Verify.equal_fn group_elt_size - let equal_integer = Verify.equal_fn integer_size + let equal_group_elt = Verify.Bytes.equal_fn group_elt_size + let equal_integer = Verify.Bytes.equal_fn integer_size let mult scalar elem = let elem' = Storage.Bytes.create group_elt_size in @@ -497,7 +625,7 @@ module Password_hash = struct (* Invariant: a salt is salt_size bytes long. *) type salt = Bytes.t - type password = Bytes.t + type password = bigbytes type difficulty = { mem_limit : int64; @@ -519,7 +647,7 @@ module Password_hash = struct let ops_limit = C.opslimit_sensitive () in { mem_limit; ops_limit; } - let wipe_password = wipe + let wipe_password = Memprotect_bigbytes.wipe let random_salt () = Random.Bytes.generate salt_size @@ -530,11 +658,12 @@ module Password_hash = struct b let derive_key key_size { ops_limit; mem_limit; } pw salt = - let key = Bytes.create key_size in + let key = Storage.Bigbytes.create key_size in + Memprotect_bigbytes.protect key ; let ret = C.derive - (Storage.Bytes.to_ptr key) (ULLong.of_int key_size) - (Storage.Bytes.to_ptr pw) (Storage.Bytes.len_ullong pw) + (Storage.Bigbytes.to_ptr key) (ULLong.of_int key_size) + (Storage.Bigbytes.to_ptr pw) (Storage.Bigbytes.len_ullong pw) (Storage.Bytes.to_ptr salt) (ULLong.of_int ops_limit) (Size_t.of_int64 mem_limit) (C.alg ()) in @@ -547,13 +676,14 @@ module Password_hash = struct val of_salt : salt -> storage val to_salt : storage -> salt - val wipe_to_password : storage -> password + val to_password : storage -> password + val of_password : password -> storage val hash_password : difficulty -> password -> storage val verify_password_hash : storage -> password -> bool end - module Make(T: Storage.S) = struct + module Make(T: Storage.S)(M: MEMPROTECT with type storage = T.t) = struct module C = C.Make(T) module Sodium = Sodium.Make(T) type storage = T.t @@ -566,17 +696,18 @@ module Password_hash = struct raise (Size_mismatch "Password_hash.to_salt"); T.to_bytes str - let wipe_to_password str = - let res = T.to_bytes str in - Sodium.memzero (T.to_ptr str) (T.len_size_t str); - res + let to_password str = + M.protected_copy_to_bigbytes str + + let of_password pw = + M.protected_copy_of_bigbytes pw let hash_password { ops_limit; mem_limit; } pw = let str = T.create password_hash_size in let ret = C.hash (T.to_ptr str) - (Storage.Bytes.to_ptr pw) (Storage.Bytes.len_ullong pw) + (Storage.Bigbytes.to_ptr pw) (Storage.Bigbytes.len_ullong pw) (ULLong.of_int ops_limit) (Size_t.of_int64 mem_limit) in assert (ret = 0); (* always returns 0 *) str @@ -585,13 +716,13 @@ module Password_hash = struct let ret = C.verify (T.to_ptr str) - (Storage.Bytes.to_ptr pw) (Storage.Bytes.len_ullong pw) in + (Storage.Bigbytes.to_ptr pw) (Storage.Bigbytes.len_ullong pw) in ret = 0 end - module Bytes = Make(Storage.Bytes) - module Bigbytes = Make(Storage.Bigbytes) + module Bytes = Make(Storage.Bytes)(Memprotect_bytes) + module Bigbytes = Make(Storage.Bigbytes)(Memprotect_bigbytes) end module Secret_box = struct @@ -604,14 +735,16 @@ module Secret_box = struct let box_zero_size = Size_t.to_int (C.boxzerobytes ()) (* Invariant: a key is key_size bytes long. *) - type 'a key = Bytes.t + type 'a key = bigbytes type secret_key = secret key (* Invariant: a nonce is nonce_size bytes long. *) type nonce = Bytes.t let random_key () = - Random.Bytes.generate key_size + let res = Random.Bigbytes.generate key_size in + Memprotect_bigbytes.protect res ; + res let derive_key = Password_hash.derive_key key_size @@ -631,9 +764,9 @@ module Secret_box = struct let increment_nonce = increment_be_bytes - let wipe_key = wipe + let wipe_key = Memprotect_bigbytes.wipe - let equal_keys = Verify.equal_fn key_size + let equal_keys = Verify.Bigbytes.equal_fn key_size module type S = sig type storage @@ -648,19 +781,19 @@ module Secret_box = struct val secret_box_open : secret key -> storage -> nonce -> storage end - module Make(T: Storage.S) = struct - module C = C.Make(T) + module Make(T: Storage.S)(M: MEMPROTECT with type storage = T.t) = struct + module C = C.Make(Storage.Bigbytes) type storage = T.t let verify_length str len fn_name = if T.length str <> len then raise (Size_mismatch fn_name) let of_key key = - T.of_bytes key + M.protected_copy_of_bigbytes key let to_key str = verify_length str key_size "Secret_box.to_key"; - T.to_bytes str + M.protected_copy_to_bigbytes str let of_nonce nonce = T.of_bytes nonce @@ -669,33 +802,31 @@ module Secret_box = struct verify_length str nonce_size "Secret_box.to_nonce"; T.to_bytes str - let pad a apad bpad f = - let a' = T.create (apad + T.length a) in - let b' = T.create (T.length a') in - T.zero a' 0 apad; - T.blit a 0 a' apad (T.length a); - f a' b'; - T.sub b' bpad ((T.length b') - bpad) + let pad = + let module P = Padding(T)(M) in + P.padded_exec let secret_box key message nonce = pad message zero_size box_zero_size (fun cleartext ciphertext -> - let ret = C.secretbox (T.to_ptr ciphertext) (T.to_ptr cleartext) - (T.len_ullong cleartext) + let ret = C.secretbox (Storage.Bigbytes.to_ptr ciphertext) + (Storage.Bigbytes.to_ptr cleartext) + (Storage.Bigbytes.len_ullong cleartext) (Storage.Bytes.to_ptr nonce) - (Storage.Bytes.to_ptr key) in + (Storage.Bigbytes.to_ptr key) in assert (ret = 0) (* always returns 0 *)) let secret_box_open key ciphertext nonce = pad ciphertext box_zero_size zero_size (fun ciphertext cleartext -> - let ret = C.secretbox_open (T.to_ptr cleartext) (T.to_ptr ciphertext) - (T.len_ullong ciphertext) + let ret = C.secretbox_open (Storage.Bigbytes.to_ptr cleartext) + (Storage.Bigbytes.to_ptr ciphertext) + (Storage.Bigbytes.len_ullong ciphertext) (Storage.Bytes.to_ptr nonce) - (Storage.Bytes.to_ptr key) in + (Storage.Bigbytes.to_ptr key) in if ret <> 0 then raise Verification_failure) end - module Bytes = Make(Storage.Bytes) - module Bigbytes = Make(Storage.Bigbytes) + module Bytes = Make(Storage.Bytes)(Memprotect_bytes) + module Bigbytes = Make(Storage.Bigbytes)(Memprotect_bigbytes) end module Stream = struct @@ -706,14 +837,16 @@ module Stream = struct let nonce_size = Size_t.to_int (C.noncebytes ()) (* Invariant: a key is key_size bytes long. *) - type 'a key = Bytes.t + type 'a key = bigbytes type secret_key = secret key (* Invariant: a nonce is nonce_size bytes long. *) type nonce = Bytes.t let random_key () = - Random.Bytes.generate key_size + let res = Random.Bigbytes.generate key_size in + Memprotect_bigbytes.protect res ; + res let derive_key = Password_hash.derive_key key_size @@ -733,9 +866,9 @@ module Stream = struct let increment_nonce = increment_be_bytes - let wipe_key = wipe + let wipe_key = Memprotect_bigbytes.wipe - let equal_keys = Verify.equal_fn key_size + let equal_keys = Verify.Bigbytes.equal_fn key_size module type S = sig type storage @@ -750,7 +883,7 @@ module Stream = struct val stream_xor : secret key -> storage -> nonce -> storage end - module Make(T: Storage.S) = struct + module Make(T: Storage.S)(M: MEMPROTECT with type storage = T.t) = struct module C = C.Make(T) type storage = T.t @@ -758,11 +891,11 @@ module Stream = struct if T.length str <> len then raise (Size_mismatch fn_name) let of_key key = - T.of_bytes key + M.protected_copy_of_bigbytes key let to_key str = verify_length str key_size "Stream.to_key"; - T.to_bytes str + M.protected_copy_to_bigbytes str let of_nonce nonce = T.of_bytes nonce @@ -775,7 +908,7 @@ module Stream = struct let stream = T.create len in let ret = C.stream (T.to_ptr stream) (T.len_ullong stream) (Storage.Bytes.to_ptr nonce) - (Storage.Bytes.to_ptr key) in + (Storage.Bigbytes.to_ptr key) in assert (ret = 0); (* always returns 0 *) stream @@ -784,13 +917,13 @@ module Stream = struct let ret = C.stream_xor (T.to_ptr ciphertext) (T.to_ptr message) (T.len_ullong message) (Storage.Bytes.to_ptr nonce) - (Storage.Bytes.to_ptr key) in + (Storage.Bigbytes.to_ptr key) in assert (ret = 0); (* always returns 0 *) ciphertext end - module Bytes = Make(Storage.Bytes) - module Bigbytes = Make(Storage.Bigbytes) + module Bytes = Make(Storage.Bytes)(Memprotect_bytes) + module Bigbytes = Make(Storage.Bigbytes)(Memprotect_bigbytes) end module Gen_auth(M: sig @@ -800,25 +933,28 @@ module Gen_auth(M: sig end) = struct module C = C.Gen_auth(M) let primitive = M.primitive + let name = M.name let key_size = Size_t.to_int (C.keybytes ()) let auth_size = Size_t.to_int (C.bytes ()) (* Invariant: a key is key_size bytes long. *) - type 'a key = Bytes.t + type 'a key = bigbytes type secret_key = secret key (* Invariant: an auth is auth_size bytes long. *) type auth = Bytes.t let random_key () = - Random.Bytes.generate key_size + let res = Random.Bigbytes.generate key_size in + Memprotect_bigbytes.protect res ; + res let derive_key = Password_hash.derive_key key_size - let wipe_key = wipe + let wipe_key = Memprotect_bigbytes.wipe - let equal_keys = Verify.equal_fn key_size + let equal_keys = Verify.Bigbytes.equal_fn key_size module type S = sig type storage @@ -833,7 +969,7 @@ end) = struct val verify : secret key -> auth -> storage -> unit end - module Make(T: Storage.S) = struct + module Make(T: Storage.S)(M: MEMPROTECT with type storage = T.t) = struct module C = C.Make(T) type storage = T.t @@ -841,18 +977,18 @@ end) = struct if T.length str <> len then raise (Size_mismatch fn_name) let of_key key = - T.of_bytes key + M.protected_copy_of_bigbytes key let to_key = - let fn_name = M.name^".to_key" in fun str -> + let fn_name = name^".to_key" in fun str -> verify_length str key_size fn_name; - T.to_bytes str + M.protected_copy_to_bigbytes str let of_auth auth = T.of_bytes auth let to_auth = - let fn_name = M.name^".to_auth" in fun str -> + let fn_name = name^".to_auth" in fun str -> verify_length str auth_size fn_name; T.to_bytes str @@ -860,19 +996,19 @@ end) = struct let auth = Storage.Bytes.create auth_size in let ret = C.auth (Storage.Bytes.to_ptr auth) (T.to_ptr message) (T.len_ullong message) - (Storage.Bytes.to_ptr key) in + (Storage.Bigbytes.to_ptr key) in assert (ret = 0); (* always returns 0 *) auth let verify key auth message = let ret = C.auth_verify (Storage.Bytes.to_ptr auth) (T.to_ptr message) (T.len_ullong message) - (Storage.Bytes.to_ptr key) in + (Storage.Bigbytes.to_ptr key) in if ret <> 0 then raise Verification_failure end - module Bytes = Make(Storage.Bytes) - module Bigbytes = Make(Storage.Bigbytes) + module Bytes = Make(Storage.Bytes)(Memprotect_bytes) + module Bigbytes = Make(Storage.Bigbytes)(Memprotect_bigbytes) end module Auth = Gen_auth(struct @@ -896,7 +1032,7 @@ module Hash = struct (* Invariant: a hash is size bytes long. *) type hash = Bytes.t - let equal = Verify.equal_fn size + let equal = Verify.Bytes.equal_fn size module type S = sig type storage @@ -935,10 +1071,10 @@ module Generichash = struct module C = C.Generichash let primitive = C.primitive - type 'a key = Bytes.t + type 'a key = bigbytes type secret_key = secret key - let wipe_key = wipe + let wipe_key = Memprotect_bigbytes.wipe let size_default = Size_t.to_int (C.hashbytes ()) let size_min = Size_t.to_int (C.hashbytesmin ()) @@ -950,10 +1086,12 @@ module Generichash = struct let key_size_default = Size_t.to_int (C.keybytes ()) let key_size_min = Size_t.to_int (C.keybytesmin ()) let key_size_max = Size_t.to_int (C.keybytesmax ()) - let size_of_key k = Bytes.length k + let size_of_key k = Storage.Bigbytes.length k let random_key () = - Random.Bytes.generate key_size_default + let res = Random.Bigbytes.generate key_size_default in + Memprotect_bigbytes.protect res ; + res let derive_key key_size = if key_size < key_size_min || key_size > key_size_max then @@ -967,13 +1105,13 @@ module Generichash = struct mutable final : bool; } - let init ?(key=Bytes.of_string "") ?(size=size_default) () = + let init ?(key=Storage.Bigbytes.create 0) ?(size=size_default) () = if size < size_min || size > size_max then raise (Size_mismatch "Generichash.init"); let ptr = allocate_n Type.Generichash.state ~count:1 in let ret = C.init ptr - (Storage.Bytes.to_ptr key) + (Storage.Bigbytes.to_ptr key) (Size_t.of_int (size_of_key key)) (Size_t.of_int size) in @@ -1011,7 +1149,7 @@ module Generichash = struct val update : state -> storage -> unit end - module Make(T: Storage.S) = struct + module Make(T: Storage.S)(M: MEMPROTECT with type storage = T.t) = struct module C = C.Make(T) type storage = T.t @@ -1025,20 +1163,20 @@ module Generichash = struct T.to_bytes str let of_key str = - T.of_bytes str + M.protected_copy_of_bigbytes str let to_key str = let len = T.length str in if len < key_size_min || len > key_size_max then raise (Size_mismatch "Generichash.to_key"); - T.to_bytes str + M.protected_copy_to_bigbytes str let digest_internal size key str = let hash = Storage.Bytes.create size in let ret = C.hash (Storage.Bytes.to_ptr hash) (Size_t.of_int size) (T.to_ptr str) (T.len_ullong str) - (Storage.Bytes.to_ptr key) (Size_t.of_int (size_of_key key)) + (Storage.Bigbytes.to_ptr key) (Size_t.of_int (size_of_key key)) in assert (ret = 0); (* always returns 0 *) hash @@ -1055,7 +1193,7 @@ module Generichash = struct with ctypes yet without giving up zero-copy passing. See . *) - digest_internal size (Bytes.create 0) str + digest_internal size (Storage.Bigbytes.create 0) str let update state str = if state.final then raise (Already_finalized "Generichash.update") @@ -1065,8 +1203,8 @@ module Generichash = struct () end - module Bytes = Make(Storage.Bytes) - module Bigbytes = Make(Storage.Bigbytes) + module Bytes = Make(Storage.Bytes)(Memprotect_bytes) + module Bigbytes = Make(Storage.Bigbytes)(Memprotect_bigbytes) end let initialized = match C.init () with diff --git a/lib/sodium.mli b/lib/sodium.mli index 46a5e0c..60452fa 100644 --- a/lib/sodium.mli +++ b/lib/sodium.mli @@ -39,9 +39,41 @@ type secret a public key. Such a key must be treated as a secret key. *) type channel +(** Unlike with [Bytes.t], values of type [bigbytes] are allocated in + the C heap, and are never moved by the memory manager of OCaml + during the lifecycle of the program. This allows the functions + {!protect_bigbytes} and {!wipe_bigbytes} to work, preventing any + shadow copy of [bigbytes] by the memory manager, which may in the + worst case end up in the swap space of the hard disk. + + All entities that are or contain secrets througout the library are + systematically stored as [bigbytes] under the hood, and protected + and wiped when needed. + + For maximum security, we recommend that you use only [bigbytes] in + your own code for storing secrets, and that you use + {!protect_bigbytes} and {!wipe_bigbytes} so that secrets are wiped + from the memory as soon as possible. In the same vein, the library + sometimes provides two variants for functions for convenience, one + with [Bytes.t], the other with [bigbytes]. We recommend that you + never use the former in security critical contexts..*) type bigbytes = (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t +(** [protect_bigbytes bytes] protects a memory zone including the + contents of [bytes] from being swapped by the operating system. + The memory zone is automatically unprotected when the value is + freed by the garbage collector. At this point, it is also + automatically zeroed out, but it is highly recommended not to wait + for the automatic zeroing and to call {!wipe_bigbytes} as soon as + the secret becomes no more useful. Be also aware that this + automatic wiping is not performed when the program ends. *) +val protect_bigbytes : bigbytes -> unit + +(** [wipe_bigbytes bytes] zeroes out the contents of [bytes]. *) +val wipe_bigbytes : bigbytes -> unit + + module Random : sig val stir : unit -> unit @@ -429,9 +461,11 @@ module Password_hash : sig @raise Size_mismatch if [s] is not {!salt_size} bytes long *) val to_salt : storage -> salt - (** [wipe_to_password s] copies a password [s] from {!storage} and - wipes [s]. *) - val wipe_to_password : storage -> password + (** [to_password s] copies [s] as a {!password}. *) + val to_password : storage -> password + + (** [of_password pw] copies a {!password} [pw] as {!storage}. *) + val of_password : password -> storage (** [hash_password d pw] uses the key derivation algorithm to create a safely storable hash of the password of size diff --git a/lib/sodium_storage.ml b/lib/sodium_storage.ml index eaa6d1a..5813927 100644 --- a/lib/sodium_storage.ml +++ b/lib/sodium_storage.ml @@ -19,6 +19,10 @@ module type S = sig val to_ptr : t -> ctype val to_bytes : t -> Bytes.t val of_bytes : Bytes.t -> t + val blit_bytes : Bytes.t -> int -> t -> int -> int -> unit + val blit_bigbytes : bigbytes -> int -> t -> int -> int -> unit + val blit_to_bytes : t -> int -> Bytes.t -> int -> int -> unit + val blit_to_bigbytes : t -> int -> bigbytes -> int -> int -> unit end module Bigbytes = struct @@ -27,30 +31,52 @@ module Bigbytes = struct let ctype = ptr char - open Bigarray + module Array1 = Bigarray.Array1 - let create len = (Array1.create char c_layout len) + let create len = Array1.create Bigarray.char Bigarray.c_layout len let length str = Array1.dim str let len_size_t str = Unsigned.Size_t.of_int (Array1.dim str) let len_ullong str = Unsigned.ULLong.of_int (Array1.dim str) let to_ptr str = bigarray_start array1 str let zero str pos len = (Array1.fill (Array1.sub str pos len) '\x00') - let to_bytes str = - let str' = Bytes.create (Array1.dim str) in - Bytes.iteri (fun i _ -> Bytes.set str' i (Array1.unsafe_get str i)) str'; - str' - - let of_bytes str = - let str' = create (Bytes.length str) in - Bytes.iteri (Array1.unsafe_set str') str; - str' + let to_bytes src = + let len = length src in + let dst = Bytes.create len in + Memcpy.memcpy + (Memcpy.bigarray Ctypes.array1 len Bigarray.char) Memcpy.ocaml_bytes + ~src ~src_off: 0 ~dst ~dst_off: 0 ~len; + dst + + let of_bytes src = + let len = Bytes.length src in + let dst = create len in + Memcpy.memcpy + Memcpy.ocaml_bytes (Memcpy.bigarray Ctypes.array1 len Bigarray.char) + ~src ~src_off: 0 ~dst ~dst_off: 0 ~len; + dst let sub = Array1.sub - let blit src srcoff dst dstoff len = - Array1.blit (Array1.sub src srcoff len) - (Array1.sub dst dstoff len) + let blit src src_off dst dst_off len = + Array1.blit (Array1.sub src src_off len) + (Array1.sub dst dst_off len) + + let blit_bigbytes = blit + let blit_to_bigbytes = blit + + let blit_bytes src src_off dst dst_off len = + Memcpy.memcpy + Memcpy.ocaml_bytes + (Memcpy.bigarray Ctypes.array1 (length dst) Bigarray.char) + ~src ~src_off ~dst ~dst_off ~len + + let blit_to_bytes src src_off dst dst_off len = + Memcpy.memcpy + (Memcpy.bigarray Ctypes.array1 (length src) Bigarray.char) + Memcpy.ocaml_bytes + ~src ~src_off ~dst ~dst_off ~len + end module Bytes = struct @@ -70,4 +96,19 @@ module Bytes = struct let of_bytes byt = Bytes.copy byt let sub = Bytes.sub let blit = Bytes.blit + + let blit_bytes = blit + let blit_to_bytes = blit + + let blit_bigbytes src src_off dst dst_off len = + Memcpy.memcpy + (Memcpy.bigarray Ctypes.array1 (Bigbytes.length src) Bigarray.char) + Memcpy.ocaml_bytes + ~src ~src_off ~dst ~dst_off ~len + + let blit_to_bigbytes src src_off dst dst_off len = + Memcpy.memcpy + Memcpy.ocaml_bytes + (Memcpy.bigarray Ctypes.array1 (Bigbytes.length dst) Bigarray.char) + ~src ~src_off ~dst ~dst_off ~len end diff --git a/lib_gen/_tags b/lib_gen/_tags index 7a7e632..b93d698 100644 --- a/lib_gen/_tags +++ b/lib_gen/_tags @@ -1 +1 @@ -<*.{ml,byte,native}>: package(ctypes.stubs) +<*.{ml,byte,native}>: package(ctypes.stubs), package(memcpy) diff --git a/lib_gen/sodium_bindgen.ml b/lib_gen/sodium_bindgen.ml index c064091..72c5acf 100644 --- a/lib_gen/sodium_bindgen.ml +++ b/lib_gen/sodium_bindgen.ml @@ -16,6 +16,7 @@ module Bind(F: Cstubs.FOREIGN) = struct module Stream' = BindStorage(Stream.Make) module Hash' = BindStorage(Hash.Make) module Generichash' = BindStorage(Generichash.Make) + module Verify' = BindStorage(Verify.Make) module Auth = Gen_auth(struct let scope = "auth" diff --git a/lib_gen/sodium_bindings.ml b/lib_gen/sodium_bindings.ml index 43273b5..6788f59 100644 --- a/lib_gen/sodium_bindings.ml +++ b/lib_gen/sodium_bindings.ml @@ -26,16 +26,23 @@ module C(F: Cstubs.FOREIGN) = struct let init = F.(foreign (prefix^"_init") (void @-> returning int)) let memcmp = F.(foreign (prefix^"_memcmp") (ocaml_bytes @-> ocaml_bytes @-> size_t @-> returning int)) + let mlock = + F.(foreign (prefix^"_mlock") (ptr char @-> size_t @-> returning int)) + let munlock = + F.(foreign (prefix^"_munlock") (ptr char @-> size_t @-> returning int)) + module Make(T: Sodium_storage.S) = struct let memzero = F.(foreign (prefix^"_memzero") (T.ctype @-> size_t @-> returning void)) end module Verify = struct - let verify_type = F.(ocaml_bytes @-> ocaml_bytes @-> returning int) - let verify_16 = F.foreign "crypto_verify_16" verify_type - let verify_32 = F.foreign "crypto_verify_32" verify_type - let verify_64 = F.foreign "crypto_verify_64" verify_type + module Make(T: Sodium_storage.S) = struct + let verify_type = F.(T.ctype @-> T.ctype @-> returning int) + let verify_16 = F.foreign "crypto_verify_16" verify_type + let verify_32 = F.foreign "crypto_verify_32" verify_type + let verify_64 = F.foreign "crypto_verify_64" verify_type + end end module Random = struct @@ -59,22 +66,22 @@ module C(F: Cstubs.FOREIGN) = struct let boxzerobytes = F.foreign (prefix^"_boxzerobytes") sz_query_type let box_keypair = F.(foreign (prefix^"_keypair") - (ocaml_bytes @-> ocaml_bytes @-> returning int)) + (ocaml_bytes @-> ptr char @-> returning int)) let box_beforenm = F.(foreign (prefix^"_beforenm") - (ocaml_bytes @-> ocaml_bytes @-> ocaml_bytes + (ptr char @-> ocaml_bytes @-> ptr char @-> returning int)) module Make(T: Sodium_storage.S) = struct let box_fn_type = F.(T.ctype @-> T.ctype @-> ullong - @-> ocaml_bytes @-> ocaml_bytes @-> ocaml_bytes + @-> ocaml_bytes @-> ocaml_bytes @-> ptr char @-> returning int) let box = F.foreign (prefix) box_fn_type let box_open = F.foreign (prefix^"_open") box_fn_type let box_afternm_type = F.(T.ctype @-> T.ctype @-> ullong - @-> ocaml_bytes @-> ocaml_bytes @-> returning int) + @-> ocaml_bytes @-> ptr char @-> returning int) let box_afternm = F.foreign (prefix^"_afternm") box_afternm_type let box_open_afternm = F.foreign (prefix^"_open_afternm") box_afternm_type @@ -92,34 +99,37 @@ module C(F: Cstubs.FOREIGN) = struct let seedbytes = F.foreign (prefix^"_seedbytes") sz_query_type let sign_keypair = F.(foreign (prefix^"_keypair") - (ocaml_bytes @-> ocaml_bytes + (ocaml_bytes @-> ptr char @-> returning int)) let sign_seed_keypair = F.(foreign (prefix^"_seed_keypair") - (ocaml_bytes @-> ocaml_bytes @-> ocaml_bytes + (ocaml_bytes @-> ptr char @-> ptr char @-> returning int)) let sign_sk_to_seed = F.(foreign (prefix^"_sk_to_seed") - (ocaml_bytes @-> ocaml_bytes + (ptr char @-> ptr char @-> returning int)) let sign_sk_to_pk = F.(foreign (prefix^"_sk_to_pk") - (ocaml_bytes @-> ocaml_bytes + (ocaml_bytes @-> ptr char @-> returning int)) - let to_curve_25519_type = F.(ocaml_bytes @-> ocaml_bytes @-> returning int) let sign_pk_to_curve25519 = F.foreign (prefix^"_pk_to_curve25519") - to_curve_25519_type + F.(ocaml_bytes @-> ocaml_bytes @-> returning int) let sign_sk_to_curve25519 = F.foreign (prefix^"_sk_to_curve25519") - to_curve_25519_type + F.(ptr char @-> ptr char @-> returning int) module Make(T: Sodium_storage.S) = struct - let sign_fn_type = F.(T.ctype @-> ptr ullong @-> T.ctype - @-> ullong @-> ocaml_bytes @-> returning int) + let sign = + F.foreign (prefix) + F.(T.ctype @-> ptr ullong @-> T.ctype + @-> ullong @-> ptr char @-> returning int) - let sign = F.foreign (prefix) sign_fn_type - let sign_open = F.foreign (prefix^"_open") sign_fn_type + let sign_open = + F.foreign (prefix^"_open") + F.(T.ctype @-> ptr ullong @-> T.ctype + @-> ullong @-> ocaml_bytes @-> returning int) let sign_detached_type = F.(T.ctype @-> ptr_opt ullong @-> T.ctype - @-> ullong @-> ocaml_bytes @-> returning int) + @-> ullong @-> ptr char @-> returning int) let sign_detached = F.foreign (prefix^"_detached") sign_detached_type @@ -173,19 +183,19 @@ module C(F: Cstubs.FOREIGN) = struct let hash = F.foreign (prefix^"_str") F.(T.ctype @-> (* hash *) - ocaml_bytes @-> ullong @-> (* passwd, passwdlen *) + ptr char @-> ullong @-> (* passwd, passwdlen *) ullong @-> size_t @-> (* opslimit, memlimit *) returning int) let verify = F.foreign (prefix^"_str_verify") F.(T.ctype @-> (* hash *) - ocaml_bytes @-> ullong @-> (* passwd, passwdlen *) + ptr char @-> ullong @-> (* passwd, passwdlen *) returning int) end let derive = F.foreign prefix - F.(ocaml_bytes @-> ullong @-> (* out, outlen *) - ocaml_bytes @-> ullong @-> (* passwd, passwdlen *) + F.(ptr char @-> ullong @-> (* out, outlen *) + ptr char @-> ullong @-> (* passwd, passwdlen *) ocaml_bytes @-> (* salt *) ullong @-> size_t @-> (* opslimit, memlimit *) int @-> (* alg *) @@ -204,7 +214,7 @@ module C(F: Cstubs.FOREIGN) = struct module Make(T: Sodium_storage.S) = struct let secretbox_fn_ty = F.(T.ctype @-> T.ctype @-> ullong - @-> ocaml_bytes @-> ocaml_bytes @-> returning int) + @-> ocaml_bytes @-> ptr char @-> returning int) let secretbox = F.foreign (prefix) secretbox_fn_ty let secretbox_open = F.foreign (prefix^"_open") secretbox_fn_ty @@ -222,10 +232,10 @@ module C(F: Cstubs.FOREIGN) = struct module Make(T: Sodium_storage.S) = struct let stream = F.(foreign (prefix) (T.ctype @-> ullong @-> ocaml_bytes - @-> ocaml_bytes @-> returning int)) + @-> ptr char @-> returning int)) let stream_xor = F.(foreign (prefix^"_xor") (T.ctype @-> T.ctype @-> ullong - @-> ocaml_bytes @-> ocaml_bytes @-> returning int)) + @-> ocaml_bytes @-> ptr char @-> returning int)) end end @@ -242,7 +252,7 @@ module C(F: Cstubs.FOREIGN) = struct module Make(T: Sodium_storage.S) = struct let auth_fn_type = F.(ocaml_bytes @-> T.ctype @-> ullong - @-> ocaml_bytes @-> returning int) + @-> ptr char @-> returning int) let auth = F.foreign (prefix) auth_fn_type let auth_verify = F.foreign (prefix^"_verify") auth_fn_type @@ -278,7 +288,7 @@ module C(F: Cstubs.FOREIGN) = struct let init = F.(foreign (prefix^"_init") ( ptr Type.Generichash.state - @-> ocaml_bytes + @-> ptr char @-> size_t @-> size_t @-> returning int)) @@ -295,7 +305,7 @@ module C(F: Cstubs.FOREIGN) = struct @-> size_t (* size_t out_len *) @-> T.ctype (* uchar* in *) @-> ullong (* unsigned long long in_len *) - @-> ocaml_bytes (* uchar* key *) + @-> ptr char (* uchar* key *) @-> size_t (* size_t keylen *) @-> returning int)) diff --git a/lib_test/_tags b/lib_test/_tags index c9aee86..986bdf3 100644 --- a/lib_test/_tags +++ b/lib_test/_tags @@ -1 +1 @@ -<*.{ml,byte,native}>: debug, package(bigarray), package(bytes), package(ctypes.stubs), package(oUnit), use_sodium_stubs +<*.{ml,byte,native}>: debug, package(bigarray), package(bytes), package(ctypes.stubs), package(oUnit), use_sodium_stubs, package(memcpy) diff --git a/lib_test/test_password_hash.ml b/lib_test/test_password_hash.ml index 914f3ba..97ee52a 100644 --- a/lib_test/test_password_hash.ml +++ b/lib_test/test_password_hash.ml @@ -19,7 +19,7 @@ open OUnit2 open Sodium let password str = - Password_hash.Bytes.wipe_to_password (Bytes.of_string str) + Password_hash.Bytes.to_password (Bytes.of_string str) let test_derive_secret_box_keys ctxt = let pw = password "Correct Horse Battery Staple" in diff --git a/opam b/opam index aee3847..dc51e56 100644 --- a/opam +++ b/opam @@ -29,6 +29,7 @@ depends: [ "ocamlfind" {build} "ocamlbuild" {build} "ctypes" {>= "0.4.0"} + "memcpy" ] depexts: [ [ ["debian"] ["libsodium-dev"] ]