upstream: https://github.com/mirage/mirage-crypto
at main 177 lines 5.7 kB view raw
1open Crypto.Uncommon 2open Common 3open Result.Syntax 4 5type pub = { p : Z.t; q : Z.t; gg : Z.t; y : Z.t } 6 7let pub ?(fips = false) ~p ~q ~gg ~y () = 8 let* () = guard Z.(one < gg && gg < p) (`Msg "bad generator") in 9 let* () = guard (Z_extra.pseudoprime q) (`Msg "q is not prime") in 10 let* () = 11 guard (Z.is_odd p && Z_extra.pseudoprime p) (`Msg "p is not prime") 12 in 13 let* () = guard Z.(zero < y && y < p) (`Msg "y not in 0..p-1") in 14 let* () = guard (q < p) (`Msg "q is not smaller than p") in 15 let* () = guard Z.(zero = pred p mod q) (`Msg "p - 1 mod q <> 0") in 16 let* () = 17 if fips then 18 match (Z.numbits p, Z.numbits q) with 19 | 1024, 160 | 2048, 224 | 2048, 256 | 3072, 256 -> Ok () 20 | _ -> Error (`Msg "bit length of p or q not FIPS specified") 21 else Ok () 22 in 23 Ok { p; q; gg; y } 24 25type priv = { p : Z.t; q : Z.t; gg : Z.t; x : Z.t; y : Z.t } 26 27let priv ?fips ~p ~q ~gg ~x ~y () = 28 let* _ = pub ?fips ~p ~q ~gg ~y () in 29 let* () = guard Z.(zero < x && x < q) (`Msg "x not in 1..q-1") in 30 let* () = guard Z.(y = powm gg x p) (`Msg "y <> g ^ x mod p") in 31 Ok { p; q; gg; x; y } 32 33let pub_of_priv { p; q; gg; y; _ } = { p; q; gg; y } 34 35type keysize = [ `Fips1024 | `Fips2048 | `Fips3072 | `Exactly of int * int ] 36 37let expand_size = function 38 | `Fips1024 -> (1024, 160) 39 | `Fips2048 -> (2048, 256) 40 | `Fips3072 -> (3072, 256) 41 | `Exactly (l, n) -> 42 if 3 <= l && 2 <= n then (l, n) 43 else invalid_arg "Dsa.generate: bits: `Exactly (%d, %d)" l n 44 45type mask = [ `No | `Yes | `Yes_with of Crypto_rng.g ] 46 47let expand_mask = function 48 | `No -> `No 49 | `Yes -> `Yes None 50 | `Yes_with g -> `Yes (Some g) 51 52(* 53 * FIPS.186-4-style derivation: 54 * - p and q are derived using a method numerically like the one described in 55 * A.1.1.2, adapted to use the native rng. 56 * - g is derived as per A.2.1. 57 *) 58let params ?g size = 59 let two = Z.(~$2) in 60 let l, n = expand_size size in 61 let q = Z_extra.prime ?g ~msb:1 n in 62 let p = 63 let q_q = Z.(q * two) in 64 until Z_extra.pseudoprime @@ fun () -> 65 let x = Z_extra.gen_bits ?g ~msb:1 l in 66 Z.(x - (x mod q_q) + one) 67 in 68 let gg = 69 let e = Z.(pred p / q) in 70 until (( <> ) Z.one) @@ fun () -> 71 let h = Z_extra.gen_r ?g two Z.(pred p) in 72 Z.(powm h e p) 73 in 74 (* all checks above are already satisfied *) 75 (p, q, gg) 76 77let generate ?g size = 78 let p, q, gg = params ?g size in 79 let x = Z_extra.gen_r ?g Z.one q in 80 let y = Z.(powm gg x p) in 81 (* checks are satisfied due to construction *) 82 { p; q; gg; x; y } 83 84module K_gen (H : Digestif.S) = struct 85 let drbg : 'a Crypto_rng.generator = 86 let module M = Crypto_rng.Hmac_drbg (H) in 87 (module M) 88 89 let z_gen ~key:{ q; x; _ } z = 90 let repr = Z_extra.to_octets_be ~size:(Z.numbits q // 8) in 91 let g = Crypto_rng.v ~strict:true drbg in 92 Crypto_rng.reseed ~g (repr x ^ repr Z.(z mod q)); 93 Z_extra.gen_r ~g Z.one q 94 95 let generate ~key buf = 96 z_gen ~key (Z_extra.of_octets_be ~bits:(Z.numbits key.q) buf) 97end 98 99module K_gen_sha256 = K_gen (Digestif.SHA256) 100 101let sign_z ?(mask = `Yes) ?k:k0 ~key:({ p; q; gg; x; _ } as key) z = 102 let k = match k0 with Some k -> k | None -> K_gen_sha256.z_gen ~key z in 103 let k' = Z.invert k q 104 and b, b' = 105 match expand_mask mask with 106 | `No -> (Z.one, Z.one) 107 | `Yes g -> 108 let m = Z_extra.gen_r ?g Z.one q in 109 (m, Z.invert m q) 110 in 111 let r = Z.(powm_sec gg k p mod q) in 112 (* normal DSA sign is: s = k^-1 * (z + r * x) mod q *) 113 (* we apply blinding where possible and compute: 114 s = k^-1 * b^-1 * (b * z + b * r * x) mod q 115 see https://github.com/openssl/openssl/pull/6524 for further details *) 116 let s = 117 let t1 = 118 let t11 = Z.(b * x mod q) in 119 Z.(t11 * r mod q) 120 in 121 let t2 = Z.(b * z mod q) in 122 let t3 = Z.((t1 + t2) mod q) in 123 let t4 = Z.(k' * t3 mod q) in 124 Z.(b' * t4 mod q) 125 in 126 if r = Z.zero || s = Z.zero then invalid_arg "k unsuitable" else (r, s) 127 128let verify_z ~key:({ p; q; gg; y } : pub) (r, s) z = 129 let v () = 130 let w = Z.invert s q in 131 let u1 = Z.(z * w mod q) and u2 = Z.(r * w mod q) in 132 Z.(powm gg u1 p * powm y u2 p mod p mod q) 133 in 134 Z.zero < r && r < q && Z.zero < s && s < q && v () = r 135 136let sign ?mask ?k ~(key : priv) digest = 137 let bits = Z.numbits key.q in 138 let size = bits // 8 in 139 let r, s = sign_z ?mask ?k ~key (Z_extra.of_octets_be ~bits digest) in 140 Z_extra.(to_octets_be ~size r, to_octets_be ~size s) 141 142let verify ~(key : pub) (r, s) digest = 143 let z = Z_extra.of_octets_be ~bits:(Z.numbits key.q) digest 144 and r, s = Z_extra.(of_octets_be r, of_octets_be s) in 145 verify_z ~key (r, s) z 146 147let rec shift_left_inplace buf = function 148 | 0 -> () 149 | bits when bits mod 8 = 0 -> 150 let off = bits / 8 in 151 let to_blit = Bytes.length buf - off in 152 Bytes.unsafe_blit buf off buf 0 to_blit; 153 Bytes.unsafe_fill buf to_blit (Bytes.length buf - to_blit) '\x00' 154 | bits when bits < 8 -> 155 let foo = 8 - bits in 156 for i = 0 to Bytes.length buf - 2 do 157 let b1 = Bytes.get_uint8 buf i and b2 = Bytes.get_uint8 buf (i + 1) in 158 Bytes.set_uint8 buf i ((b1 lsl bits) lor (b2 lsr foo)) 159 done; 160 Bytes.set_uint8 buf 161 (Bytes.length buf - 1) 162 (Bytes.get_uint8 buf (Bytes.length buf - 1) lsl bits) 163 | bits -> 164 shift_left_inplace buf (8 * (bits / 8)); 165 shift_left_inplace buf (bits mod 8) 166 167let ( lsl ) buf bits = 168 let buf' = Bytes.of_string buf in 169 shift_left_inplace buf' bits; 170 Bytes.unsafe_to_string buf' 171 172let massage ~key:({ q; _ } : pub) digest = 173 let bits = Z.numbits q in 174 if bits >= String.length digest * 8 then digest 175 else 176 let buf = Z_extra.(to_octets_be Z.(of_octets_be digest mod q)) in 177 buf lsl ((8 - (bits mod 8)) mod 8)