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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
open Types
type passwd =
{ plain_passwd : string ;
strong_passwd : string }
type t = passwd
let empty_passwd =
{ plain_passwd = "" ;
strong_passwd = "" }
let plain_passwd p = p.plain_passwd
let strong_passwd p = p.strong_passwd
let digest s = Cryptokit.hash_string (Cryptokit.Hash.sha256 ()) s
let normalize_passwd passwd = Cryptokit.hash_string (Cryptokit.Hash.sha256 ()) passwd
let transform ~passwd way p =
let tr = Cryptokit.Cipher.aes ~pad:Cryptokit.Padding.length (normalize_passwd passwd) way in
Cryptokit.transform_string tr p
let encrypt ~passwd =
transform ~passwd:passwd.strong_passwd Cryptokit.Cipher.Encrypt
let decrypt ~passwd =
let f = transform ~passwd:passwd.strong_passwd Cryptokit.Cipher.Decrypt in
fun s -> try f s with _ -> raiserror (Bad_password Any)
let compute_padding ~key ~passwd ~max_pad =
let hash = digest (key ^ "*\000z" ^ passwd.strong_passwd ^ "!\000x" ^ string_of_int max_pad) in
assert (String.length hash >= 3) ;
let numb = (Char.code hash.[0]) lsl 16 + (Char.code hash.[1]) lsl 8 + (Char.code hash.[2]) in
numb mod (1 + max_pad)
let rec circular_xor s1 s2 pos len1 len2 =
if pos >= len1 then ()
else
begin
let n = min (len1 - pos) len2 in
Cryptokit.xor_string s2 0 s1 pos n ;
circular_xor s1 s2 (pos + n) len1 len2
end
let compute_strong_passwd iterations p =
let rec iterate current n =
if n = 0 then current
else
let current2 = transform ~passwd:p Cryptokit.Cipher.Encrypt current in
let current_hash = digest current2 in
let current2 = Bytes.of_string current2 in
circular_xor current2 current_hash 0 (Bytes.length current2) (String.length current_hash) ;
iterate (digest (Bytes.to_string current2)) (n-1)
in
try digest (iterate p (abs iterations))
with _ -> assert false
let mk_passwd ~iterations p =
if p = "" then empty_passwd
else
{ plain_passwd = p ;
strong_passwd = compute_strong_passwd iterations p }
let mk_weak_passwd p =
if p = "" then empty_passwd
else
{ plain_passwd = p ;
strong_passwd = p }
let concat plist =
List.fold_left
begin fun acu p ->
if p == empty_passwd then acu
else if acu == empty_passwd then p
else
{ plain_passwd = acu.plain_passwd ^ p.plain_passwd ;
strong_passwd = acu.strong_passwd ^ p.strong_passwd }
end
empty_passwd plist
let random_salt ~len = Utils.(random_string Utils.gen len)