1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
module V = struct
  type nc_pub =
    | RSA_pub of Nocrypto.Rsa.pub

  let good_rsa p = Nocrypto.Rsa.pub_bits p >= 2048

  let encode_key = function
    | RSA_pub pub -> String.trim (Cstruct.to_string (X509.Encoding.Pem.Public_key.to_pem_cstruct1 (`RSA pub)))

  let decode_key data =
    match X509.Encoding.Pem.Public_key.of_pem_cstruct (Cstruct.of_string data) with
    | [ `RSA pub ] -> Some (RSA_pub pub)
    | _ -> None

  module Pss_sha256 = Nocrypto.Rsa.PSS (Nocrypto.Hash.SHA256)

  let verify_rsa_pss ~key ~data ~signature =
    match Nocrypto.Base64.decode (Cstruct.of_string signature) with
    | None -> Error `InvalidBase64Encoding
    | Some signature ->
      let cs_data = Cstruct.of_string data in
      match decode_key key with
      | Some (RSA_pub key) when good_rsa key ->
        if Pss_sha256.verify ~key ~signature cs_data then
          Ok ()
        else
          Error `InvalidSignature
      | _ -> Error `InvalidPublicKey

  let b64sha256 data =
    let cs = Cstruct.of_string data in
    let check = Nocrypto.Hash.digest `SHA256 cs in
    let b64 = Nocrypto.Base64.encode check in
    Cstruct.to_string b64
end

module C = struct
  type nc_priv =
    | RSA_priv of Nocrypto.Rsa.priv

  let decode_priv data =
    match X509.Encoding.Pem.Private_key.of_pem_cstruct (Cstruct.of_string data) with
    | [ `RSA priv ] -> Some (RSA_priv priv)
    | _ -> None

  let encode_priv = function
    | RSA_priv priv ->
      let pem = X509.Encoding.Pem.Private_key.to_pem_cstruct1 (`RSA priv) in
      Cstruct.to_string pem

  let generate_rsa ?(bits = 4096) () =
    let key = RSA_priv (Nocrypto.Rsa.generate bits) in
    encode_priv key

  let bits_rsa k =
    match V.decode_key k with
    | None -> Error "couldn't decode key"
    | Some (V.RSA_pub pub) -> Ok (Nocrypto.Rsa.pub_bits pub)

  let pub_of_priv_rsa k =
    match decode_priv k with
    | Some (RSA_priv k) ->
      let pub = Nocrypto.Rsa.pub_of_priv k in
      let pem = V.encode_key (V.RSA_pub pub) in
      Ok pem
    | None -> Error "couldn't decode private key"

  let primitive_sign priv data =
    let cs = Cstruct.of_string data in
    let signature =
      match priv with
      | RSA_priv key -> V.Pss_sha256.sign ~key cs
    in
    let b64 = Nocrypto.Base64.encode signature in
    Cstruct.to_string b64

  let sign_rsa_pss ~key data =
    match decode_priv key with
    | Some key -> Ok (primitive_sign key data)
    | None -> Error "couldn't decode private key"
end

module NC_S = Conex_crypto.Make_sign (C)
module NC_V = Conex_crypto.Make_verify (V)