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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
type location =
| Table_Builtin
| Subtable_Builtin of int
| Subtable_User of int
let max_subtable = 1 lsl 14 - 1
let loc2s = function
| Table_Builtin -> "Table_Builtin"
| Subtable_Builtin n -> "Subtable_Builtin " ^ (string_of_int n)
| Subtable_User n -> "Subtable_User " ^ (string_of_int n)
type 'a howstored =
| Uncrypted
| Encrypted of 'a
type hidden =
{ table_encrypt : string -> string ;
subtable_encrypt : string -> string }
type key_kind =
{ key_loc : location ;
key_how : (Cipher.passwd * Cipher.passwd * int) howstored ;
cryptf : hidden }
type data_kind =
{ data_how : (Cipher.passwd * int) howstored }
let mk_data how = { data_how = how }
let encrypt_error _ = (Printf.printf "Unexpectedly calling encrypt_error in kinds.ml\n%!" ; assert false)
let nocryptf = { table_encrypt = encrypt_error ; subtable_encrypt = encrypt_error }
let mkcrypt p =
if p == Cipher.empty_passwd then encrypt_error else
begin
let res = Cipher.encrypt ~passwd:p in
res
end
let mk_key loc how =
let cryptf =
match how with
| Uncrypted -> nocryptf
| Encrypted (table_passwd, subtable_passwd, _) ->
assert (not (table_passwd == Cipher.empty_passwd && subtable_passwd == Cipher.empty_passwd)) ;
assert (loc <> Table_Builtin || subtable_passwd == Cipher.empty_passwd) ;
{ table_encrypt = mkcrypt table_passwd ;
subtable_encrypt = mkcrypt subtable_passwd }
in
{ key_loc = loc ;
key_how = how ;
cryptf }
type encoded_key = string
type encoded_data = string
let cmp_encoded_key ek1 ek2 = compare ek1 ek2
module LowerDB = LowerDB_impl
let choose_data_padding max_pad = Random.int (max_pad + 1)
open Strings
let put_location = function
| Table_Builtin -> "\xc0"
| Subtable_Builtin subt -> assert (subt >= 0 && subt <= max_subtable) ; insert16 "oo" 0 (0x4000 lor subt)
| Subtable_User subt -> assert (subt >= 0 && subt <= max_subtable) ; insert16 "oo" 0 subt
let loc2hash = put_location
let get_location s =
let len = String.length s in
assert (len > 0) ;
match s.[0] with
| '\xc0' -> (Table_Builtin, String.sub s 1 (len-1))
| _ ->
assert (len >= 2) ;
let code = read16 s ~pos:0 in
let subt = code land 0x3FFF
and hd = (code land 0xc000) lsr 14 in
let loc =
match hd with
| 0 -> Subtable_User subt
| 1 -> Subtable_Builtin subt
| _ -> assert false
in
(loc, String.sub s 2 (len-2))
let encode_data data kind =
match kind.data_how with
| Uncrypted -> data
| Encrypted (passwd, padlength) ->
assert (passwd != Cipher.empty_passwd) ;
let padded_data = if padlength = 0 then pad data 0 else pad data (choose_data_padding padlength) in
Cipher.encrypt ~passwd padded_data
let decode_data encdata kind =
match kind.data_how with
| Uncrypted -> encdata
| Encrypted (passwd, _) ->
assert (passwd != Cipher.empty_passwd) ;
let paddata = Cipher.decrypt ~passwd encdata in
unpad paddata
let encode_key key kind =
match kind.key_how with
| Uncrypted -> append_char (put_location kind.key_loc ^ key) '0'
| Encrypted (table_passwd, subtable_passwd, padlength) ->
assert (not (table_passwd == Cipher.empty_passwd && subtable_passwd == Cipher.empty_passwd)) ;
assert (kind.key_loc <> Table_Builtin || subtable_passwd == Cipher.empty_passwd) ;
let padded_key =
if padlength = 0 then pad key 0
else
let passwd = if table_passwd == Cipher.empty_passwd then subtable_passwd else table_passwd in
pad key (Cipher.compute_padding ~key ~passwd ~max_pad:padlength)
in
let subtable_key =
if subtable_passwd == Cipher.empty_passwd then padded_key
else
begin
let located = put_location kind.key_loc ^ padded_key in
let res = kind.cryptf.subtable_encrypt located in
res
end
in
let located_key =
let subtable_char = if subtable_passwd == Cipher.empty_passwd then 'T' else 'E' in
(append_char (put_location kind.key_loc) subtable_char) ^ subtable_key
in
let table_key =
if table_passwd == Cipher.empty_passwd then located_key
else kind.cryptf.table_encrypt located_key
in
append_char table_key (if table_passwd == Cipher.empty_passwd then '1' else '2')
let get_key_info passwd ~subt_pas enckey =
let (last, rest_key) = get_last_char enckey in
match last with
| '0' ->
let (key_loc, key) = get_location rest_key in
let kind = { key_loc ;
key_how = Uncrypted ;
cryptf = nocryptf }
in
Some (kind, Some key)
| '1' | '2' ->
begin
assert (not (last = '1' && passwd != Cipher.empty_passwd)) ;
try
let table_key =
if last = '1' then
rest_key
else
if passwd == Cipher.empty_passwd then
raise Not_found
else
Cipher.decrypt ~passwd rest_key
in
let (loc, temp_key) = get_location table_key in
let (subchar, subtable_key) = get_first_char temp_key in
let (key, subpass) =
begin match (loc, subchar) with
| Table_Builtin, 'T' -> (Some (unpad subtable_key), Cipher.empty_passwd)
| Table_Builtin, _ -> assert false
| (Subtable_Builtin subt | Subtable_User subt), 'T' ->
(Some (unpad subtable_key), Cipher.empty_passwd)
| (Subtable_Builtin subt | Subtable_User subt), 'E' ->
let subt_passwd = subt_pas subt in
if subt_passwd == Cipher.empty_passwd then
(None, Cipher.empty_passwd)
else
begin
let inner_key = Cipher.decrypt ~passwd:subt_passwd subtable_key in
let (loc2, padded_key) = get_location inner_key in
assert (loc = loc2) ;
(Some (unpad padded_key), subt_passwd)
end
| (Subtable_Builtin subt | Subtable_User subt), _ -> assert false
end
in
let kind =
{ key_loc = loc ;
key_how = Encrypted (passwd, subpass, 0) ;
cryptf = nocryptf }
in
Some (kind, key)
with Not_found -> None
end
| _ -> assert false
let sign passwd v = Cipher.digest ("$_" ^ Cipher.strong_passwd passwd ^ "\003M" ^ v ^ "=")
let sign_encoded_key = sign
let sign_encoded_data = sign
let id x = x
let encodedkey2s = id
let encodeddata2s = id
let s2encodedkey = id
let s2encodeddata = id