Library
Module
Module type
Parameter
Class
Class type
Eqaf - constant time / timing side channel resistant functions
In cryptography, a timing-attack is a side-channel attack in which the attacker attempts to compromise a cryptosystem by analyzing the time taken to execute cryptographic algorithms.
In some cases, a process needs to compare two values (input value and expected password). An attacker can analyze time needed by String.compare
/String.equal
to calculate expected password.
This side-channel attack is due implementation of String.compare
/String.equal
which leaves as soon as possible when it reachs a difference between a
and b
. By this way, time taken to compare two values differs if they are equal or not.
Distribution provides a little example of this kind of attack where we construct step by step (byte per byte) expected value from time spended to execute Stdlib.compare
.
Distribution wants to provide some functions which protect user against this kind of attack:
equal
like String.equal
compare_be
like String.compare
compare_le
which is a String.compare
with a reverse operation on inputsdivmod
like Int32.unsigned_div
and Int32.unsigned_rem
These functions are tested to see how long they took to compare two equal values and two different values. See check tool for more informations.
equal a b
returns true
if a
and b
are equals. String.equal a b =
equal a b
for any a
and b
. The execution time of equal
depends solely on the length of the strings, not the contents.
compare_be a b
returns 0
if a
is equal to b
, a negative integer if a
if less (lexicographically) than b
, and a positive integer if a
is greater (lexicographically) than b
.
compare_be a b
returns the same order than String.compare a b
for any a
and b
(but not necessary the same integer!). Order is defined as:
compare_be a b < 0
means a < b
compare_be a b > 0
means a > b
compare_be a b = 0
means a = b
About time, if String.length a <> String.length b
, compare_be
does not look into a
or b
and no comparison in bytes will be done.
compare_be_with_len ~len a b
does compare_be
a b
on len
bytes.
compare_le a b
is semantically compare_be (rev a) (rev b)
, where rev
is a function that reverses a string bytewise (a = rev (rev a)
).
compare_le_with_len a b
is semantically compare_be_with_len ~len (rev a)
(rev b)
. With rev
reverse a string (a = rev (rev a)
).
32-bit unsigned division with remainder, constant-time with respect to x
(not m
).
find_uint8 ?off ~f v
returns the index of the first occurrence which respects the predicate f
in string v
. Otherwise, it returns -1
. The caller is responsible for ensuring that ~f
operates in constant time. The bool_of_int
function can be relevant when writing ~f
functions.
exists_uint8 ?off ~f v
tests if an occurrence respects the predicate f
in the string v
.
ascii_of_int64 ~digits ~n
is a string consisting of the rightmost digits
characters of the decimal representation of n
. If digits
is larger than the decimal representation, it is left-padded with '0'
. If digits
is smaller, the output is truncated.
Example:
let s1 = ascii_of_int64 ~digits:6 ~n:12345678L in
assert (s = "345678") ;
let s2 = ascii_of_int64 ~digits:6 ~n:1234L in
assert (s = "001234") ;
lowercase_ascii str
is str
where A-Z
is replaced with a-z
. It is a constant time implementation of String.lowercase_ascii
uppercase_ascii str
is str
where a-z
is replaced with A-Z
. It is a constant time implementation of String.uppercase_ascii
hex_of_bytes raw
is raw
hex-encoded in constant time. Can be used to serialize sensitive values. The contents can be secret, but an attacker can learn the length of raw
by timing this function.
Hex has two valid forms, lowercase and uppercase. This function produces lowercase hex characters exclusively.
Example:
let secret = "--Hi\x24" in
let serialized = hex_of_string secret in
(* serialized is now "2d2d486924" *)
bytes_of_hex hex
is raw, error
decoded in constant time. Can be used to e.g. decode secrets from configuration files. The contents can be secret, but an attacker can learn the length of hex
by timing this function.
Error handling: The second tuple element error
is non-zero when the length of hex
is not a multiple of 2, or hex
contains invalid characters. Implementations should ensure that `error = 0` before using raw
. The function signals errors this way to allow implementations to handle invalid input errors in constant time.
string_of_hex hex
is bytes_of_hex
hex
, but returning a string
instead of bytes
. See bytes_of_hex
regarding handling of invalid input errors.
one_if_not_zero n
is a constant-time version of if n <> 0 then 1 else 0
. This is functionally equivalent to !!n
in the C programming language.
zero_if_not_zero n
is a constant-time of if n <> 0 then 0 else 1
. This is functionnaly equivalent to !n
in the C programming language.
int_of_bool b
is equivalent to if b then 1 else 0
. Internally it cast with %identity
instead of branching.
select_int choose_b a b
is a
if choose_b = 0
and b
otherwise. This comparison is constant-time and it should not be possible for a measuring adversary to determine anything about the values of choose_b
, a
, or b
.