(* $Id: netauth.ml 1543 2011-02-08 02:08:35Z gerd $ *) let xor_s s u = let s_len = String.length s in let u_len = String.length u in assert(s_len = u_len); let x = String.create s_len in for k = 0 to s_len-1 do x.[k] <- Char.chr ((Char.code s.[k]) lxor (Char.code u.[k])) done; x let hmac ~h ~b ~l ~k ~message = if String.length k > b then failwith "Netauth.hmac: key too long"; let k_padded = k ^ String.make (b - String.length k) '\000' in let ipad = String.make b '\x36' in let opad = String.make b '\x5c' in h((xor_s k_padded opad) ^ (h ((xor_s k_padded ipad) ^ message))) let add_1_complement s1 s2 = (* Add two bitstrings s1 and s2 (in big-endian order) with one's complement addition *) let l1 = String.length s1 in let l2 = String.length s2 in if l1 <> l2 then invalid_arg "Netauth.add_1_complement"; let r = String.make l1 '\000' in let carry = ref 0 in for k = l1-1 downto 0 do let i1 = Char.code s1.[k] in let i2 = Char.code s2.[k] in let sum = i1 + i2 + !carry in r.[k] <- Char.chr (sum land 0xff); carry := if sum > 0xff then 1 else 0; done; if !carry > 0 then ( for k = l1-1 downto 0 do let i = Char.code r.[k] in let sum = i + !carry in r.[k] <- Char.chr (sum land 0xff); carry := if sum > 0xff then 1 else 0; done ); r let rotate_right n s = (* Rotate the (big-endian) bitstring s to the right by n bits *) let l = String.length s in let b = 8 * l in (* bit length of s *) let n' = n mod b in let n' = if n' < 0 then b+n' else n' in let u = String.create l in (* First byte-shift the string, then bit-shift the remaining 0-7 bits *) let bytes = n' lsr 3 in let bits = n' land 7 in String.blit s 0 u bytes (l-bytes); if bytes > 0 then String.blit s (l-bytes) u 0 bytes; let mask = match bits with | 0 -> 0 | 1 -> 1 | 2 -> 3 | 3 -> 7 | 4 -> 15 | 5 -> 31 | 6 -> 63 | 7 -> 127 | _ -> assert false in let carry = ref 0 in if bits > 0 && l > 0 then ( for k = 0 to l-1 do let x = Char.code u.[k] in u.[k] <- Char.chr ((x lsr bits) lor (!carry lsl (8-bits))); carry := x land mask; done; u.[0] <- Char.chr((Char.code u.[0]) lor (!carry lsl (8-bits))); ); u let n_fold n s = (** n-fold the number given by the bitstring s. The length of the number is taken as the byte-length of s. n must be divisible by 8. *) if n=0 || n mod 8 <> 0 then invalid_arg "Netauth.n_fold"; let p = n / 8 in let buf = Buffer.create (String.length s) in let rec add_rot u len = if len > 0 && len mod p = 0 then () else ( Buffer.add_string buf u; add_rot (rotate_right 13 u) (len+String.length u) ) in add_rot s 0; let blen = Buffer.length buf in let s = ref (Buffer.sub buf 0 p) in for k = 1 to (blen / p) - 1 do s := add_1_complement !s (Buffer.sub buf (k*p) p) done; !s type key_type = [ `Kc | `Ke | `Ki ] let k_truncate k s = let b = k/8 in String.sub s 0 b let derive_key_rfc3961_simplified ~encrypt ~random_to_key ~block_size ~k ~usage ~key_type = if block_size < 40 then invalid_arg "Netauth.derive_key_rfc3961: bad block_size"; if k <= 0 || k mod 8 <> 0 then invalid_arg "Netauth.derive_key_rfc3961: bad k"; if usage < 0 || usage > 255 then invalid_arg "Netauth.derive_key_rfc3961: bad usage (only 0-255 allowed)"; let usage_s = String.make 3 '\000' ^ String.make 1 (Char.chr usage) ^ (match key_type with | `Kc -> "\x99" | `Ke -> "\xaa" | `Ki -> "\x55" ) in let usage_exp = n_fold block_size usage_s in let kbuf = Buffer.create 80 in let ki = ref (encrypt usage_exp) in Buffer.add_string kbuf !ki; while 8*(Buffer.length kbuf) < k do ki := encrypt !ki; Buffer.add_string kbuf !ki done; let derived_random = k_truncate k (Buffer.contents kbuf) in random_to_key derived_random