···11-21module type S = sig
32 val extract : ?salt:string -> string -> string
43 val expand : prk:string -> ?info:string -> int -> string
···6576module Make (H : Digestif.S) : S = struct
87 let extract ?salt ikm =
99- let key = match salt with
1010- | None -> String.make H.digest_size '\x00'
1111- | Some x -> x
88+ let key =
99+ match salt with None -> String.make H.digest_size '\x00' | Some x -> x
1210 in
1311 H.(to_raw_string (hmac_string ~key ikm))
14121513 let expand ~prk ?info len =
1616- let info = match info with
1717- | None -> ""
1818- | Some x -> x
1919- in
1414+ let info = match info with None -> "" | Some x -> x in
2015 let t n last =
2116 let nc = String.make 1 (Char.unsafe_chr n) in
2222- H.(to_raw_string (hmac_string ~key:prk (String.concat "" [last ; info ; nc])))
1717+ H.(
1818+ to_raw_string
1919+ (hmac_string ~key:prk (String.concat "" [ last; info; nc ])))
2320 in
2421 let n = succ (len / H.digest_size) in
2525- let rec compute acc count = match count, acc with
2222+ let rec compute acc count =
2323+ match (count, acc) with
2624 | c, xs when c > n -> String.concat "" (List.rev xs)
2727- | c, x::_ -> compute (t c x :: acc) (succ c)
2525+ | c, x :: _ -> compute (t c x :: acc) (succ c)
2826 | _, [] -> invalid_arg "can not happen"
2927 in
3030- let buf = compute [""] 1 in
2828+ let buf = compute [ "" ] 1 in
3129 String.sub buf 0 len
3230end
33313432let extract ~hash ?salt ikm =
3535- let module H = (val (Digestif.module_of_hash' hash)) in
3333+ let module H = (val Digestif.module_of_hash' hash) in
3634 let module HKDF = Make (H) in
3735 HKDF.extract ?salt ikm
38363937let expand ~hash ~prk ?info len =
4040- let module H = (val (Digestif.module_of_hash' hash)) in
3838+ let module H = (val Digestif.module_of_hash' hash) in
4139 let module HKDF = Make (H) in
4240 HKDF.expand ~prk ?info len
+9-9
hkdf/hkdf.mli
···11-21(** {{:https://tools.ietf.org/html/rfc5869}RFC 5869} specifies a HMAC-based
32 Extract-and-Expand Key Derivation Function (HKDF), which is abstracted over
43 a specific hash function. *)
5465module type S = sig
77-66+ val extract : ?salt:string -> string -> string
87 (** [extract salt ikm] is [prk], the pseudorandom key of hash length octets.
98 The [salt] is an optional non-secret random value, [ikm] the input key
109 material. *)
1111- val extract : ?salt:string -> string -> string
12101313- (** [expand prk info length] is [okm], the output keying material. Given the
1414- pseudorandom key of hash length (usually output of [!extract] step), and an
1515- optional context and application specific information [info], the [okm] is
1616- generated. *)
1711 val expand : prk:string -> ?info:string -> int -> string
1212+ (** [expand prk info length] is [okm], the output keying material. Given the
1313+ pseudorandom key of hash length (usually output of [!extract] step), and
1414+ an optional context and application specific information [info], the [okm]
1515+ is generated. *)
1816end
19172018(** Given a Hash function, get the HKDF *)
2119module Make (H : Digestif.S) : S
22202323-(** convenience [extract hash salt ikm] where the [hash] has to be provided explicitly *)
2421val extract : hash:Digestif.hash' -> ?salt:string -> string -> string
2222+(** convenience [extract hash salt ikm] where the [hash] has to be provided
2323+ explicitly *)
25242626-(** convenience [expand hash prk info len] where the [hash] has to be provided explicitly *)
2725val expand : hash:Digestif.hash' -> prk:string -> ?info:string -> int -> string
2626+(** convenience [expand hash prk info len] where the [hash] has to be provided
2727+ explicitly *)
···11-21let test ~hash ~ikm ?salt ?info ~l ~prk ~okm () =
32 let ikm = Ohex.decode ikm
43 and salt = match salt with None -> None | Some x -> Some (Ohex.decode x)
54 and info = match info with None -> None | Some x -> Some (Ohex.decode x)
65 and prk = Ohex.decode prk
77- and okm = Ohex.decode okm
88- in
99- (fun () ->
1010- let cprk = Hkdf.extract ~hash ?salt ikm in
1111- Alcotest.check Alcotest.string "PRK matches" prk cprk ;
1212- let cokm = Hkdf.expand ~hash ~prk:cprk ?info l in
1313- Alcotest.check Alcotest.string "OKM matches" okm cokm)
66+ and okm = Ohex.decode okm in
77+ fun () ->
88+ let cprk = Hkdf.extract ~hash ?salt ikm in
99+ Alcotest.check Alcotest.string "PRK matches" prk cprk;
1010+ let cokm = Hkdf.expand ~hash ~prk:cprk ?info l in
1111+ Alcotest.check Alcotest.string "OKM matches" okm cokm
14121513let test1 =
1616- test
1717- ~hash:`SHA256
1818- ~ikm:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
1919- ~salt:"000102030405060708090a0b0c"
2020- ~info:"f0f1f2f3f4f5f6f7f8f9"
2121- ~l:42
2222- ~prk:"077709362c2e32df0ddc3f0dc47bba63 \
2323- 90b6c73bb50f9c3122ec844ad7c2b3e5"
2424- ~okm:"3cb25f25faacd57a90434f64d0362f2a \
2525- 2d2d0a90cf1a5a4c5db02d56ecc4c5bf \
2626- 34007208d5b887185865"
1414+ test ~hash:`SHA256 ~ikm:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
1515+ ~salt:"000102030405060708090a0b0c" ~info:"f0f1f2f3f4f5f6f7f8f9" ~l:42
1616+ ~prk:"077709362c2e32df0ddc3f0dc47bba63 90b6c73bb50f9c3122ec844ad7c2b3e5"
1717+ ~okm:
1818+ "3cb25f25faacd57a90434f64d0362f2a 2d2d0a90cf1a5a4c5db02d56ecc4c5bf \
1919+ 34007208d5b887185865"
2720 ()
28212922and test2 =
3030- test
3131- ~hash:`SHA256
3232- ~ikm:"000102030405060708090a0b0c0d0e0f \
3333- 101112131415161718191a1b1c1d1e1f \
3434- 202122232425262728292a2b2c2d2e2f \
3535- 303132333435363738393a3b3c3d3e3f \
3636- 404142434445464748494a4b4c4d4e4f"
3737- ~salt:"606162636465666768696a6b6c6d6e6f \
3838- 707172737475767778797a7b7c7d7e7f \
3939- 808182838485868788898a8b8c8d8e8f \
4040- 909192939495969798999a9b9c9d9e9f \
4141- a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
4242- ~info:"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf \
4343- c0c1c2c3c4c5c6c7c8c9cacbcccdcecf \
4444- d0d1d2d3d4d5d6d7d8d9dadbdcdddedf \
4545- e0e1e2e3e4e5e6e7e8e9eaebecedeeef \
4646- f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
2323+ test ~hash:`SHA256
2424+ ~ikm:
2525+ "000102030405060708090a0b0c0d0e0f 101112131415161718191a1b1c1d1e1f \
2626+ 202122232425262728292a2b2c2d2e2f 303132333435363738393a3b3c3d3e3f \
2727+ 404142434445464748494a4b4c4d4e4f"
2828+ ~salt:
2929+ "606162636465666768696a6b6c6d6e6f 707172737475767778797a7b7c7d7e7f \
3030+ 808182838485868788898a8b8c8d8e8f 909192939495969798999a9b9c9d9e9f \
3131+ a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
3232+ ~info:
3333+ "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf c0c1c2c3c4c5c6c7c8c9cacbcccdcecf \
3434+ d0d1d2d3d4d5d6d7d8d9dadbdcdddedf e0e1e2e3e4e5e6e7e8e9eaebecedeeef \
3535+ f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
4736 ~l:82
4848- ~prk:"06a6b88c5853361a06104c9ceb35b45c \
4949- ef760014904671014a193f40c15fc244"
5050- ~okm:"b11e398dc80327a1c8e7f78c596a4934 \
5151- 4f012eda2d4efad8a050cc4c19afa97c \
5252- 59045a99cac7827271cb41c65e590e09 \
5353- da3275600c2f09b8367793a9aca3db71 \
5454- cc30c58179ec3e87c14c01d5c1f3434f \
5555- 1d87"
3737+ ~prk:"06a6b88c5853361a06104c9ceb35b45c ef760014904671014a193f40c15fc244"
3838+ ~okm:
3939+ "b11e398dc80327a1c8e7f78c596a4934 4f012eda2d4efad8a050cc4c19afa97c \
4040+ 59045a99cac7827271cb41c65e590e09 da3275600c2f09b8367793a9aca3db71 \
4141+ cc30c58179ec3e87c14c01d5c1f3434f 1d87"
5642 ()
57435844and test3 =
5959- test
6060- ~hash:`SHA256
6161- ~ikm:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
6262- ~salt:""
6363- (* info = (0 octets) *)
6464- ~l:42
6565- ~prk:"19ef24a32c717b167f33a91d6f648bdf \
6666- 96596776afdb6377ac434c1c293ccb04"
6767- ~okm:"8da4e775a563c18f715f802a063c5a31 \
6868- b8a11f5c5ee1879ec3454e5f3c738d2d \
6969- 9d201395faa4b61a96c8"
4545+ test ~hash:`SHA256 ~ikm:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
4646+ ~salt:"" (* info = (0 octets) *) ~l:42
4747+ ~prk:"19ef24a32c717b167f33a91d6f648bdf 96596776afdb6377ac434c1c293ccb04"
4848+ ~okm:
4949+ "8da4e775a563c18f715f802a063c5a31 b8a11f5c5ee1879ec3454e5f3c738d2d \
5050+ 9d201395faa4b61a96c8"
7051 ()
71527253and test4 =
7373- test
7474- ~hash:`SHA1
7575- ~ikm:"0b0b0b0b0b0b0b0b0b0b0b"
7676- ~salt:"000102030405060708090a0b0c"
7777- ~info:"f0f1f2f3f4f5f6f7f8f9"
7878- ~l:42
5454+ test ~hash:`SHA1 ~ikm:"0b0b0b0b0b0b0b0b0b0b0b"
5555+ ~salt:"000102030405060708090a0b0c" ~info:"f0f1f2f3f4f5f6f7f8f9" ~l:42
7956 ~prk:"9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243"
8080- ~okm:"085a01ea1b10f36933068b56efa5ad81 \
8181- a4f14b822f5b091568a9cdd4f155fda2 \
8282- c22e422478d305f3f896"
5757+ ~okm:
5858+ "085a01ea1b10f36933068b56efa5ad81 a4f14b822f5b091568a9cdd4f155fda2 \
5959+ c22e422478d305f3f896"
8360 ()
84618562and test5 =
8686- test
8787- ~hash:`SHA1
8888- ~ikm:"000102030405060708090a0b0c0d0e0f \
8989- 101112131415161718191a1b1c1d1e1f \
9090- 202122232425262728292a2b2c2d2e2f \
9191- 303132333435363738393a3b3c3d3e3f \
9292- 404142434445464748494a4b4c4d4e4f"
9393- ~salt:"606162636465666768696a6b6c6d6e6f \
9494- 707172737475767778797a7b7c7d7e7f \
9595- 808182838485868788898a8b8c8d8e8f \
9696- 909192939495969798999a9b9c9d9e9f \
9797- a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
9898- ~info:"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf \
9999- c0c1c2c3c4c5c6c7c8c9cacbcccdcecf \
100100- d0d1d2d3d4d5d6d7d8d9dadbdcdddedf \
101101- e0e1e2e3e4e5e6e7e8e9eaebecedeeef \
102102- f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
103103- ~l:82
104104- ~prk:"8adae09a2a307059478d309b26c4115a224cfaf6"
105105- ~okm:"0bd770a74d1160f7c9f12cd5912a06eb \
106106- ff6adcae899d92191fe4305673ba2ffe \
107107- 8fa3f1a4e5ad79f3f334b3b202b2173c \
108108- 486ea37ce3d397ed034c7f9dfeb15c5e \
109109- 927336d0441f4c4300e2cff0d0900b52 \
110110- d3b4"
111111- ()
6363+ test ~hash:`SHA1
6464+ ~ikm:
6565+ "000102030405060708090a0b0c0d0e0f 101112131415161718191a1b1c1d1e1f \
6666+ 202122232425262728292a2b2c2d2e2f 303132333435363738393a3b3c3d3e3f \
6767+ 404142434445464748494a4b4c4d4e4f"
6868+ ~salt:
6969+ "606162636465666768696a6b6c6d6e6f 707172737475767778797a7b7c7d7e7f \
7070+ 808182838485868788898a8b8c8d8e8f 909192939495969798999a9b9c9d9e9f \
7171+ a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
7272+ ~info:
7373+ "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf c0c1c2c3c4c5c6c7c8c9cacbcccdcecf \
7474+ d0d1d2d3d4d5d6d7d8d9dadbdcdddedf e0e1e2e3e4e5e6e7e8e9eaebecedeeef \
7575+ f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
7676+ ~l:82 ~prk:"8adae09a2a307059478d309b26c4115a224cfaf6"
7777+ ~okm:
7878+ "0bd770a74d1160f7c9f12cd5912a06eb ff6adcae899d92191fe4305673ba2ffe \
7979+ 8fa3f1a4e5ad79f3f334b3b202b2173c 486ea37ce3d397ed034c7f9dfeb15c5e \
8080+ 927336d0441f4c4300e2cff0d0900b52 d3b4"
8181+ ()
1128211383and test6 =
114114- test
115115- ~hash:`SHA1
116116- ~ikm:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
117117- ~salt:""
118118- (* info = (0 octets) *)
119119- ~l:42
8484+ test ~hash:`SHA1 ~ikm:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
8585+ ~salt:"" (* info = (0 octets) *) ~l:42
12086 ~prk:"da8c8a73c7fa77288ec6f5e7c297786aa0d32d01"
121121- ~okm:"0ac1af7002b3d761d1e55298da9d0506 \
122122- b9ae52057220a306e07b6b87e8df21d0 \
123123- ea00033de03984d34918"
8787+ ~okm:
8888+ "0ac1af7002b3d761d1e55298da9d0506 b9ae52057220a306e07b6b87e8df21d0 \
8989+ ea00033de03984d34918"
12490 ()
1259112692and test7 =
127127- test
128128- ~hash:`SHA1
9393+ test ~hash:`SHA1
12994 ~ikm:"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"
130130- (* salt = not provided (defaults to HashLen zero octets) *)
131131- (* info = (0 octets) *)
132132- ~l:42
133133- ~prk:"2adccada18779e7c2077ad2eb19d3f3e731385dd"
134134- ~okm:"2c91117204d745f3500d636a62f64f0a \
135135- b3bae548aa53d423b0d1f27ebba6f5e5 \
136136- 673a081d70cce7acfc48"
9595+ (* salt = not provided (defaults to HashLen zero octets) *)
9696+ (* info = (0 octets) *)
9797+ ~l:42 ~prk:"2adccada18779e7c2077ad2eb19d3f3e731385dd"
9898+ ~okm:
9999+ "2c91117204d745f3500d636a62f64f0a b3bae548aa53d423b0d1f27ebba6f5e5 \
100100+ 673a081d70cce7acfc48"
137101 ()
138102139139-let tests = [
140140- "RFC 5869 Test Case 1", `Quick, test1 ;
141141- "RFC 5869 Test Case 2", `Quick, test2 ;
142142- "RFC 5869 Test Case 3", `Quick, test3 ;
143143- "RFC 5869 Test Case 4", `Quick, test4 ;
144144- "RFC 5869 Test Case 5", `Quick, test5 ;
145145- "RFC 5869 Test Case 6", `Quick, test6 ;
146146- "RFC 5869 Test Case 7", `Quick, test7 ;
147147-]
103103+let tests =
104104+ [
105105+ ("RFC 5869 Test Case 1", `Quick, test1);
106106+ ("RFC 5869 Test Case 2", `Quick, test2);
107107+ ("RFC 5869 Test Case 3", `Quick, test3);
108108+ ("RFC 5869 Test Case 4", `Quick, test4);
109109+ ("RFC 5869 Test Case 5", `Quick, test5);
110110+ ("RFC 5869 Test Case 6", `Quick, test6);
111111+ ("RFC 5869 Test Case 7", `Quick, test7);
112112+ ]
148113149149-let () = Alcotest.run "HKDF Tests" [ "RFC 5869", tests ]
114114+let () = Alcotest.run "HKDF Tests" [ ("RFC 5869", tests) ]
+25-17
pbkdf/pbkdf.ml
···11module type S = sig
22- val pbkdf1 : password:string -> salt:string -> count:int -> dk_len:int -> string
33- val pbkdf2 : password:string -> salt:string -> count:int -> dk_len:int32 -> string
22+ val pbkdf1 :
33+ password:string -> salt:string -> count:int -> dk_len:int -> string
44+55+ val pbkdf2 :
66+ password:string -> salt:string -> count:int -> dk_len:int32 -> string
47end
5869let cdiv x y =
···811 (formerly known as [cdiv]). It is part of the documented, publically
912 exposed _internal_ utility library not for public consumption, hence
1013 the API break that prompted this copy-pasted function. *)
1111- if y < 1 then raise Division_by_zero else
1212- if x > 0 then 1 + ((x - 1) / y) else 0 [@@inline]
1414+ if y < 1 then raise Division_by_zero
1515+ else if x > 0 then 1 + ((x - 1) / y)
1616+ else 0
1717+[@@inline]
13181414-module Make (H: Digestif.S) : S = struct
1919+module Make (H : Digestif.S) : S = struct
1520 let pbkdf1 ~password ~salt ~count ~dk_len =
1621 if String.length salt <> 8 then invalid_arg "salt should be 8 bytes"
1722 else if count <= 0 then invalid_arg "count must be a positive integer"
1818- else if dk_len <= 0 then invalid_arg "derived key length must be a positive integer"
2323+ else if dk_len <= 0 then
2424+ invalid_arg "derived key length must be a positive integer"
1925 else if dk_len > H.digest_size then invalid_arg "derived key too long"
2026 else
2127 let rec loop t = function
2222- 0 -> t
2828+ | 0 -> t
2329 | i -> loop H.(to_raw_string (digest_string t)) (i - 1)
2430 in
2531 String.sub (loop (password ^ salt) count) 0 dk_len
26322733 let pbkdf2 ~password ~salt ~count ~dk_len =
2834 if count <= 0 then invalid_arg "count must be a positive integer"
2929- else if dk_len <= 0l then invalid_arg "derived key length must be a positive integer"
3535+ else if dk_len <= 0l then
3636+ invalid_arg "derived key length must be a positive integer"
3037 else
3131- let h_len = H.digest_size
3232- and dk_len = Int32.to_int dk_len in
3838+ let h_len = H.digest_size and dk_len = Int32.to_int dk_len in
3339 let l = cdiv dk_len h_len in
3434- let r = dk_len - (l - 1) * h_len in
4040+ let r = dk_len - ((l - 1) * h_len) in
3541 let block i =
3642 let rec f u xor = function
3743 | 0 -> xor
3844 | j ->
3939- let u = H.(to_raw_string (hmac_string ~key:password u)) in
4040- f u (Crypto.Uncommon.xor xor u) (j - 1)
4545+ let u = H.(to_raw_string (hmac_string ~key:password u)) in
4646+ f u (Crypto.Uncommon.xor xor u) (j - 1)
4147 in
4248 let int_i = Bytes.create 4 in
4349 Bytes.set_int32_be int_i 0 (Int32.of_int i);
4444- let u_1 = H.hmac_string ~key:password (salt ^ Bytes.unsafe_to_string int_i) in
5050+ let u_1 =
5151+ H.hmac_string ~key:password (salt ^ Bytes.unsafe_to_string int_i)
5252+ in
4553 let u_1 = H.to_raw_string u_1 in
4654 f u_1 u_1 (count - 1)
4755 in
···4957 | 0 -> blocks
5058 | i -> loop (block i :: blocks) (i - 1)
5159 in
5252- String.concat "" (loop [String.sub (block l) 0 r] (l - 1))
6060+ String.concat "" (loop [ String.sub (block l) 0 r ] (l - 1))
5361end
54625563let pbkdf1 ~hash ~password ~salt ~count ~dk_len =
5656- let module H = (val (Digestif.module_of_hash' hash)) in
6464+ let module H = (val Digestif.module_of_hash' hash) in
5765 let module PBKDF = Make (H) in
5866 PBKDF.pbkdf1 ~password ~salt ~count ~dk_len
59676068let pbkdf2 ~prf ~password ~salt ~count ~dk_len =
6161- let module H = (val (Digestif.module_of_hash' prf)) in
6969+ let module H = (val Digestif.module_of_hash' prf) in
6270 let module PBKDF = Make (H) in
6371 PBKDF.pbkdf2 ~password ~salt ~count ~dk_len
+33-15
pbkdf/pbkdf.mli
···11-(** {{:https://tools.ietf.org/html/rfc2898}RFC 2898} specifies two password-based
22- key derivation functions (PBKDF1 and PBKDF2), which are abstracted over
33- a specific hash/pseudorandom function. *)
11+(** {{:https://tools.ietf.org/html/rfc2898}RFC 2898} specifies two
22+ password-based key derivation functions (PBKDF1 and PBKDF2), which are
33+ abstracted over a specific hash/pseudorandom function. *)
44module type S = sig
55- (** [pbkdf1 password salt count dk_len] is [dk], the derived key of [dk_len] octets.
66- The [salt] must be eight octets, [count] the iteration count.
77- @raise Invalid_argument when either [salt] is not eight octets long or either
88- [count] or [dk_len] are not valid. *)
99- val pbkdf1 : password:string -> salt:string -> count:int -> dk_len:int -> string
55+ val pbkdf1 :
66+ password:string -> salt:string -> count:int -> dk_len:int -> string
77+ (** [pbkdf1 password salt count dk_len] is [dk], the derived key of [dk_len]
88+ octets. The [salt] must be eight octets, [count] the iteration count.
99+ @raise Invalid_argument
1010+ when either [salt] is not eight octets long or either [count] or
1111+ [dk_len] are not valid. *)
10121111- (** [pbkdf2 password salt count dk_len] is [dk], the derived key of [dk_len] octets.
1313+ val pbkdf2 :
1414+ password:string -> salt:string -> count:int -> dk_len:int32 -> string
1515+ (** [pbkdf2 password salt count dk_len] is [dk], the derived key of [dk_len]
1616+ octets.
1217 @raise Invalid_argument when either [count] or [dk_len] are not valid *)
1313- val pbkdf2 : password:string -> salt:string -> count:int -> dk_len:int32 -> string
1418end
15191620(** Given a Hash/pseudorandom function, get the PBKDF *)
1717-module Make (H: Digestif.S) : S
2121+module Make (H : Digestif.S) : S
18221919-(** convenience [pbkdf1 hash password salt count dk_len] where the [hash] has to be provided explicitly *)
2020-val pbkdf1 : hash:Digestif.hash' -> password:string -> salt:string -> count:int -> dk_len:int -> string
2323+val pbkdf1 :
2424+ hash:Digestif.hash' ->
2525+ password:string ->
2626+ salt:string ->
2727+ count:int ->
2828+ dk_len:int ->
2929+ string
3030+(** convenience [pbkdf1 hash password salt count dk_len] where the [hash] has to
3131+ be provided explicitly *)
21322222-(** convenience [pbkdf2 prf password salt count dk_len] where the [prf] has to be provided explicitly *)
2323-val pbkdf2 : prf:Digestif.hash' -> password:string -> salt:string -> count:int -> dk_len:int32 -> string
3333+val pbkdf2 :
3434+ prf:Digestif.hash' ->
3535+ password:string ->
3636+ salt:string ->
3737+ count:int ->
3838+ dk_len:int32 ->
3939+ string
4040+(** convenience [pbkdf2 prf password salt count dk_len] where the [prf] has to
4141+ be provided explicitly *)
···11-external salsa_core : int -> string -> bytes -> unit = "caml_salsa_core" [@@noalloc]
11+external salsa_core : int -> string -> bytes -> unit = "caml_salsa_core"
22+[@@noalloc]
2334let salsa20_core count i =
45 let l = 64 in
···89 salsa_core count i o;
910 Bytes.unsafe_to_string o
10111111-let salsa20_8_core i =
1212- salsa20_core 4 i
1212+let salsa20_8_core i = salsa20_core 4 i
13131414let scrypt_block_mix b r =
1515 let b' = Bytes.create (String.length b) in
1616 let x = Bytes.create 64 in
1717- Bytes.unsafe_blit_string b ((2 * r - 1) * 64) x 0 64;
1818- for i = 0 to 2 * r - 1 do
1717+ Bytes.unsafe_blit_string b (((2 * r) - 1) * 64) x 0 64;
1818+ for i = 0 to (2 * r) - 1 do
1919 let b_i = Bytes.unsafe_of_string (String.sub b (i * 64) 64) in
2020- Crypto.Uncommon.unsafe_xor_into (Bytes.unsafe_to_string x) ~src_off:0 b_i ~dst_off:0 64;
2121- Bytes.unsafe_blit_string (salsa20_8_core (Bytes.unsafe_to_string b_i)) 0 x 0 64;
2222- let offset = (i mod 2) lsl (max 0 (r / 2 - 1)) + i / 2 in
2020+ Crypto.Uncommon.unsafe_xor_into (Bytes.unsafe_to_string x) ~src_off:0 b_i
2121+ ~dst_off:0 64;
2222+ Bytes.unsafe_blit_string
2323+ (salsa20_8_core (Bytes.unsafe_to_string b_i))
2424+ 0 x 0 64;
2525+ let offset = ((i mod 2) lsl max 0 ((r / 2) - 1)) + (i / 2) in
2326 Bytes.blit x 0 b' (offset * 64) 64
2427 done;
2528 b'
···3437 done;
3538 for _ = 0 to n - 1 do
3639 let integerify x =
3737- let k = Bytes.get_int32_le x (128 * r - 64) in
4040+ let k = Bytes.get_int32_le x ((128 * r) - 64) in
3841 let n' = n - 1 in
3942 Int32.(to_int (logand k (of_int n')))
4043 in
4144 let j = integerify !x in
4242- Crypto.Uncommon.unsafe_xor_into (Bytes.unsafe_to_string v) ~src_off:(blen * j) !x ~dst_off:0 blen;
4343- x := scrypt_block_mix (Bytes.unsafe_to_string !x) r;
4545+ Crypto.Uncommon.unsafe_xor_into (Bytes.unsafe_to_string v)
4646+ ~src_off:(blen * j) !x ~dst_off:0 blen;
4747+ x := scrypt_block_mix (Bytes.unsafe_to_string !x) r
4448 done;
4549 !x
46504751let scrypt ~password ~salt ~n ~r ~p ~dk_len =
4848- let is_power_of_2 x = (x land (x - 1)) = 0 in
5252+ let is_power_of_2 x = x land (x - 1) = 0 in
4953 if n <= 1 then invalid_arg "n must be larger than 1"
5054 else if not (is_power_of_2 n) then invalid_arg "n must be a power of 2"
5155 else if p <= 0 then invalid_arg "p must be a positive integer"
5252- else if p > (Int64.to_int (Int64.div 0xffffffffL 4L) / r) then invalid_arg "p too big"
5353- else if dk_len <= 0l then invalid_arg "derived key length must be a positive integer";
5656+ else if p > Int64.to_int (Int64.div 0xffffffffL 4L) / r then
5757+ invalid_arg "p too big"
5858+ else if dk_len <= 0l then
5959+ invalid_arg "derived key length must be a positive integer";
5460 let rec partition b blocks = function
5561 | 0 -> blocks
5662 | i ->
5757- let off = (i - 1) * r * 128 in
5858- let block = Bytes.unsafe_of_string (String.sub b off (r * 128)) in
5959- partition b (block :: blocks) (i - 1)
6363+ let off = (i - 1) * r * 128 in
6464+ let block = Bytes.unsafe_of_string (String.sub b off (r * 128)) in
6565+ partition b (block :: blocks) (i - 1)
6066 in
6167 let blen = Int32.of_int (128 * r * p) in
6268 let dk = Pbkdf.pbkdf2 ~prf:`SHA256 ~password ~salt ~count:1 ~dk_len:blen in
+18-14
scrypt/scrypt.mli
···11-(** {{:https://tools.ietf.org/html/rfc7914}
22- The scrypt Password-Based Key Derivation Function}
33- specifies the password-based key derivation function scrypt. The
44- function derives one or more secret keys from a secret string.
55- It is based on memory-hard functions which offer added protection
66- against attacks using custom hardware. *)
11+(** {{:https://tools.ietf.org/html/rfc7914} The scrypt Password-Based Key
22+ Derivation Function} specifies the password-based key derivation function
33+ scrypt. The function derives one or more secret keys from a secret string.
44+ It is based on memory-hard functions which offer added protection against
55+ attacks using custom hardware. *)
7688-(** [scrypt_kdf password salt n r p dk_len] is [dk], the derived key
99- of [dk_len] octets.
1010- [n], the cost parameter, must be larger than 1 and a power of 2.
1111- [p], the parallelization parameter, must be a possitive integer
1212- and less than or equal to 2^32 - 1 / (4 * r)
1313- @raise Invalid_argument when either [n], [p] or [dk_len] are not
1414- valid *)
1515-val scrypt : password:string -> salt:string -> n:int -> r:int -> p:int -> dk_len:int32 -> string
77+val scrypt :
88+ password:string ->
99+ salt:string ->
1010+ n:int ->
1111+ r:int ->
1212+ p:int ->
1313+ dk_len:int32 ->
1414+ string
1515+(** [scrypt_kdf password salt n r p dk_len] is [dk], the derived key of [dk_len]
1616+ octets. [n], the cost parameter, must be larger than 1 and a power of 2.
1717+ [p], the parallelization parameter, must be a possitive integer and less
1818+ than or equal to 2^32 - 1 / (4 * r)
1919+ @raise Invalid_argument when either [n], [p] or [dk_len] are not valid *)
+30-47
scrypt/tests/scrypt_kdf_tests.ml
···11let test_scrypt_kdf ~password ~salt ~n ~r ~p ~dk_len ~dk =
22 let dk = Ohex.decode dk in
33- (fun () ->
44- let edk = Scrypt.scrypt ~password ~salt ~n ~r ~p ~dk_len in
55- Alcotest.check Alcotest.string "Scrypt test" edk dk)
33+ fun () ->
44+ let edk = Scrypt.scrypt ~password ~salt ~n ~r ~p ~dk_len in
55+ Alcotest.check Alcotest.string "Scrypt test" edk dk
6677let scrypt_kdf_test1 =
88- test_scrypt_kdf
99- ~password:""
1010- ~salt:""
1111- ~n:16
1212- ~r:1
1313- ~p:1
1414- ~dk_len:64l
1515- ~dk:"77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906"
88+ test_scrypt_kdf ~password:"" ~salt:"" ~n:16 ~r:1 ~p:1 ~dk_len:64l
99+ ~dk:
1010+ "77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906"
16111712let scrypt_kdf_test2 =
1818- test_scrypt_kdf
1919- ~password:"password"
2020- ~salt:"NaCl"
2121- ~n:1024
2222- ~r:8
2323- ~p:16
1313+ test_scrypt_kdf ~password:"password" ~salt:"NaCl" ~n:1024 ~r:8 ~p:16
2414 ~dk_len:64l
2525- ~dk:"fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640"
1515+ ~dk:
1616+ "fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640"
26172718let scrypt_kdf_test3 =
2828- test_scrypt_kdf
2929- ~password:"pleaseletmein"
3030- ~salt:"SodiumChloride"
3131- ~n:16384
3232- ~r:8
3333- ~p:1
3434- ~dk_len:64l
3535- ~dk:"7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887"
1919+ test_scrypt_kdf ~password:"pleaseletmein" ~salt:"SodiumChloride" ~n:16384 ~r:8
2020+ ~p:1 ~dk_len:64l
2121+ ~dk:
2222+ "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887"
36233724let scrypt_kdf_test4 =
3838- test_scrypt_kdf
3939- ~password:"pleaseletmein"
4040- ~salt:"SodiumChloride"
4141- ~n:1048576
4242- ~r:8
4343- ~p:1
4444- ~dk_len:64l
4545- ~dk:"2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049e8a952fbcbf45c6fa77a41a4"
2525+ test_scrypt_kdf ~password:"pleaseletmein" ~salt:"SodiumChloride" ~n:1048576
2626+ ~r:8 ~p:1 ~dk_len:64l
2727+ ~dk:
2828+ "2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049e8a952fbcbf45c6fa77a41a4"
46294730let scrypt_kdf_tests () =
4848- let tests = [
4949- "Test Case 1", `Quick, scrypt_kdf_test1;
5050- "Test Case 2", `Quick, scrypt_kdf_test2;
5151- ] in
3131+ let tests =
3232+ [
3333+ ("Test Case 1", `Quick, scrypt_kdf_test1);
3434+ ("Test Case 2", `Quick, scrypt_kdf_test2);
3535+ ]
3636+ in
5237 (* Skip test case 3 and 4 for architectures with 31 bit sizes or less, as it requires a buffer larger than Int.max_size in those cases *)
5353- if Sys.int_size <= 31 then
3838+ if Sys.int_size <= 31 then tests
3939+ else
5440 tests
5555- else
5656- tests @ [
5757- "Test Case 3", `Quick, scrypt_kdf_test3;
5858- "Test Case 4", `Slow, scrypt_kdf_test4;
5959- ]
4141+ @ [
4242+ ("Test Case 3", `Quick, scrypt_kdf_test3);
4343+ ("Test Case 4", `Slow, scrypt_kdf_test4);
4444+ ]
60456146let () =
6262- Alcotest.run "Scrypt kdf Tests" [
6363- "Scrypt kdf tests", scrypt_kdf_tests ();
6464- ]
4747+ Alcotest.run "Scrypt kdf Tests" [ ("Scrypt kdf tests", scrypt_kdf_tests ()) ]