Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ec] Handle K_gen correctly for bitlen mod 8 <> 0 #230

Merged
merged 2 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions ec/mirage_crypto_ec.ml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ module type Dsa = sig
type priv
type pub
val byte_length : int
val bit_length : int
val priv_of_octets : string -> (priv, error) result
val priv_to_octets : priv -> string
val pub_of_octets : string -> (pub, error) result
Expand Down Expand Up @@ -85,6 +86,7 @@ module type Parameters = sig
val n : field_element
val pident: string
val byte_length : int
val bit_length : int
val fe_length : int
val first_byte_bits : int option
end
Expand Down Expand Up @@ -600,6 +602,8 @@ module Make_dsa (Param : Parameters) (F : Fn) (P : Point) (S : Scalar) (H : Dige

let byte_length = Param.byte_length

let bit_length = Param.bit_length

let priv_of_octets= S.of_octets

let priv_to_octets = S.to_octets
Expand Down Expand Up @@ -628,14 +632,36 @@ module Make_dsa (Param : Parameters) (F : Fn) (P : Point) (S : Scalar) (H : Dige

let g ~key msg =
let g = Mirage_crypto_rng.create ~strict:true drbg in
Mirage_crypto_rng.reseed ~g
(S.to_octets key ^ msg);
Mirage_crypto_rng.reseed ~g (S.to_octets key ^ msg);
g

(* Defined in RFC 6979 sec 2.3.2 with
- blen = 8 * Param.byte_length
- qlen = Param.bit_length *)
let bits2int r =
(* keep qlen *leftmost* bits *)
let shift = (8 * Param.byte_length) - Param.bit_length in
if shift = 0 then
Bytes.unsafe_to_string r
else
(* Assuming shift is < 8 *)
let r' = Bytes.create Param.byte_length in
let p = ref 0x00 in
for i = 0 to Param.byte_length - 1 do
let x = Bytes.get_uint8 r i in
let v = (x lsr shift) lor (!p lsl (8 - shift)) in
p := x;
Bytes.set_uint8 r' i v
done;
Bytes.unsafe_to_string r'

(* take qbit length, and ensure it is suitable for ECDSA (> 0 & < n) *)
let gen g =
let rec go () =
let r = Mirage_crypto_rng.generate ~g Param.byte_length in
let b = Bytes.create Param.byte_length in
Mirage_crypto_rng.generate_into ~g b Param.byte_length;
(* truncate to the desired number of bits *)
let r = bits2int b in
if S.is_in_range r then r else go ()
in
go ()
Expand Down Expand Up @@ -758,6 +784,7 @@ module P256 : Dh_dsa = struct
let n = "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xBC\xE6\xFA\xAD\xA7\x17\x9E\x84\xF3\xB9\xCA\xC2\xFC\x63\x25\x51"
let pident = "\x3F\xFF\xFF\xFF\xC0\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" |> rev_string (* (Params.p + 1) / 4*)
let byte_length = 32
let bit_length = 256
let fe_length = 32
let first_byte_bits = None
end
Expand Down Expand Up @@ -809,6 +836,7 @@ module P384 : Dh_dsa = struct
let n = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC7\x63\x4D\x81\xF4\x37\x2D\xDF\x58\x1A\x0D\xB2\x48\xB0\xA7\x7A\xEC\xEC\x19\x6A\xCC\xC5\x29\x73"
let pident = "\x3F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xBF\xFF\xFF\xFF\xC0\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00" |> rev_string (* (Params.p + 1) / 4*)
let byte_length = 48
let bit_length = 384
let fe_length = 48
let first_byte_bits = None
end
Expand Down Expand Up @@ -861,6 +889,7 @@ module P521 : Dh_dsa = struct
let n = "\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFA\x51\x86\x87\x83\xBF\x2F\x96\x6B\x7F\xCC\x01\x48\xF7\x09\xA5\xD0\x3B\xB5\xC9\xB8\x89\x9C\x47\xAE\xBB\x6F\xB7\x1E\x91\x38\x64\x09"
let pident = "\x01\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" |> rev_string
let byte_length = 66
let bit_length = 521
let fe_length = if Sys.word_size == 64 then 72 else 68 (* TODO: is this congruent with C code? *)
let first_byte_bits = Some 0x01
end
Expand Down
3 changes: 3 additions & 0 deletions ec/mirage_crypto_ec.mli
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ module type Dsa = sig
val byte_length : int
(** [byte_length] is the size of a ECDSA signature in bytes. *)

val bit_length : int
(** [bit_length] is the number of significant bits in a ECDSA signature *)

(** {2 Serialisation} *)

val priv_of_octets : string -> (priv, error) result
Expand Down
8 changes: 4 additions & 4 deletions tests/test_ec.ml
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ let ecdsa_rfc6979_p521 =
let sig' = P521.Dsa.sign ~key:priv ~k msg in
Alcotest.(check bool __LOC__ true (sig_eq sig'))
in
let _cases = [
let cases = [

case Digestif.sha1 ~message:"sample"
~k:"089C071B419E1C2820962321787258469511958E80582E95D8378E0C2CCDB3CB
Expand Down Expand Up @@ -624,9 +624,9 @@ let ecdsa_rfc6979_p521 =
CE3"

] in
[ ("public key matches", `Quick, pub_rfc); ("public key compression and decompression", `Quick, pub_key_compression)]
(* TODO: our deterministic generator for bit_size mod 8 <> 0 is different from RFC 6979 *)
(* List.mapi (fun i c -> "RFC 6979 A.2.7 " ^ string_of_int i, `Quick, c) cases *)
("public key matches", `Quick, pub_rfc) ::
("public key compression and decompression", `Quick, pub_key_compression) ::
List.mapi (fun i c -> "RFC 6979 A.2.7 " ^ string_of_int i, `Quick, c) cases

let x25519 () =
(* RFC 7748, 6.1 *)
Expand Down
Loading