From 90fd268088b3774ec38d9be20872d51a295a49d2 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 24 Mar 2026 18:00:23 +0100 Subject: [PATCH] utils: Add constant-time comparison primitives for uint32_t --- src/libstrongswan/Makefile.am | 3 +- src/libstrongswan/utils/utils.h | 1 + src/libstrongswan/utils/utils/constant_time.h | 103 ++++++++++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 src/libstrongswan/utils/utils/constant_time.h diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 79d94be9b..5a3e50301 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -138,7 +138,8 @@ utils/parser_helper.h utils/test.h utils/integrity_checker.h utils/process.h \ utils/utils/strerror.h utils/compat/windows.h utils/compat/apple.h utils/compat/android.h \ utils/utils/atomics.h utils/utils/types.h utils/utils/byteorder.h \ utils/utils/string.h utils/utils/memory.h utils/utils/tty.h utils/utils/path.h \ -utils/utils/status.h utils/utils/object.h utils/utils/time.h utils/utils/align.h +utils/utils/status.h utils/utils/object.h utils/utils/time.h utils/utils/align.h \ +utils/utils/constant_time.h if USE_VM_SOCKETS nobase_strongswan_include_HEADERS += \ networking/streams/stream_vsock.h \ diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h index 42d01144a..ab0be7206 100644 --- a/src/libstrongswan/utils/utils.h +++ b/src/libstrongswan/utils/utils.h @@ -53,6 +53,7 @@ #include "utils/atomics.h" #include "utils/align.h" #include "utils/byteorder.h" +#include "utils/constant_time.h" #include "utils/string.h" #include "utils/memory.h" #include "utils/strerror.h" diff --git a/src/libstrongswan/utils/utils/constant_time.h b/src/libstrongswan/utils/utils/constant_time.h new file mode 100644 index 000000000..0c2c6a2e0 --- /dev/null +++ b/src/libstrongswan/utils/utils/constant_time.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2026 Tobias Brunner + * + * Copyright (C) secunet Security Networks AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup constant_time_i constant_time + * @{ @ingroup constant_time_i + */ + +#ifndef CONSTANT_TIME_H_ +#define CONSTANT_TIME_H_ + +#include + +/** + * Check if the given values are not equal in constant time. + * + * @param x first value to check + * @param y second value to check + * @return 1 if values are not equal, 0 otherwise + */ +static inline u_int constant_time_neq(uint32_t x, uint32_t y) +{ + return ((x-y) | (y-x)) >> 31; +} + +/** + * Check if the given values are equal in constant time. + * + * @param x first value to check + * @param y second value to check + * @return 1 if values are equal, 0 otherwise + */ +static inline u_int constant_time_eq(uint32_t x, uint32_t y) +{ + return 1 ^ constant_time_neq(x, y); +} + +/** + * Compare the two values and return 1 if the first argument is lower than + * the second in constant time. + * + * @param x first value to check + * @param y second value to check + * @return 1 if first value is lower than second + */ +static inline u_int constant_time_lt(uint32_t x, uint32_t y) +{ + return (x ^ ((x^y) | ((x-y) ^ y))) >> 31; +} + +/** + * Compare the two values and return 1 if the first argument greater or equal to + * the second in constant time. + * + * @param x first value to check + * @param y second value to check + * @return 1 if first value is greater or equal to the second + */ +static inline u_int constant_time_ge(uint32_t x, uint32_t y) +{ + return 1 ^ constant_time_lt(x, y); +} + +/** + * Return a 32-bit all bit-set mask if the given value is not 0. + * + * @param x value to check + * @return 0xffffffff if value is != 0, 0 otherwise + */ +static inline uint32_t constant_time_mask(uint32_t x) +{ + return -(uint32_t)constant_time_neq(x, 0); +} + +/** + * Select one of two values depending on whether the condition is != 0 or not. + * Basically equivalent to 'c ? x : y'. + * + * @param x first value to select + * @param y second value to select + * @param c condition + * @return x if c is != 0, y otherwise + */ +static inline uint32_t constant_time_select(uint32_t x, uint32_t y, uint32_t c) +{ + uint32_t m = constant_time_mask(c); + return (x & m) | (y & ~m); +} + +#endif /** CONSTANT_TIME_H_ @} */