From 32eb43f99c9c3b6dcbc18c97970a1f8ca389c20e Mon Sep 17 00:00:00 2001 From: leitner Date: Thu, 22 Oct 2020 20:43:13 +0000 Subject: [PATCH] add byte_start, byte_starts add a man page for byte_equal_notimingattack --- CHANGES | 2 ++ byte.h | 16 ++++++++++++++++ byte/byte_equal.3 | 8 ++++++-- byte/byte_equal_notimingattack.3 | 17 +++++++++++++++++ byte/byte_start.3 | 20 ++++++++++++++++++++ byte/byte_start.c | 16 ++++++++++++++++ byte/byte_starts.3 | 24 ++++++++++++++++++++++++ byte/byte_starts.c | 24 ++++++++++++++++++++++++ 8 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 byte/byte_equal_notimingattack.3 create mode 100644 byte/byte_start.3 create mode 100644 byte/byte_start.c create mode 100644 byte/byte_starts.3 create mode 100644 byte/byte_starts.c diff --git a/CHANGES b/CHANGES index e3095af..4f1804c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,6 @@ 0.33: + add byte_start, byte_starts + add a man page for byte_equal_notimingattack 0.32: remove OpenBSD #warning (obsd maintainer says no longer needed) diff --git a/byte.h b/byte.h index 9e9ba04..8224d67 100644 --- a/byte.h +++ b/byte.h @@ -56,6 +56,22 @@ void byte_zero(void* out, size_t len); #define byte_equal(s,n,t) (!byte_diff((s),(n),(t))) +/* Return 1 iff (b,blen) is a prefix of (a,alen), 0 otherwise. + * Will abort early on mismatch */ +__readmemsz__(1,2) +__readmemsz__(3,4) +int byte_start(const void* a,size_t alen,const void* b,size_t blen) __pure__; + +/* equivalent to byte_start(a,alen,str,strlen(str)) */ +__readmemsz__(1,2) +__readmem__(3) +int byte_starts(const void* a,size_t alen,const char* str) __pure__; + +#if defined(__GNUC__) && !defined(__LIBOWFAT_INTERNAL) +/* If str is a string constant, strlen will be done at compile time */ +#define byte_starts(a,alen,str) (__builtin_constant_p(str) ? byte_start(a,alen,str,strlen(str)) : byte_starts(a,alen,str)) +#endif + __readmemsz__(1,2) __readmemsz__(3,2) int byte_equal_notimingattack(const void* a, size_t len,const void* b) __pure__; diff --git a/byte/byte_equal.3 b/byte/byte_equal.3 index c017720..fde7c13 100644 --- a/byte/byte_equal.3 +++ b/byte/byte_equal.3 @@ -9,7 +9,11 @@ int \fBbyte_equal\fP(const char *\fIone\fR,size_t \fIlen\fR,const char *\fItwo\f \fIbyte_equal\fR returns 1 if the strings are equal, 0 otherwise. When the strings are different, byte_equal does not read bytes past the -first difference. +first difference. An attacker observing the execution timing can thus +learn where the first mismatch happened. + +Use byte_equal_notimingattack to compare keys, passphrases, cookies or +hashes instead. .SH "SEE ALSO" -byte_diff(3) +byte_diff(3), byte_equal_notimingattack(3) diff --git a/byte/byte_equal_notimingattack.3 b/byte/byte_equal_notimingattack.3 new file mode 100644 index 0000000..ae0fcdc --- /dev/null +++ b/byte/byte_equal_notimingattack.3 @@ -0,0 +1,17 @@ +.TH byte_equal_notimingattack 3 +.SH NAME +byte_equal_notimingattack \- compare two strings +.SH SYNTAX +.B #include + +int \fBbyte_equal_notimingattack\fP(const char *\fIone\fR,size_t \fIlen\fR,const char *\fItwo\fR); +.SH DESCRIPTION +\fIbyte_equal_notimingattack\fR returns 1 if the strings are equal, 0 otherwise. + +When the strings are different, byte_equal_notimingattack will still +read and compare all the other bytes. That way, an attacker observing +the timing of the execution can not learn where the first mismatch +occurred. + +.SH "SEE ALSO" +byte_diff(3), byte_equal(3) diff --git a/byte/byte_start.3 b/byte/byte_start.3 new file mode 100644 index 0000000..be27a61 --- /dev/null +++ b/byte/byte_start.3 @@ -0,0 +1,20 @@ +.TH byte_start 3 +.SH NAME +byte_start \- find out if string b is prefix of string a +.SH SYNTAX +.B #include + +int \fBbyte_start\fP(const char *\fIa\fR,size_t \fIalen\fR,const char *\fIb\fR,size_t blen); +.SH DESCRIPTION +\fIbyte_start\fR returns 1 if \fIalen\fR >= \fIblen\fR and the first \fIblen\fR bytes from +\fIa\fR and \fIb\fR are equal. + +When \fIblen\fR is too large or the strings are different, \fIbyte_start\fR does not +read bytes past the first difference. An attacker observing the +execution timing can thus learn where the first mismatch happened. + +Use \fIbyte_equal_notimingattack\fR to compare keys, passphrases, cookies or +hashes instead. + +.SH "SEE ALSO" +byte_equal(3), byte_equal_notimingattack(3), byte_starts(3) diff --git a/byte/byte_start.c b/byte/byte_start.c new file mode 100644 index 0000000..ebae323 --- /dev/null +++ b/byte/byte_start.c @@ -0,0 +1,16 @@ +#include +#include + +int byte_start(const void* a,size_t alen,const void* b,size_t blen) { + return blen<=alen && !memcmp(a,b,blen); +} + +#ifdef UNITTEST +#include +int main() { + static char buf[]="The quick brown fox jumps over the lazy dog"; + assert(byte_start(buf,sizeof(buf)-1,"The ",4)); + assert(!byte_start(buf,sizeof(buf)-1,"the ",4)); + assert(!byte_start(buf,3,buf,9)); +} +#endif diff --git a/byte/byte_starts.3 b/byte/byte_starts.3 new file mode 100644 index 0000000..2af3e34 --- /dev/null +++ b/byte/byte_starts.3 @@ -0,0 +1,24 @@ +.TH byte_starts 3 +.SH NAME +byte_starts \- find out if a buffer starts with a string +.SH SYNTAX +.B #include + +int \fBbyte_starts\fP(const char *\fIbuf\fR,size_t \fIbuflen\fR,const char *\fIstr\fR); +.SH DESCRIPTION +\fIbyte_starts\fR returns 1 if the \fIbuflen\fR>=strlen(\fIstr\fR) and the first +strlen(\fIstr\fR) bytes of \fIbuf\fR match the contents of \fIstr\fR, or +0 otherwise. + +This function is meant to be used in protocol parsing and with a string +constant for \fIstr\fR and will use gcc/clang macro trickery to reduce to a call to +\fImemcmp\fR then. + +\fIbyte_starts\fR compares as few bytes as possible. An attacker observing +the execution timing can thus learn where the first mismatch happened. + +Use \fIbyte_equal_notimingattack\fR to compare keys, passphrases, cookies or +hashes instead. + +.SH "SEE ALSO" +byte_equal(3), byte_equal_notimingattack(3), byte_start(3) diff --git a/byte/byte_starts.c b/byte/byte_starts.c new file mode 100644 index 0000000..a88292e --- /dev/null +++ b/byte/byte_starts.c @@ -0,0 +1,24 @@ +#include +#undef byte_starts +#include + +int byte_starts(const void* a,size_t alen,const char* s) { + size_t i; + for (i=0; i + +int main() { + static char buf[]="The quick brown fox jumps over the lazy dog"; + assert(byte_starts(buf,sizeof(buf)-1,"The ")); + assert(!byte_starts(buf,sizeof(buf)-1,"the ")); + assert(!byte_starts(buf,2,"The ")); + assert(byte_starts("The ",4,"The ")); +} +#endif