From 395a75390e3d422faa9007f56b7604750b7b3cf4 Mon Sep 17 00:00:00 2001 From: swrup Date: Thu, 5 Feb 2026 18:24:43 +0100 Subject: [PATCH] ~ Bin_rsa --- src/crypto.ml | 116 ++++++++++++++++++++++++++++++++++++++++++++------ src/util.ml | 111 ----------------------------------------------- 2 files changed, 103 insertions(+), 124 deletions(-) diff --git a/src/crypto.ml b/src/crypto.ml index 3849c761..bf437fce 100644 --- a/src/crypto.ml +++ b/src/crypto.ml @@ -1,3 +1,100 @@ +open Syntax + +module Binary_format_rsa = struct + (* TODO tests: + - need to strip leading zeros? + - endianess ok? *) + (* RSA public key binary format + https://www.gnupg.org/documentation/manuals/gcrypt/MPI-formats.html + := { uint16_be: n size; uint16_be: e size; n; e} + + integer in big-endian format (MSB first) + leading zeroes are stripped unless they are required to keep a value positive + no 0-termination *) + + let rev_string len s = String.init len (fun i -> s.[len - 1 - i]) + + (* we reverse bytes because Z.of_bits reads bytes in little endian *) + let z_of_bits_be src pos len = + String.sub src pos len |> rev_string len |> Z.of_bits + + let z_to_bits_be z = + let bits = Z.to_bits z in + rev_string (String.length bits) bits + + let z_array_to_octets (arr : Z.t array) = + let nb = Array.length arr in + let bits_arr = Array.map z_to_bits_be arr in + let len_arr = Array.map String.length bits_arr in + let len = (2 * nb) + Array.fold_left ( + ) 0 len_arr in + let b = Bytes.make len '\x00' in + let pos = ref 0 in + Array.iter + (fun len -> + Bytes.set_uint16_be b !pos len; + pos := !pos + 2) + len_arr; + Array.iteri + (fun i bits -> + let len = len_arr.(i) in + Bytes.blit_string bits 0 b !pos len; + pos := !pos + len) + bits_arr; + Bytes.unsafe_to_string b + + let check = function + | false -> Error "rsa of_octets error, invalid data" + | true -> Ok () + + let z_array_of_octets ~nb s = + let s_len = String.length s in + let* () = check (s_len > 2 * nb) in + let pos = ref 0 in + let len_arr = + Array.init nb (fun _i -> + let len = String.get_uint16_be s !pos in + pos := !pos + 2; + len) + in + let* () = + let len = (2 * nb) + Array.fold_left ( + ) 0 len_arr in + check (s_len = len) + in + let z_arr = + Array.init nb (fun i -> + let len = len_arr.(i) in + let z = z_of_bits_be s !pos len in + pos := !pos + len; + z) + in + Ok z_arr + + let pub_to_octets ({ n; e } : Mirage_crypto_pk.Rsa.pub) = + z_array_to_octets [| n; e |] + + let pub_of_octets s = + let* arr = z_array_of_octets ~nb:2 s in + match arr with + | [| n; e |] -> + let+ pub = Mirage_crypto_pk.Rsa.pub ~n ~e |> unwrap_err_msg in + pub + | _ -> assert false + + let priv_to_octets ({ e; d; n; p; q; dp; dq; q' } : Mirage_crypto_pk.Rsa.priv) + = + z_array_to_octets [| e; d; n; p; q; dp; dq; q' |] + + let priv_of_octets s = + let* arr = z_array_of_octets ~nb:8 s in + match arr with + | [| e; d; n; p; q; dp; dq; q' |] -> + let+ priv = + Mirage_crypto_pk.Rsa.priv ~e ~d ~n ~p ~q ~dp ~dq ~q' |> unwrap_err_msg + in + priv + | _ -> assert false +end + (* TODO key format - check what is the exact format in GNUNET - endianess issue? *) @@ -17,13 +114,10 @@ module EddsaPublicKey = struct | Ok v -> Ok v let bin = - let of_octets o = - match of_octets o with Error e -> raise (Util.Bin_error e) | Ok v -> v - in - Bin.map (Bin.bytes 32) of_octets to_octets + let of_octets_exn t = of_octets t |> Result.get_ok in + Bin.map (Bin.bytes 32) of_octets_exn to_octets let of_b32 s = - let open Syntax in let* octets = B32.decode s in let* pub = of_octets octets in Ok pub @@ -62,7 +156,6 @@ module EddsaPrivateKey = struct let jsont = let of_b32 s = - let open Syntax in let* octets = B32.decode s in of_octets octets in @@ -117,7 +210,6 @@ end = struct let jsont = let of_b32 s = - let open Syntax in let* t = B32.decode s in let+ () = check_size t in t @@ -137,12 +229,11 @@ module RsaPublicKey = struct type t = Rsa.pub - let to_octets = Util.Bin_rsa.pub_to_octets - let of_octets = Util.Bin_rsa.pub_of_octets + let to_octets = Binary_format_rsa.pub_to_octets + let of_octets = Binary_format_rsa.pub_of_octets let jsont = let of_b32 s = - let open Syntax in let* s = B32.decode s in let+ v = of_octets s in v @@ -168,12 +259,11 @@ module RsaPrivateKey = struct (priv, pub) let pub_of_priv = pub_of_priv - let of_octets = Util.Bin_rsa.priv_of_octets - let to_octets = Util.Bin_rsa.priv_to_octets + let of_octets = Binary_format_rsa.priv_of_octets + let to_octets = Binary_format_rsa.priv_to_octets let jsont = let of_b32 s = - let open Syntax in let* s = B32.decode s in let+ v = of_octets s in v diff --git a/src/util.ml b/src/util.ml index 5d6bac8e..c690a009 100644 --- a/src/util.ml +++ b/src/util.ml @@ -1,114 +1,3 @@ -exception Bin_error of string - -(* TODO bin - - no [Bin.of_string] ? *) -let bin_of_string bin s = - let v = Bin.decode bin s (ref 0) in - Ok v - -module Bin_rsa = struct - (* TODO - - need to strip leading zeros? - - endianess ok? - - tests *) - (* RSA public key binary format - https://www.gnupg.org/documentation/manuals/gcrypt/MPI-formats.html - := { uint16_be: n size; uint16_be: e size; n; e} - - integer in big-endian format (MSB first) - leading zeroes are stripped unless they are required to keep a value positive - no 0-termination *) - (* RSA private key custom format is inspired by the public rsa key format - used by secmod to save private key to file *) - open Syntax - - module Internal = struct - let rev_string len s = String.init len (fun i -> s.[len - 1 - i]) - - (* we need reverse bytes because Z.of_bits reads bytes in little endian *) - let z_of_bits_be src pos len = - String.sub src pos len |> rev_string len |> Z.of_bits - - let z_to_bits_be z = - let bits = Z.to_bits z in - rev_string (String.length bits) bits - - let z_array_to_octets (arr : Z.t array) = - let nb = Array.length arr in - let bits_arr = Array.map z_to_bits_be arr in - let len_arr = Array.map String.length bits_arr in - let len = (2 * nb) + Array.fold_left ( + ) 0 len_arr in - let b = Bytes.make len '\x00' in - let pos = ref 0 in - Array.iter - (fun len -> - Bytes.set_uint16_be b !pos len; - pos := !pos + 2) - len_arr; - Array.iteri - (fun i bits -> - let len = len_arr.(i) in - Bytes.blit_string bits 0 b !pos len; - pos := !pos + len) - bits_arr; - Bytes.unsafe_to_string b - - let check = function - | false -> Error "rsa of_octets error, invalid data" - | true -> Ok () - - let z_array_of_octets ~nb s = - let s_len = String.length s in - let* () = check (s_len > 2 * nb) in - let pos = ref 0 in - let len_arr = - Array.init nb (fun _i -> - let len = String.get_uint16_be s !pos in - pos := !pos + 2; - len) - in - let* () = - let len = (2 * nb) + Array.fold_left ( + ) 0 len_arr in - check (s_len = len) - in - let z_arr = - Array.init nb (fun i -> - let len = len_arr.(i) in - let z = z_of_bits_be s !pos len in - pos := !pos + len; - z) - in - Ok z_arr - end - - open Internal - - let pub_to_octets ({ n; e } : Mirage_crypto_pk.Rsa.pub) = - z_array_to_octets [| n; e |] - - let pub_of_octets s = - let* arr = z_array_of_octets ~nb:2 s in - match arr with - | [| n; e |] -> - let+ pub = Mirage_crypto_pk.Rsa.pub ~n ~e |> unwrap_err_msg in - pub - | _ -> assert false - - let priv_to_octets ({ e; d; n; p; q; dp; dq; q' } : Mirage_crypto_pk.Rsa.priv) - = - z_array_to_octets [| e; d; n; p; q; dp; dq; q' |] - - let priv_of_octets s = - let* arr = z_array_of_octets ~nb:8 s in - match arr with - | [| e; d; n; p; q; dp; dq; q' |] -> - let+ priv = - Mirage_crypto_pk.Rsa.priv ~e ~d ~n ~p ~q ~dp ~dq ~q' |> unwrap_err_msg - in - priv - | _ -> assert false -end - module Log_reporter = struct let detail_tag : string Logs.Tag.def = Logs.Tag.def "Detail tag" ~doc:"" Fmt.string