upstream: https://github.com/mirage/mirage-crypto
at main 167 lines 5.5 kB view raw
1open Uncommon 2 3let block_size = 16 4let flags bit6 len1 len2 = (bit6 lsl 6) + (len1 lsl 3) + len2 5 6let encode_len buf ~off size value = 7 let rec ass num = function 8 | 0 -> Bytes.set_uint8 buf off num 9 | m -> 10 Bytes.set_uint8 buf (off + m) (num land 0xff); 11 (ass [@tailcall]) (num lsr 8) (pred m) 12 in 13 ass value (pred size) 14 15let set_format buf ?(off = 0) nonce flag_val value = 16 let n = String.length nonce in 17 let small_q = 15 - n in 18 (* first octet block: 19 0 : flags 20 1..15 - q : N 21 16 - q..15 : Q *) 22 Bytes.set_uint8 buf off flag_val; 23 Bytes.unsafe_blit_string nonce 0 buf (off + 1) n; 24 encode_len buf ~off:(off + n + 1) small_q value 25 26let gen_adata a = 27 let llen, set_llen = 28 match String.length a with 29 | x when x < (1 lsl 16) - (1 lsl 8) -> 30 (2, fun buf off -> Bytes.set_uint16_be buf off x) 31 | x when Sys.int_size < 32 || x < 1 lsl 32 -> 32 ( 6, 33 fun buf off -> 34 Bytes.set_uint16_be buf off 0xfffe; 35 Bytes.set_int32_be buf (off + 2) (Int32.of_int x) ) 36 | x -> 37 ( 10, 38 fun buf off -> 39 Bytes.set_uint16_be buf off 0xffff; 40 Bytes.set_int64_be buf (off + 2) (Int64.of_int x) ) 41 in 42 let to_pad = 43 let leftover = (llen + String.length a) mod block_size in 44 block_size - leftover 45 in 46 ( llen + String.length a + to_pad, 47 fun buf off -> 48 set_llen buf off; 49 Bytes.unsafe_blit_string a 0 buf (off + llen) (String.length a); 50 Bytes.unsafe_fill buf (off + llen + String.length a) to_pad '\000' ) 51 52let gen_ctr nonce i = 53 let n = String.length nonce in 54 let small_q = 15 - n in 55 let flag_val = flags 0 0 (small_q - 1) in 56 let buf = Bytes.create 16 in 57 set_format buf nonce flag_val i; 58 buf 59 60let prepare_header nonce adata plen tlen = 61 let small_q = 15 - String.length nonce in 62 let b6 = if String.length adata = 0 then 0 else 1 in 63 let flag_val = flags b6 ((tlen - 2) / 2) (small_q - 1) in 64 if String.length adata = 0 then ( 65 let hdr = Bytes.create 16 in 66 set_format hdr nonce flag_val plen; 67 hdr) 68 else 69 let len, set = gen_adata adata in 70 let buf = Bytes.create (16 + len) in 71 set_format buf nonce flag_val plen; 72 set buf 16; 73 buf 74 75type mode = Encrypt | Decrypt 76 77let crypto_core_into ~cipher ~mode ~key ~nonce ~adata src ~src_off dst ~dst_off 78 len = 79 let cbcheader = prepare_header nonce adata len block_size in 80 81 let small_q = 15 - String.length nonce in 82 let ctr_flag_val = flags 0 0 (small_q - 1) in 83 let ctrblock i block dst_off = 84 Bytes.set_uint8 block dst_off ctr_flag_val; 85 Bytes.unsafe_blit_string nonce 0 block (dst_off + 1) (String.length nonce); 86 encode_len block ~off:(dst_off + String.length nonce + 1) small_q i; 87 cipher ~key (Bytes.unsafe_to_string block) ~src_off:dst_off block ~dst_off 88 in 89 90 let cbc iv src_off block dst_off = 91 unsafe_xor_into iv ~src_off block ~dst_off block_size; 92 cipher ~key (Bytes.unsafe_to_string block) ~src_off:dst_off block ~dst_off 93 in 94 95 let iv = 96 let rec doit iv iv_off block block_off = 97 match Bytes.length block - block_off with 98 | 0 -> Bytes.sub iv iv_off block_size 99 | _ -> 100 cbc (Bytes.unsafe_to_string iv) iv_off block block_off; 101 (doit [@tailcall]) block block_off block (block_off + block_size) 102 in 103 doit (Bytes.make block_size '\x00') 0 cbcheader 0 104 in 105 106 let rec loop ctr src src_off dst dst_off len = 107 let cbcblock, cbc_off = 108 match mode with 109 | Encrypt -> (src, src_off) 110 | Decrypt -> (Bytes.unsafe_to_string dst, dst_off) 111 in 112 if len = 0 then () 113 else if len < block_size then begin 114 let buf = Bytes.make block_size '\x00' in 115 Bytes.unsafe_blit dst dst_off buf 0 len; 116 ctrblock ctr buf 0; 117 Bytes.unsafe_blit buf 0 dst dst_off len; 118 unsafe_xor_into src ~src_off dst ~dst_off len; 119 Bytes.unsafe_blit_string cbcblock cbc_off buf 0 len; 120 Bytes.unsafe_fill buf len (block_size - len) '\x00'; 121 cbc (Bytes.unsafe_to_string buf) 0 iv 0 122 end 123 else begin 124 ctrblock ctr dst dst_off; 125 unsafe_xor_into src ~src_off dst ~dst_off block_size; 126 cbc cbcblock cbc_off iv 0; 127 (loop [@tailcall]) (succ ctr) src (src_off + block_size) dst 128 (dst_off + block_size) (len - block_size) 129 end 130 in 131 loop 1 src src_off dst dst_off len; 132 iv 133 134let crypto_core ~cipher ~mode ~key ~nonce ~adata data = 135 let datalen = String.length data in 136 let dst = Bytes.create datalen in 137 let t = 138 crypto_core_into ~cipher ~mode ~key ~nonce ~adata data ~src_off:0 dst 139 ~dst_off:0 datalen 140 in 141 (dst, t) 142 143let crypto_t t nonce cipher key = 144 let ctr = gen_ctr nonce 0 in 145 cipher ~key (Bytes.unsafe_to_string ctr) ~src_off:0 ctr ~dst_off:0; 146 unsafe_xor_into 147 (Bytes.unsafe_to_string ctr) 148 ~src_off:0 t ~dst_off:0 (Bytes.length t) 149 150let unsafe_generation_encryption_into ~cipher ~key ~nonce ~adata src ~src_off 151 dst ~dst_off ~tag_off len = 152 let t = 153 crypto_core_into ~cipher ~mode:Encrypt ~key ~nonce ~adata src ~src_off dst 154 ~dst_off len 155 in 156 crypto_t t nonce cipher key; 157 Bytes.unsafe_blit t 0 dst tag_off block_size 158 159let unsafe_decryption_verification_into ~cipher ~key ~nonce ~adata src ~src_off 160 ~tag_off dst ~dst_off len = 161 let tag = String.sub src tag_off block_size in 162 let t = 163 crypto_core_into ~cipher ~mode:Decrypt ~key ~nonce ~adata src ~src_off dst 164 ~dst_off len 165 in 166 crypto_t t nonce cipher key; 167 Eqaf.equal tag (Bytes.unsafe_to_string t)