forked from
gazagnaire.org/ocaml-crypto
upstream: https://github.com/mirage/mirage-crypto
1open Uncommon
2
3module type Stream = sig
4 type key
5 type result = { message : string; key : key }
6
7 val of_secret : string -> key
8 val encrypt : key:key -> string -> result
9 val decrypt : key:key -> string -> result
10end
11
12module ARC4 = struct
13 type key = int * int * int array
14 type result = { message : string; key : key }
15
16 let of_secret buf =
17 let len = String.length buf in
18 if len < 1 || len > 256 then invalid_arg "ARC4.of_secret: key size %d" len;
19 let s = Array.init 256 (fun x -> x) in
20 let rec loop j = function
21 | 256 -> ()
22 | i ->
23 let x = String.get_uint8 buf (i mod len) in
24 let si = s.(i) in
25 let j = (j + si + x) land 0xff in
26 let sj = s.(j) in
27 s.(i) <- sj;
28 s.(j) <- si;
29 (loop [@tailcall]) j (succ i)
30 in
31 loop 0 0;
32 (0, 0, s)
33
34 let encrypt ~key:(i, j, s') buf =
35 let s = Array.copy s' and len = String.length buf in
36 let res = Bytes.create len in
37 let rec mix i j = function
38 | n when n = len -> (i, j, s)
39 | n ->
40 let i = succ i land 0xff in
41 let si = s.(i) in
42 let j = (j + si) land 0xff in
43 let sj = s.(j) in
44 s.(i) <- sj;
45 s.(j) <- si;
46 let k = s.((si + sj) land 0xff) in
47 Bytes.set_uint8 res n (k lxor String.get_uint8 buf n);
48 (mix [@tailcall]) i j (succ n)
49 in
50 let key' = mix i j 0 in
51 { key = key'; message = Bytes.unsafe_to_string res }
52
53 let decrypt = encrypt
54end