176 lines
6.1 KiB
OCaml
176 lines
6.1 KiB
OCaml
|
|
|
||
|
|
let pitable = [|
|
||
|
|
0xd9; 0x78; 0xf9; 0xc4; 0x19; 0xdd; 0xb5; 0xed; 0x28; 0xe9; 0xfd; 0x79; 0x4a; 0xa0; 0xd8; 0x9d;
|
||
|
|
0xc6; 0x7e; 0x37; 0x83; 0x2b; 0x76; 0x53; 0x8e; 0x62; 0x4c; 0x64; 0x88; 0x44; 0x8b; 0xfb; 0xa2;
|
||
|
|
0x17; 0x9a; 0x59; 0xf5; 0x87; 0xb3; 0x4f; 0x13; 0x61; 0x45; 0x6d; 0x8d; 0x09; 0x81; 0x7d; 0x32;
|
||
|
|
0xbd; 0x8f; 0x40; 0xeb; 0x86; 0xb7; 0x7b; 0x0b; 0xf0; 0x95; 0x21; 0x22; 0x5c; 0x6b; 0x4e; 0x82;
|
||
|
|
0x54; 0xd6; 0x65; 0x93; 0xce; 0x60; 0xb2; 0x1c; 0x73; 0x56; 0xc0; 0x14; 0xa7; 0x8c; 0xf1; 0xdc;
|
||
|
|
0x12; 0x75; 0xca; 0x1f; 0x3b; 0xbe; 0xe4; 0xd1; 0x42; 0x3d; 0xd4; 0x30; 0xa3; 0x3c; 0xb6; 0x26;
|
||
|
|
0x6f; 0xbf; 0x0e; 0xda; 0x46; 0x69; 0x07; 0x57; 0x27; 0xf2; 0x1d; 0x9b; 0xbc; 0x94; 0x43; 0x03;
|
||
|
|
0xf8; 0x11; 0xc7; 0xf6; 0x90; 0xef; 0x3e; 0xe7; 0x06; 0xc3; 0xd5; 0x2f; 0xc8; 0x66; 0x1e; 0xd7;
|
||
|
|
0x08; 0xe8; 0xea; 0xde; 0x80; 0x52; 0xee; 0xf7; 0x84; 0xaa; 0x72; 0xac; 0x35; 0x4d; 0x6a; 0x2a;
|
||
|
|
0x96; 0x1a; 0xd2; 0x71; 0x5a; 0x15; 0x49; 0x74; 0x4b; 0x9f; 0xd0; 0x5e; 0x04; 0x18; 0xa4; 0xec;
|
||
|
|
0xc2; 0xe0; 0x41; 0x6e; 0x0f; 0x51; 0xcb; 0xcc; 0x24; 0x91; 0xaf; 0x50; 0xa1; 0xf4; 0x70; 0x39;
|
||
|
|
0x99; 0x7c; 0x3a; 0x85; 0x23; 0xb8; 0xb4; 0x7a; 0xfc; 0x02; 0x36; 0x5b; 0x25; 0x55; 0x97; 0x31;
|
||
|
|
0x2d; 0x5d; 0xfa; 0x98; 0xe3; 0x8a; 0x92; 0xae; 0x05; 0xdf; 0x29; 0x10; 0x67; 0x6c; 0xba; 0xc9;
|
||
|
|
0xd3; 0x00; 0xe6; 0xcf; 0xe1; 0x9e; 0xa8; 0x2c; 0x63; 0x16; 0x01; 0x3f; 0x58; 0xe2; 0x89; 0xa9;
|
||
|
|
0x0d; 0x38; 0x34; 0x1b; 0xab; 0x33; 0xff; 0xb0; 0xbb; 0x48; 0x0c; 0x5f; 0xb9; 0xb1; 0xcd; 0x2e;
|
||
|
|
0xc5; 0xf3; 0xdb; 0x47; 0xe5; 0xa5; 0x9c; 0x77; 0x0a; 0xa6; 0x20; 0x68; 0xfe; 0x7f; 0xc1; 0xad
|
||
|
|
|]
|
||
|
|
|
||
|
|
(* effective is sometimes named t1 *)
|
||
|
|
let tm effective =
|
||
|
|
let t8 = (effective + 7) / 8 in
|
||
|
|
(* RFC says (TM = 255 MOD 2^(8 + effective - 8*T8)) *)
|
||
|
|
let bits = 8 + effective - 8 * t8 in
|
||
|
|
(* likely there's a smarter way to do this *)
|
||
|
|
let rec c acc = function
|
||
|
|
| 0 -> acc
|
||
|
|
| n -> c ((acc lsl 1) + 1) (pred n)
|
||
|
|
in
|
||
|
|
t8, c 0 bits
|
||
|
|
|
||
|
|
(* L[i] is the i-th byte of the key; K[i] is the i-th 16-bit-word of the key *)
|
||
|
|
let key_expansion effective key =
|
||
|
|
(* result is a 128 byte key, where we need the words.. *)
|
||
|
|
let t = String.length key in
|
||
|
|
let l = Array.init 128 (fun idx -> if idx < t then String.get_uint8 key idx else 0) in
|
||
|
|
let t8, tm = tm effective in
|
||
|
|
for i = t to 127 do
|
||
|
|
l.(i) <- pitable.((l.(i - 1) + l.(i - t)) mod 256)
|
||
|
|
done;
|
||
|
|
l.(128 - t8) <- pitable.(l.(128 - t8) land tm);
|
||
|
|
for i = 127 - t8 downto 0 do
|
||
|
|
l.(i) <- pitable.(l.(i + 1) lxor l.(i + t8));
|
||
|
|
done;
|
||
|
|
Array.init 64 (fun idx -> l.(2 * idx) + 256 * l.(2 * idx + 1))
|
||
|
|
|
||
|
|
let mod16 f = 0xFFFF land f
|
||
|
|
|
||
|
|
let rol16 x k = mod16 ((x lsl k) lor (x lsr (16 - k)))
|
||
|
|
|
||
|
|
let ror16 x k = mod16 ((x lsr k) lor (x lsl (16 - k)))
|
||
|
|
|
||
|
|
let not16 x = mod16 (lnot x)
|
||
|
|
|
||
|
|
let s = Array.init 4 (function 0 -> 1 | 1 -> 2 | 2 -> 3 | 3 -> 5 | _ -> assert false)
|
||
|
|
|
||
|
|
let pmod a =
|
||
|
|
let b = 4 in
|
||
|
|
let r = a mod b in
|
||
|
|
if r < 0 then (r + b) mod b else r
|
||
|
|
|
||
|
|
(* only used for encryption which we don't support
|
||
|
|
let mix r i k j =
|
||
|
|
r.(i) <- mod16 (r.(i) + k.(j) + r.(pmod (i - 1)) land r.(pmod (i - 2)) +
|
||
|
|
(not16 r.(pmod (i - 1))) land r.(pmod (i - 3)));
|
||
|
|
let j = succ j in
|
||
|
|
r.(i) <- rol16 r.(i) s.(i);
|
||
|
|
j
|
||
|
|
|
||
|
|
let mix_round r k j =
|
||
|
|
let j' = mix r 0 k j in
|
||
|
|
let j'' = mix r 1 k j' in
|
||
|
|
let j''' = mix r 2 k j'' in
|
||
|
|
let j'''' = mix r 3 k j''' in
|
||
|
|
j''''
|
||
|
|
|
||
|
|
let mash r i k =
|
||
|
|
r.(i) <- mod16 (r.(i) + k.(r.(pmod (i - 1)) land 63))
|
||
|
|
|
||
|
|
let mash_round r k =
|
||
|
|
mash r 0 k;
|
||
|
|
mash r 1 k;
|
||
|
|
mash r 2 k;
|
||
|
|
mash r 3 k
|
||
|
|
|
||
|
|
let encrypt_one ~key ~data =
|
||
|
|
let r = Array.init 4 (fun idx -> Cstruct.LE.get_uint16 data (idx * 2)) in
|
||
|
|
let j = 0 in
|
||
|
|
let j = mix_round r key j in
|
||
|
|
let j = mix_round r key j in
|
||
|
|
let j = mix_round r key j in
|
||
|
|
let j = mix_round r key j in
|
||
|
|
let j = mix_round r key j in
|
||
|
|
mash_round r key;
|
||
|
|
let j = mix_round r key j in
|
||
|
|
let j = mix_round r key j in
|
||
|
|
let j = mix_round r key j in
|
||
|
|
let j = mix_round r key j in
|
||
|
|
let j = mix_round r key j in
|
||
|
|
let j = mix_round r key j in
|
||
|
|
mash_round r key;
|
||
|
|
let j = mix_round r key j in
|
||
|
|
let j = mix_round r key j in
|
||
|
|
let j = mix_round r key j in
|
||
|
|
let j = mix_round r key j in
|
||
|
|
let _j = mix_round r key j in
|
||
|
|
let out = Cstruct.create 8 in
|
||
|
|
Cstruct.LE.set_uint16 out 0 r.(0);
|
||
|
|
Cstruct.LE.set_uint16 out 2 r.(1);
|
||
|
|
Cstruct.LE.set_uint16 out 4 r.(2);
|
||
|
|
Cstruct.LE.set_uint16 out 6 r.(3);
|
||
|
|
out
|
||
|
|
*)
|
||
|
|
|
||
|
|
let r_mix r i k j =
|
||
|
|
r.(i) <- ror16 r.(i) s.(i);
|
||
|
|
r.(i) <- mod16 (r.(i) - k.(j) -
|
||
|
|
(r.(pmod (i - 1)) land r.(pmod (i - 2))) -
|
||
|
|
(not16 r.(pmod (i - 1)) land (r.(pmod (i - 3)))));
|
||
|
|
pred j
|
||
|
|
|
||
|
|
let r_mix_round r k j =
|
||
|
|
let j' = r_mix r 3 k j in
|
||
|
|
let j'' = r_mix r 2 k j' in
|
||
|
|
let j''' = r_mix r 1 k j'' in
|
||
|
|
let j'''' = r_mix r 0 k j''' in
|
||
|
|
j''''
|
||
|
|
|
||
|
|
let r_mash r i k =
|
||
|
|
r.(i) <- mod16 (r.(i) - k.(r.(pmod (i - 1)) land 63))
|
||
|
|
|
||
|
|
let r_mash_round r k =
|
||
|
|
r_mash r 3 k;
|
||
|
|
r_mash r 2 k;
|
||
|
|
r_mash r 1 k;
|
||
|
|
r_mash r 0 k
|
||
|
|
|
||
|
|
let decrypt_one ~key ~data ?(off = 0) dst =
|
||
|
|
let r = Array.init 4 (fun idx -> String.get_uint16_le data (off + idx * 2)) in
|
||
|
|
let j = 63 in
|
||
|
|
let j = r_mix_round r key j in
|
||
|
|
let j = r_mix_round r key j in
|
||
|
|
let j = r_mix_round r key j in
|
||
|
|
let j = r_mix_round r key j in
|
||
|
|
let j = r_mix_round r key j in
|
||
|
|
r_mash_round r key;
|
||
|
|
let j = r_mix_round r key j in
|
||
|
|
let j = r_mix_round r key j in
|
||
|
|
let j = r_mix_round r key j in
|
||
|
|
let j = r_mix_round r key j in
|
||
|
|
let j = r_mix_round r key j in
|
||
|
|
let j = r_mix_round r key j in
|
||
|
|
r_mash_round r key;
|
||
|
|
let j = r_mix_round r key j in
|
||
|
|
let j = r_mix_round r key j in
|
||
|
|
let j = r_mix_round r key j in
|
||
|
|
let j = r_mix_round r key j in
|
||
|
|
let _j = r_mix_round r key j in
|
||
|
|
Bytes.set_uint16_le dst (off + 0) r.(0);
|
||
|
|
Bytes.set_uint16_le dst (off + 2) r.(1);
|
||
|
|
Bytes.set_uint16_le dst (off + 4) r.(2);
|
||
|
|
Bytes.set_uint16_le dst (off + 6) r.(3)
|
||
|
|
|
||
|
|
let decrypt_cbc ?(effective = 128) ~key ~iv data =
|
||
|
|
let block = 8 in
|
||
|
|
let key = key_expansion effective key in
|
||
|
|
let l = String.length data in
|
||
|
|
let dst = Bytes.create l in
|
||
|
|
for i = 0 to pred ((l + pred block) / block) do
|
||
|
|
decrypt_one ~key ~data ~off:(i * block) dst
|
||
|
|
done;
|
||
|
|
Mirage_crypto.Uncommon.unsafe_xor_into iv ~src_off:0 dst ~dst_off:0 block;
|
||
|
|
Mirage_crypto.Uncommon.unsafe_xor_into data ~src_off:0 dst ~dst_off:block (l - block);
|
||
|
|
Bytes.unsafe_to_string dst
|