224 lines
7.9 KiB
OCaml
224 lines
7.9 KiB
OCaml
(** {1 Elliptic curve cryptography} *)
|
|
|
|
(** Mirage-crypto-ec implements public key cryptography with named elliptic
|
|
curves. Ephemeral key exchanges with {{!Dh}Diffie-Hellman} and
|
|
{{!Dsa}digital signatures (ECDSA)} are implemented.
|
|
|
|
The arithmetic operations uses code generated by
|
|
{{:https://github.com/mit-plv/fiat-crypto}fiat-crypto} which is proven to
|
|
consume a constant amount of time, independent of the input values.
|
|
*)
|
|
|
|
type error = [
|
|
| `Invalid_range
|
|
| `Invalid_format
|
|
| `Invalid_length
|
|
| `Not_on_curve
|
|
| `At_infinity
|
|
| `Low_order
|
|
]
|
|
(** The type for errors. *)
|
|
|
|
val pp_error : Format.formatter -> error -> unit
|
|
(** Pretty printer for errors *)
|
|
|
|
exception Message_too_long
|
|
(** Raised if the provided message is too long for the curve. *)
|
|
|
|
(** Diffie-Hellman key exchange. *)
|
|
module type Dh = sig
|
|
|
|
type secret
|
|
(** Type for private keys. *)
|
|
|
|
val secret_of_octets : ?compress:bool -> string ->
|
|
(secret * string, error) result
|
|
(** [secret_of_octets ~compress secret] decodes the provided buffer as
|
|
{!secret}. If [compress] is provided and [true] (defaults to [false]),
|
|
the shared part will be compressed. May result in an error if the buffer
|
|
had an invalid length or was not in bounds. *)
|
|
|
|
val secret_to_octets : secret -> string
|
|
(** [secret_to_octets secret] encodes the provided secret into a freshly
|
|
allocated buffer. *)
|
|
|
|
val gen_key : ?compress:bool -> ?g:Mirage_crypto_rng.g -> unit ->
|
|
secret * string
|
|
(** [gen_key ~compress ~g ()] generates a private and a public key for
|
|
Ephemeral Diffie-Hellman. If [compress] is provided and [true] (defaults
|
|
to [false]), the shared part will be compressed. The returned key pair
|
|
MUST only be used for a single key exchange.
|
|
|
|
The generated private key is checked to be greater than zero and lower
|
|
than the group order meaning the public key cannot be the point at
|
|
inifinity. *)
|
|
|
|
val key_exchange : secret -> string -> (string, error) result
|
|
(** [key_exchange secret received_public_key] performs Diffie-Hellman key
|
|
exchange using your secret and the data received from the other party.
|
|
Returns the shared secret or an error if the received data is wrongly
|
|
encoded, doesn't represent a point on the curve or represent the point
|
|
at infinity.
|
|
|
|
The shared secret is returned as is i.e. not stripped from leading 0x00
|
|
bytes.
|
|
|
|
The public key encoding is described
|
|
{{:http://www.secg.org/sec1-v2.pdf}in SEC 1} from SECG. *)
|
|
end
|
|
|
|
(** Digital signature algorithm. *)
|
|
module type Dsa = sig
|
|
|
|
type priv
|
|
(** The type for private keys. *)
|
|
|
|
type pub
|
|
(** The type for public keys. *)
|
|
|
|
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
|
|
(** [priv_of_octets buf] decodes a private key from the buffer [buf]. If the
|
|
provided data is invalid, an error is returned. *)
|
|
|
|
val priv_to_octets : priv -> string
|
|
(** [priv_to_octets p] encode the private key [p] to a buffer. *)
|
|
|
|
val pub_of_octets : string -> (pub, error) result
|
|
(** [pub_of_octets buf] decodes a public key from the buffer [buf]. If the
|
|
provided data is invalid, an error is returned. *)
|
|
|
|
val pub_to_octets : ?compress:bool -> pub -> string
|
|
(** [pub_to_octets ~compress p] encodes the public key [p] into a buffer.
|
|
If [compress] is provided and [true] (default [false]), the compressed
|
|
representation is returned. *)
|
|
|
|
(** {2 Deriving the public key} *)
|
|
|
|
val pub_of_priv : priv -> pub
|
|
(** [pub_of_priv p] extracts the public key from the private key [p]. *)
|
|
|
|
(** {2 Key generation} *)
|
|
|
|
val generate : ?g:Mirage_crypto_rng.g -> unit -> priv * pub
|
|
(** [generate ~g ()] generates a key pair. *)
|
|
|
|
(** {2 Cryptographic operations} *)
|
|
|
|
val sign : key:priv -> ?k:string -> string -> string * string
|
|
(** [sign ~key ~k digest] signs the message [digest] using the private
|
|
[key]. The [digest] is not processed further - it should be the hash of
|
|
the message to sign. If [k] is not provided, it is computed using the
|
|
deterministic construction from RFC 6979. The result is a pair of [r]
|
|
and [s].
|
|
|
|
Warning: there {{:https://www.hertzbleed.com/2h2b.pdf}are}
|
|
{{:https://www.hertzbleed.com/hertzbleed.pdf}attacks} that recover the
|
|
private key from a power and timing analysis of the RFC 6979 computation
|
|
of [k] - thus it is advised to provide a good nonce ([k]) explicitly,
|
|
which is independent of key and digest.
|
|
|
|
@raise Invalid_argument if [k] is not suitable or not in range.
|
|
@raise Message_too_long if the bit size of [msg] exceeds the curve. *)
|
|
|
|
val verify : key:pub -> string * string -> string -> bool
|
|
(** [verify ~key (r, s) digest] verifies the signature [r, s] on the message
|
|
[digest] with the public [key]. The return value is [true] if verification
|
|
was successful, [false] otherwise. If the message has more bits than the
|
|
group order, the result is false. *)
|
|
|
|
(** [K_gen] can be instantiated over a hashing module to obtain an RFC6979
|
|
compliant [k]-generator for that hash. *)
|
|
module K_gen (H : Digestif.S) : sig
|
|
|
|
val generate : key:priv -> string -> string
|
|
(** [generate ~key digest] deterministically takes the given private key
|
|
and message digest to a [k] suitable for seeding the signing process. *)
|
|
end
|
|
|
|
(** {2 Misc} *)
|
|
|
|
(** Operations to precompute useful data meant to be hardcoded in
|
|
[mirage-crypto-ec] before compilation *)
|
|
module Precompute : sig
|
|
val generator_tables : unit -> string array array array
|
|
(** Return an array of shape (Fe_length * 2, 15, 3) containing multiples of
|
|
the generator point for the curve. Useful only to bootstrap tables
|
|
necessary for scalar multiplication. *)
|
|
end
|
|
end
|
|
|
|
(** Elliptic curve with Diffie-Hellman and DSA. *)
|
|
module type Dh_dsa = sig
|
|
|
|
(** Diffie-Hellman key exchange. *)
|
|
module Dh : Dh
|
|
|
|
(** Digital signature algorithm. *)
|
|
module Dsa : Dsa
|
|
end
|
|
|
|
(** The NIST P-256 curve, also known as SECP256R1. *)
|
|
module P256 : Dh_dsa
|
|
|
|
(** The NIST P-384 curve, also known as SECP384R1. *)
|
|
module P384 : Dh_dsa
|
|
|
|
(** The NIST P-521 curve, also known as SECP521R1. *)
|
|
module P521 : Dh_dsa
|
|
|
|
(** Curve 25519 Diffie-Hellman, also known as X25519. *)
|
|
module X25519 : Dh
|
|
|
|
(** Curve 25519 DSA, also known as Ed25519. *)
|
|
module Ed25519 : sig
|
|
type priv
|
|
(** The type for private keys. *)
|
|
|
|
type pub
|
|
(** The type for public keys. *)
|
|
|
|
(** {2 Serialisation} *)
|
|
|
|
val priv_of_octets : string -> (priv, error) result
|
|
(** [priv_of_octets buf] decodes a private key from the buffer [buf]. If the
|
|
provided data is invalid, an error is returned. *)
|
|
|
|
val priv_to_octets : priv -> string
|
|
(** [priv_to_octets p] encode the private key [p] to a buffer. *)
|
|
|
|
val pub_of_octets : string -> (pub, error) result
|
|
(** [pub_of_octets buf] decodes a public key from the buffer [buf]. If the
|
|
provided data is invalid, an error is returned. *)
|
|
|
|
val pub_to_octets : pub -> string
|
|
(** [pub_to_octets p] encodes the public key [p] into a buffer. *)
|
|
|
|
(** {2 Deriving the public key} *)
|
|
|
|
val pub_of_priv : priv -> pub
|
|
(** [pub_of_priv p] extracts the public key from the private key [p]. *)
|
|
|
|
(** {2 Key generation} *)
|
|
|
|
val generate : ?g:Mirage_crypto_rng.g -> unit -> priv * pub
|
|
(** [generate ~g ()] generates a key pair. *)
|
|
|
|
(** {2 Cryptographic operations} *)
|
|
|
|
val sign : key:priv -> string -> string
|
|
(** [sign ~key msg] signs the message [msg] using the private [key]. The
|
|
result is the concatenation of [r] and [s], as specified in RFC 8032. *)
|
|
|
|
val verify : key:pub -> string -> msg:string -> bool
|
|
(** [verify ~key signature msg] verifies the [signature] on the message
|
|
[msg] with the public [key]. The return value is [true] if verification
|
|
was successful, [false] otherwise. *)
|
|
end
|