Skip to content
Open
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
25 changes: 15 additions & 10 deletions ConstantTime.xs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@



static int do_compare(unsigned char *a, unsigned char *b, size_t n) {
static int do_compare(unsigned char *a, size_t a_len, unsigned char *b, size_t b_len) {
size_t i;
unsigned char r = 0;

for (i = 0; i < n; i++) {
r |= *a++ ^ *b++;
unsigned char *s;
unsigned char r;
uintptr_t mask;

/* Orchestrate a dummy compare which never matches and whose run-time does
* not stand out if a_len != b_len */
r = (a_len != b_len);
/* Branching-less: s = (r) ? b : a */
mask = (uintptr_t)0u - r;
s = (unsigned char *)(((uintptr_t)b & mask) | ((uintptr_t)a & ~mask));

for (i = 0; i < b_len; i++) {
r |= *s++ ^ *b++;
Comment thread
ppisar marked this conversation as resolved.
}

return r;
Expand Down Expand Up @@ -41,11 +50,7 @@ equals(a, b)
ap = SvPV(a, alen);
bp = SvPV(b, blen);

if (alen == blen) {
r = !do_compare(ap, bp, alen);
} else {
r = 0;
}
r = !do_compare(ap, alen, bp, blen);
} else if (SvOK(a) || SvOK(b)) {
r = 0;
} else {
Expand Down
4 changes: 1 addition & 3 deletions lib/String/Compare/ConstantTime.pm
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ An example with HMACs:

This module provides one function, C<equals> (not exported by default).

You should pass this function two strings of the same length. Just like perl's C<eq>, it will return true if they are string-wise identical and false otherwise. However, comparing any two differing strings of the same length will take a fixed amount of time. If the lengths of the strings are different, C<equals> will return false right away.
You should pass this function two strings of the same length. Just like perl's C<eq>, it will return true if they are string-wise identical and false otherwise. However, comparing any two differing strings of the same length will take a fixed amount of time. If the lengths of the strings are different, C<equals> will spend time proportional to a length of the user-supplied string and return false anyway.

B<NOTE>: This does byte-wise comparison of the underlying string storage, meaning that comparing strings with non-ASCII data with different states of the internal UTF-8 flag is not reliable. You should always encode your data to bytes before comparing.

Expand All @@ -62,8 +62,6 @@ Some programs take different amounts of time to run depending on the input value

Most routines that compare strings (like perl's C<eq> and C<cmp> and C's C<strcmp> and C<memcmp>) start scanning from the start of the strings and terminate as soon as they determine the strings won't match. This is good for efficiency but bad because it opens a timing side-channel. If one of the strings being compared is a secret and the other is controlled by some untrusted party, it is sometimes possible for this untrusted party to learn the secret using a timing side-channel.

If the lengths of the strings are different, because C<equals> returns false right away the size of the secret string may be leaked (but not its contents).



=head1 HMAC
Expand Down