cryptodev: introduce constant-time memory comparison
PATCH 1/1 cryptodev: introduce constant-time memory comparison
Add rte_consttime_memcmp() to prevent timing attacks in cryptographic digest verification operations.
Replace memcmp() with rte_consttime_memcmp() in cryptographic authentication verification operations across multiple crypto drivers:
* ipsec_mb
* scheduler
Note: OpenSSL crypto driver already uses CRYPTO_memcmp() which provides equivalent timing attack resistance and is left unchanged.
Bugzilla ID: 1773
Cc: [email protected]
[0] https://bugs.dpdk.org/show_bug.cgi?id=1773
--- drivers/crypto/ipsec_mb/pmd_aesni_gcm.c | 4 ++-- drivers/crypto/ipsec_mb/pmd_aesni_mb.c | 6 ++--- drivers/crypto/ipsec_mb/pmd_snow3g.c | 2 +- drivers/crypto/ipsec_mb/pmd_zuc.c | 2 +- .../scheduler/rte_cryptodev_scheduler.c | 2 +- lib/cryptodev/rte_cryptodev.h | 23 +++++++++++++++++++ 6 files changed, 31 insertions(+), 8 deletions(-)
drivers/crypto/ipsec_mb/pmd_aesni_gcm.c +2 -2
@@ -206,7 +206,7 @@ post_process_gcm_crypto_op(struct ipsec_mb_qp *qp, tag, session->req_digest_length);#endif -if (memcmp (tag, digest, session->req_digest_length) !=0 ) +if (rte_consttime_memcmp (tag, digest, session->req_digest_length) !=0 ) op->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }else {if (session->req_digest_length != session->gen_digest_length) {
@@ -558,7 +558,7 @@ aesni_gcm_sgl_op_finalize_decryption(const struct aesni_gcm_session *s, ops.finalize_dec (&s->gdata_key, gdata_ctx, tmpdigest, s->gen_digest_length); -return memcmp (digest, tmpdigest, s->req_digest_length) ==0 ?0 +return rte_consttime_memcmp (digest, tmpdigest, s->req_digest_length) ==0 ?0 :EBADMSG ; }
drivers/crypto/ipsec_mb/pmd_aesni_mb.c +3 -3
@@ -1902,7 +1902,7 @@ verify_docsis_sec_crc(IMB_JOB *job, uint8_t *status) crc = job->dst + crc_offset;/* Verify CRC (at the end of the message) */ -if (memcmp (job->auth_tag_output, crc,RTE_ETHER_CRC_LEN ) !=0 ) +if (rte_consttime_memcmp (job->auth_tag_output, crc,RTE_ETHER_CRC_LEN ) !=0 ) *status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }
@@ -1910,7 +1910,7 @@ static inline void verify_digest(IMB_JOB *job, void *digest, uint16_t len, uint8_t *status) {/* Verify digest if required */ -if (memcmp (job->auth_tag_output, digest, len) !=0 ) +if (rte_consttime_memcmp (job->auth_tag_output, digest, len) !=0 ) *status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }
@@ -2305,7 +2305,7 @@ verify_sync_dgst(struct rte_crypto_sym_vec *vec,for (i =0 , k =0 ; i != vec->num; i++) {if (vec->status[i] ==0 ) { -if (memcmp (vec->digest[i].va, dgst[i], len) !=0 ) +if (rte_consttime_memcmp (vec->digest[i].va, dgst[i], len) !=0 ) vec->status[i] =EBADMSG ;else k++;
drivers/crypto/ipsec_mb/pmd_snow3g.c +1 -1
@@ -269,7 +269,7 @@ process_snow3g_hash_op(struct ipsec_mb_qp *qp, struct rte_crypto_op **ops, &session->pKeySched_hash, iv, src, length_in_bits, dst);/* Verify digest. */ -if (memcmp (dst, ops[i]->sym->auth.digest.data, +if (rte_consttime_memcmp (dst, ops[i]->sym->auth.digest.data,SNOW3G_DIGEST_LENGTH ) !=0 ) ops[i]->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ;
drivers/crypto/ipsec_mb/pmd_zuc.c +1 -1
@@ -185,7 +185,7 @@ process_zuc_hash_op(struct ipsec_mb_qp *qp, struct rte_crypto_op **ops,*/ for (i =0 ; i < processed_ops; i++)if (sessions[i]->auth_op ==RTE_CRYPTO_AUTH_OP_VERIFY ) -if (memcmp (dst[i], ops[i]->sym->auth.digest.data, +if (rte_consttime_memcmp (dst[i], ops[i]->sym->auth.digest.data,ZUC_DIGEST_LENGTH ) !=0 ) ops[i]->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ;
drivers/crypto/scheduler/rte_cryptodev_scheduler.c +1 -1
@@ -100,7 +100,7 @@ check_sec_cap_equal(const struct rte_security_capability *sec_cap1,return 0 ;if (sec_cap1->protocol ==RTE_SECURITY_PROTOCOL_DOCSIS ) -return !memcmp (&sec_cap1->docsis, &sec_cap2->docsis, +return !rte_consttime_memcmp (&sec_cap1->docsis, &sec_cap2->docsis,sizeof (sec_cap1->docsis));else return 0 ;
lib/cryptodev/rte_cryptodev.h +23 -0
@@ -78,6 +78,29 @@ extern int rte_cryptodev_logtype;#define rte_crypto_op_ctophys_offset (c, o) \ (rte_iova_t)((c)->phys_addr + (o)) +/** +* Constant-time memory comparison for cryptographic use. +* Returns 0 if the memory regions are equal, nonzero otherwise. +* Runs in constant time with respect to the length to prevent timing attacks. +* +* @param a +* Pointer to the first memory region. +* @param b +* Pointer to the second memory region. +* @param n +* Number of bytes to compare. +* @return +* 0 if memory regions are equal, nonzero otherwise. +*/ +#define rte_consttime_memcmp (a, b, n) __extension__ ({ \ + const volatile uint8_t *__pa = (const volatile uint8_t *)(a); \ + const volatile uint8_t *__pb = (const volatile uint8_t *)(b); \ + uint8_t __result = 0; \ + for (size_t __i = 0; __i < (n); __i++) \ + __result |= __pa[__i] ^ __pb[__i]; \ + __result; \ +}) +/** * Crypto parameters range description */
Signature · 1 line
2.34.1
Quoted 44 lines
Add
rte_consttime_memcmp()to prevent timing attacks in cryptographic digest verification operations.Replace
memcmp()withrte_consttime_memcmp()in cryptographic authentication verification operations across multiple crypto drivers:*
ipsec_mb
* schedulerNote: OpenSSL crypto driver already uses
CRYPTO_memcmp()which provides equivalent timing attack resistance and is left unchanged.Bugzilla ID: 1773
Cc: [email protected][0] https://bugs.dpdk.org/show_bug.cgi?id=1773
Signed-off-by Kai Ji <[email protected]>lib/cryptodev/rte_cryptodev.h +16
-0@@ -78,6 +78,29 @@ extern int rte_cryptodev_logtype;#define rte_crypto_op_ctophys_offset (c, o) \ (rte_iova_t)((c)->phys_addr + (o)) +/** +* Constant-time memory comparison for cryptographic use. +* Returns 0 if the memory regions are equal, nonzero otherwise. +* Runs in constant time with respect to the length to prevent timing attacks. +* +* @param a +* Pointer to the first memory region. +* @param b +* Pointer to the second memory region. +* @param n +* Number of bytes to compare. +* @return +* 0 if memory regions are equal, nonzero otherwise. +*/ +#define rte_consttime_memcmp (a, b, n) __extension__ ({ \ + const volatile uint8_t *__pa = (const volatile uint8_t *)(a); \
lib/cryptodev/rte_cryptodev.h extern int rte_cryptodev_logtype; · line 106
Quoted 10 lines
lib/cryptodev/rte_cryptodev.h +7
-0+const volatile uint8_t *__pb = (const volatile uint8_t *)(b); \ +uint8_t __result =0 ; \ +for (size_t __i =0 ; __i < (n); __i++) \ + __result |= __pa[__i] ^ __pb[__i]; \ + __result; \ +}) +/** * Crypto parameters range description */
I believe this is not the right place to add this define. It should be somewhere in common eal if it is already not there.
++ Thomas, Stephen, Bruce, David.
25/09/2025 12:33, Akhil Goyal:
Quoted 17 lines
Quoted 17 lines
lib/cryptodev/rte_cryptodev.h +17
-0+/** +* Constant-time memory comparison for cryptographic use. +* Returns 0 if the memory regions are equal, nonzero otherwise. +* Runs in constant time with respect to the length to prevent timing attacks. +* +* @param a +* Pointer to the first memory region. +* @param b +* Pointer to the second memory region. +* @param n +* Number of bytes to compare. +* @return +* 0 if memory regions are equal, nonzero otherwise. +*/ +#define rte_consttime_memcmp (a, b, n) __extension__ ({ \ + const volatile uint8_t *__pa = (const volatile uint8_t *)(a); \ + const volatile uint8_t *__pb = (const volatile uint8_t *)(b); \
Quoted 8 lines
lib/cryptodev/rte_cryptodev.h extern int rte_cryptodev_logtype; · line 102
Quoted 5 lines
lib/cryptodev/rte_cryptodev.h +5
-0+uint8_t __result =0 ; \ +for (size_t __i =0 ; __i < (n); __i++) \ + __result |= __pa[__i] ^ __pb[__i]; \ + __result; \ +})I believe this is not the right place to add this define. It should be somewhere in common eal if it is already not there.
Yes indeed.
cryptodev is the API for managing crypto devices. A new memcmp function would be better hosted in libc, and in EAL for compatibility with all supported libc.
I mean please add it in EAL, and propose it to glibc as well.
Quoted 27 lines · Thomas Monjalon
25/09/2025 12:33, Akhil Goyal:
Quoted 17 lines
Quoted 17 lines
lib/cryptodev/rte_cryptodev.h +17
-0+/** +* Constant-time memory comparison for cryptographic use. +* Returns 0 if the memory regions are equal, nonzero otherwise. +* Runs in constant time with respect to the length to prevent timing attacks. +* +* @param a +* Pointer to the first memory region. +* @param b +* Pointer to the second memory region. +* @param n +* Number of bytes to compare. +* @return +* 0 if memory regions are equal, nonzero otherwise. +*/ +#define rte_consttime_memcmp (a, b, n) __extension__ ({ \ + const volatile uint8_t *__pa = (const volatile uint8_t *)(a); \ + const volatile uint8_t *__pb = (const volatile uint8_t *)(b); \Quoted 8 lines
lib/cryptodev/rte_cryptodev.h extern int rte_cryptodev_logtype; · line 102
Quoted 5 lines
lib/cryptodev/rte_cryptodev.h +5
-0+uint8_t __result =0 ; \ +for (size_t __i =0 ; __i < (n); __i++) \ + __result |= __pa[__i] ^ __pb[__i]; \ + __result; \ +})I believe this is not the right place to add this define. It should be somewhere in common eal if it is already not there.
Quoted 7 lines
Yes indeed.
cryptodev is the API for managing crypto devices. A new memcmp function would be better hosted in libc, and in EAL for compatibility with all supported libc.I mean please add it in EAL, and propose it to glibc as well.
Just for reference, there is a good discussion of such functions and reference code under MIT license at [1]. After reading that, I note that the proposed macro above it not strictly a memcmp function because it just returns a zero/non-zero value, rather than a value indicating which array value is greater. Therefore some feedback on this code:
* Use an inline function returning bool rather than a macro
* A more accurate name might be rte_consttime_memneq, since the code returns 0 (false) if equal.
Regars,
/Bruce
Quoted 36 lines · Bruce Richardson
Quoted 27 lines · Thomas Monjalon
25/09/2025 12:33, Akhil Goyal:
Quoted 17 lines
Quoted 17 lines
lib/cryptodev/rte_cryptodev.h +17
-0+/** +* Constant-time memory comparison for cryptographic use. +* Returns 0 if the memory regions are equal, nonzero otherwise. +* Runs in constant time with respect to the length to prevent timing attacks. +* +* @param a +* Pointer to the first memory region. +* @param b +* Pointer to the second memory region. +* @param n +* Number of bytes to compare. +* @return +* 0 if memory regions are equal, nonzero otherwise. +*/ +#define rte_consttime_memcmp (a, b, n) __extension__ ({ \ + const volatile uint8_t *__pa = (const volatile uint8_t *)(a); \ + const volatile uint8_t *__pb = (const volatile uint8_t *)(b); \Quoted 8 lines
lib/cryptodev/rte_cryptodev.h extern int rte_cryptodev_logtype; · line 102
Quoted 5 lines
lib/cryptodev/rte_cryptodev.h +5
-0+uint8_t __result =0 ; \ +for (size_t __i =0 ; __i < (n); __i++) \ + __result |= __pa[__i] ^ __pb[__i]; \ + __result; \ +})I believe this is not the right place to add this define. It should be somewhere in common eal if it is already not there.
Quoted 7 lines
Yes indeed.
cryptodev is the API for managing crypto devices. A new memcmp function would be better hosted in libc, and in EAL for compatibility with all supported libc.I mean please add it in EAL, and propose it to glibc as well.
Quoted 9 lines
Just for reference, there is a good discussion of such functions and reference code under MIT license at [1]. After reading that, I note that the proposed macro above it not strictly a memcmp function because it just returns a zero/non-zero value, rather than a value indicating which array value is greater. Therefore some feedback on this code:
* Use an inline function returning bool rather than a macro
* A more accurate name might berte_consttime_memneq, since the code returns 0 (false) if equal.
Or better, change the return value from result to !result to make it a "memeq" function, which also has the benefit of clamping return values to just 0 and 1.
Quoted 4 lines
Regars,
/Bruce
Quoted 54 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Friday, 26 September 2025 09.56Quoted 5 lines · Thomas Monjalon
25/09/2025 12:33, Akhil Goyal:
Quoted 4 lines
Quoted 4 lines
+/**
+ * Constant-time memory comparison for cryptographic use.
+ * Returns 0 if the memory regions are equal, nonzero otherwise.
+ * Runs in constant time with respect to the length to preventtiming attacks.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
+ *
+ * @param a
+ * Pointer to the first memory region.
+ * @param bQuoted 8 lines
Quoted 8 lines
Review
Quoted 8 lines
+ * Pointer to the second memory region.
+ * @param n
+ * Number of bytes to compare.
+ * @return
+ * 0 if memory regions are equal, nonzero otherwise.
+ */(quoted diff) +2
-0+#define rte_consttime_memcmp(a, b, n) __extension__ ({ \ + const volatile uint8_t *__pa = (const volatile uint8_t*)(a); \
Quoted 1 line
Quoted 1 line
Review
Quoted 1 line
(quoted diff) +1
-0+ const volatile uint8_t *__pb = (const volatile uint8_t*)(b); \
Quoted 9 lines
Quoted 8 lines
lib/cryptodev/rte_cryptodev.h extern int rte_cryptodev_logtype; · line 102
Quoted 5 lines
lib/cryptodev/rte_cryptodev.h +5
-0+uint8_t __result =0 ; \ +for (size_t __i =0 ; __i < (n); __i++) \ + __result |= __pa[__i] ^ __pb[__i]; \ + __result; \ +})I believe this is not the right place to add this define. It should be somewhere in common eal if it is already not there.
Quoted 7 lines
Yes indeed.
cryptodev is the API for managing crypto devices. A new memcmp function would be better hosted in libc, and in EAL for compatibility with all supported libc.I mean please add it in EAL, and propose it to glibc as well.
Just for reference, there is a good discussion of such functions and reference code under MIT license at [1]. After reading that, I note that
the proposed macro above it not strictly a memcmp function because it just
returns a zero/non-zero value, rather than a value indicating which array
value is greater. Therefore some feedback on this code:
* Use an inline function returning bool rather than a macro
* A more accurate name might berte_consttime_memneq, since the code returns 0 (false) if equal.
Quoted 4 lines
Regars,
/Bruce
When deciding on the function name and location:
Can we foresee other consttime or crypto-purpose functions that should reside in the EAL?
There's already rte_memzero_explicit() in rte_memory.h:
https://elixir.bootlin.com/dpdk/v25.07/source/lib/eal/include/rte_memory.h#L747
Please use the same naming convention, i.e. put the function purpose first, and append the special behavior as postfix:rte_memneq_consttime(), e.g.:
bool rte_memneq_consttime(const void *s1, const void *s2, size_t n);
IMHO, eal/include/rte_memory.h is a good location for this too.
Should it be an inline or normal function?
If it's primarily for fast path, inline is preferable.
You could also add the inverse function, i.e. add both memneq and memeq.
Quoted 28 lines
25/09/2025 12:33, Akhil Goyal:
Quoted 17 lines
Quoted 17 lines
lib/cryptodev/rte_cryptodev.h +17
-0+/** +* Constant-time memory comparison for cryptographic use. +* Returns 0 if the memory regions are equal, nonzero otherwise. +* Runs in constant time with respect to the length to prevent timing attacks. +* +* @param a +* Pointer to the first memory region. +* @param b +* Pointer to the second memory region. +* @param n +* Number of bytes to compare. +* @return +* 0 if memory regions are equal, nonzero otherwise. +*/ +#define rte_consttime_memcmp (a, b, n) __extension__ ({ \ + const volatile uint8_t *__pa = (const volatile uint8_t *)(a); \ + const volatile uint8_t *__pb = (const volatile uint8_t *)(b); \Quoted 8 lines
lib/cryptodev/rte_cryptodev.h extern int rte_cryptodev_logtype; · line 102
Quoted 5 lines
lib/cryptodev/rte_cryptodev.h +5
-0+uint8_t __result =0 ; \ +for (size_t __i =0 ; __i < (n); __i++) \ + __result |= __pa[__i] ^ __pb[__i]; \ + __result; \ +})I believe this is not the right place to add this define. It should be somewhere in common eal if it is already not there.
Quoted 6 lines
Yes indeed.
cryptodev is the API for managing crypto devices. A new memcmp function would be better hosted in libc, and in EAL for compatibility with all supported libc.I mean please add it in EAL, and propose it to glibc as well.
Stupid q: what's wrong with standard C memcmp() function?
Quoted 32 lines
Quoted 9 lines
25/09/2025 12:33, Akhil Goyal:
Quoted 4 lines
Quoted 4 lines
+/**
+ * Constant-time memory comparison for cryptographic use.
+ * Returns 0 if the memory regions are equal, nonzero otherwise.
+ * Runs in constant time with respect to the length to prevent timingattacks.
Quoted 22 lines
Quoted 21 lines
Quoted 10 lines
+ *
+ * @param a
+ * Pointer to the first memory region.
+ * @param b
+ * Pointer to the second memory region.
+ * @param n
+ * Number of bytes to compare.
+ * @return
+ * 0 if memory regions are equal, nonzero otherwise.
+ */lib/cryptodev/rte_cryptodev.h extern int rte_cryptodev_logtype; · line 102
Quoted 8 lines
lib/cryptodev/rte_cryptodev.h +8
-0+#define rte_consttime_memcmp (a, b, n) __extension__ ({ \ + const volatile uint8_t *__pa = (const volatile uint8_t *)(a); \ + const volatile uint8_t *__pb = (const volatile uint8_t *)(b); \ + uint8_t __result = 0; \ + for (size_t __i = 0; __i < (n); __i++) \ + __result |= __pa[__i] ^ __pb[__i]; \ + __result; \ +})I believe this is not the right place to add this define. It should be somewhere in common eal if it is already not there.
Quoted 8 lines
Quoted 6 lines
Yes indeed.
cryptodev is the API for managing crypto devices. A new memcmp function would be better hosted in libc, and in EAL for compatibility with all supported libc.I mean please add it in EAL, and propose it to glibc as well.
Stupid q: what's wrong with standard C
memcmp()function?
Ah, sorry, didn't read properly.
Please disregard, and yes - might be EAL is the right place for it.
PATCH v2 1/2 eal: Add rte_consttime_memsq() to prevent timing attacks memcmp.
In reply to Kai JiBugzilla ID: 1773
Cc: [email protected]
[0] https://bugs.dpdk.org/show_bug.cgi?id=1773
--- lib/eal/include/rte_common.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)
lib/eal/include/rte_common.h +34 -0
@@ -700,6 +700,40 @@ rte_is_aligned(const void * const __rte_restrict ptr, const unsigned int align)return ((uintptr_t )ptr & (align -1 )) ==0 ; } +/** +* Constant-time memory inequality comparison. +* +* This function compares two memory regions in constant time, making it +* resistant to timing side-channel attacks. The execution time depends only +* on the length parameter, not on the actual data values being compared. +* +* This is particularly important for cryptographic operations where timing +* differences could leak information about secret keys, passwords, or other +* sensitive data. +* +* @param a +* Pointer to the first memory region to compare +* @param b +* Pointer to the second memory region to compare +* @param n +* Number of bytes to compare +* @return +* false if the memory regions are identical, true if they differ +*/ +static inline bool +rte_consttime_memneq (const void *a,const void *b,size_t n) +{ +const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result !=0 ; +} +/*********** Macros for compile type checks ********/ /* Workaround for toolchain issues with missing C11 macro in FreeBSD */
Signature · 1 line
2.34.1
PATCH v2 2/2 crypto/ipsec-mb: use constant-time memory comparison
Replace memcmp() with rte_consttime_memsq() in cryptographic authentication verification operations across multiple crypto drivers:
* ipsec_mb
Note: OpenSSL crypto driver already uses CRYPTO_memcmp() which provides equivalent timing attack resistance and is left unchanged.
Note: scheduler driver memcmp stays unchanged as its not secret data comparison and actually faster with no timing attack risk.
Bugzilla ID: 1773
Cc: [email protected]
[0] https://bugs.dpdk.org/show_bug.cgi?id=1773
--- drivers/crypto/ipsec_mb/pmd_aesni_gcm.c | 5 ++--- drivers/crypto/ipsec_mb/pmd_aesni_mb.c | 6 +++--- drivers/crypto/ipsec_mb/pmd_snow3g.c | 4 ++-- drivers/crypto/ipsec_mb/pmd_zuc.c | 4 ++-- 4 files changed, 9 insertions(+), 10 deletions(-)
drivers/crypto/ipsec_mb/pmd_aesni_gcm.c +2 -3
@@ -206,7 +206,7 @@ post_process_gcm_crypto_op(struct ipsec_mb_qp *qp, tag, session->req_digest_length);#endif -if (memcmp (tag, digest, session->req_digest_length) !=0 ) +if (rte_consttime_memneq (tag, digest, session->req_digest_length)) op->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }else {if (session->req_digest_length != session->gen_digest_length) {
@@ -558,8 +558,7 @@ aesni_gcm_sgl_op_finalize_decryption(const struct aesni_gcm_session *s, ops.finalize_dec (&s->gdata_key, gdata_ctx, tmpdigest, s->gen_digest_length); -return memcmp (digest, tmpdigest, s->req_digest_length) ==0 ?0 - :EBADMSG ; +return rte_consttime_memneq (digest, tmpdigest, s->req_digest_length) ?EBADMSG :0 ; } static inline void
drivers/crypto/ipsec_mb/pmd_aesni_mb.c +3 -3
@@ -1902,7 +1902,7 @@ verify_docsis_sec_crc(IMB_JOB *job, uint8_t *status) crc = job->dst + crc_offset;/* Verify CRC (at the end of the message) */ -if (memcmp (job->auth_tag_output, crc,RTE_ETHER_CRC_LEN ) !=0 ) +if (rte_consttime_memneq (job->auth_tag_output, crc,RTE_ETHER_CRC_LEN )) *status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }
@@ -1910,7 +1910,7 @@ static inline void verify_digest(IMB_JOB *job, void *digest, uint16_t len, uint8_t *status) {/* Verify digest if required */ -if (memcmp (job->auth_tag_output, digest, len) !=0 ) +if (rte_consttime_memneq (job->auth_tag_output, digest, len)) *status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }
@@ -2305,7 +2305,7 @@ verify_sync_dgst(struct rte_crypto_sym_vec *vec,for (i =0 , k =0 ; i != vec->num; i++) {if (vec->status[i] ==0 ) { -if (memcmp (vec->digest[i].va, dgst[i], len) !=0 ) +if (rte_consttime_memneq (vec->digest[i].va, dgst[i], len)) vec->status[i] =EBADMSG ;else k++;
drivers/crypto/ipsec_mb/pmd_snow3g.c +2 -2
@@ -269,8 +269,8 @@ process_snow3g_hash_op(struct ipsec_mb_qp *qp, struct rte_crypto_op **ops, &session->pKeySched_hash, iv, src, length_in_bits, dst);/* Verify digest. */ -if (memcmp (dst, ops[i]->sym->auth.digest.data, -SNOW3G_DIGEST_LENGTH ) !=0 ) +if (rte_consttime_memneq (dst, ops[i]->sym->auth.digest.data, +SNOW3G_DIGEST_LENGTH )) ops[i]->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }else {
drivers/crypto/ipsec_mb/pmd_zuc.c +2 -2
@@ -185,8 +185,8 @@ process_zuc_hash_op(struct ipsec_mb_qp *qp, struct rte_crypto_op **ops,*/ for (i =0 ; i < processed_ops; i++)if (sessions[i]->auth_op ==RTE_CRYPTO_AUTH_OP_VERIFY ) -if (memcmp (dst[i], ops[i]->sym->auth.digest.data, -ZUC_DIGEST_LENGTH ) !=0 ) +if (rte_consttime_memneq (dst[i], ops[i]->sym->auth.digest.data, +ZUC_DIGEST_LENGTH )) ops[i]->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ;
Signature · 1 line
2.34.1
PATCH v3 1/2 eal: Add rte_consttime_memneq() to prevent timing attacks memcmp.
In reply to Kai JiBugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773
--- lib/eal/include/rte_common.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)
lib/eal/include/rte_common.h +34 -0
@@ -700,6 +700,40 @@ rte_is_aligned(const void * const __rte_restrict ptr, const unsigned int align)return ((uintptr_t )ptr & (align -1 )) ==0 ; } +/** +* Constant-time memory inequality comparison. +* +* This function compares two memory regions in constant time, making it +* resistant to timing side-channel attacks. The execution time depends only +* on the length parameter, not on the actual data values being compared. +* +* This is particularly important for cryptographic operations where timing +* differences could leak information about secret keys, passwords, or other +* sensitive data. +* +* @param a +* Pointer to the first memory region to compare +* @param b +* Pointer to the second memory region to compare +* @param n +* Number of bytes to compare +* @return +* false if the memory regions are identical, true if they differ +*/ +static inline bool +rte_consttime_memneq (const void *a,const void *b,size_t n) +{ +const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result !=0 ; +} +/*********** Macros for compile type checks ********/ /* Workaround for toolchain issues with missing C11 macro in FreeBSD */
Signature · 1 line
2.34.1
PATCH v3 2/2 crypto/ipsec-mb: use constant-time memory comparison
Replace memcmp() with rte_consttime_memneq() in cryptographic authentication verification operations in ipsec_mb crypto driver.
Note: OpenSSL crypto driver already uses CRYPTO_memcmp() which provides equivalent timing attack resistance and is left unchanged.
Note: scheduler driver memcmp stays unchanged as its not secret data comparison and actually faster with no timing attack risk.
Bugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773
--- drivers/crypto/ipsec_mb/pmd_aesni_gcm.c | 5 ++--- drivers/crypto/ipsec_mb/pmd_aesni_mb.c | 6 +++--- drivers/crypto/ipsec_mb/pmd_snow3g.c | 4 ++-- drivers/crypto/ipsec_mb/pmd_zuc.c | 4 ++-- 4 files changed, 9 insertions(+), 10 deletions(-)
drivers/crypto/ipsec_mb/pmd_aesni_gcm.c +2 -3
@@ -206,7 +206,7 @@ post_process_gcm_crypto_op(struct ipsec_mb_qp *qp, tag, session->req_digest_length);#endif -if (memcmp (tag, digest, session->req_digest_length) !=0 ) +if (rte_consttime_memneq (tag, digest, session->req_digest_length)) op->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }else {if (session->req_digest_length != session->gen_digest_length) {
@@ -558,8 +558,7 @@ aesni_gcm_sgl_op_finalize_decryption(const struct aesni_gcm_session *s, ops.finalize_dec (&s->gdata_key, gdata_ctx, tmpdigest, s->gen_digest_length); -return memcmp (digest, tmpdigest, s->req_digest_length) ==0 ?0 - :EBADMSG ; +return rte_consttime_memneq (digest, tmpdigest, s->req_digest_length) ?EBADMSG :0 ; } static inline void
drivers/crypto/ipsec_mb/pmd_aesni_mb.c +3 -3
@@ -1902,7 +1902,7 @@ verify_docsis_sec_crc(IMB_JOB *job, uint8_t *status) crc = job->dst + crc_offset;/* Verify CRC (at the end of the message) */ -if (memcmp (job->auth_tag_output, crc,RTE_ETHER_CRC_LEN ) !=0 ) +if (rte_consttime_memneq (job->auth_tag_output, crc,RTE_ETHER_CRC_LEN )) *status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }
@@ -1910,7 +1910,7 @@ static inline void verify_digest(IMB_JOB *job, void *digest, uint16_t len, uint8_t *status) {/* Verify digest if required */ -if (memcmp (job->auth_tag_output, digest, len) !=0 ) +if (rte_consttime_memneq (job->auth_tag_output, digest, len)) *status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }
@@ -2305,7 +2305,7 @@ verify_sync_dgst(struct rte_crypto_sym_vec *vec,for (i =0 , k =0 ; i != vec->num; i++) {if (vec->status[i] ==0 ) { -if (memcmp (vec->digest[i].va, dgst[i], len) !=0 ) +if (rte_consttime_memneq (vec->digest[i].va, dgst[i], len)) vec->status[i] =EBADMSG ;else k++;
drivers/crypto/ipsec_mb/pmd_snow3g.c +2 -2
@@ -269,8 +269,8 @@ process_snow3g_hash_op(struct ipsec_mb_qp *qp, struct rte_crypto_op **ops, &session->pKeySched_hash, iv, src, length_in_bits, dst);/* Verify digest. */ -if (memcmp (dst, ops[i]->sym->auth.digest.data, -SNOW3G_DIGEST_LENGTH ) !=0 ) +if (rte_consttime_memneq (dst, ops[i]->sym->auth.digest.data, +SNOW3G_DIGEST_LENGTH )) ops[i]->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }else {
drivers/crypto/ipsec_mb/pmd_zuc.c +2 -2
@@ -185,8 +185,8 @@ process_zuc_hash_op(struct ipsec_mb_qp *qp, struct rte_crypto_op **ops,*/ for (i =0 ; i < processed_ops; i++)if (sessions[i]->auth_op ==RTE_CRYPTO_AUTH_OP_VERIFY ) -if (memcmp (dst[i], ops[i]->sym->auth.digest.data, -ZUC_DIGEST_LENGTH ) !=0 ) +if (rte_consttime_memneq (dst[i], ops[i]->sym->auth.digest.data, +ZUC_DIGEST_LENGTH )) ops[i]->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ;
Signature · 1 line
2.34.1
Re: [dpdk-dev v3 1/2] eal: Add rte_consttime_memneq() to prevent timing attacks memcmp.
In reply to Kai JiQuoted 12 lines · On Fri, 26 Sep 2025 16:02:08 +0000 Kai Ji <[email protected]> wrote:
lib/eal/include/rte_common.h +12
-0+/** +* Constant-time memory inequality comparison. +* +* This function compares two memory regions in constant time, making it +* resistant to timing side-channel attacks. The execution time depends only +* on the length parameter, not on the actual data values being compared. +* +* This is particularly important for cryptographic operations where timing +* differences could leak information about secret keys, passwords, or other +* sensitive data. +* +* @param a
lib/eal/include/rte_common.h rte_is_aligned(const void * const __rte_restrict ptr, const unsigned int align) · line 724
Quoted 10 lines
lib/eal/include/rte_common.h +10
-0+* Pointer to the first memory region to compare +* @param b +* Pointer to the second memory region to compare +* @param n +* Number of bytes to compare +* @return +* false if the memory regions are identical, true if they differ +*/ +static inline bool +rte_consttime_memneq (const void *a,const void *b,size_t n)
prefer FreeBSD naming i.e memeq instead of memneq
RE: [dpdk-dev v3 1/2] eal: Add rte_consttime_memneq() to prevent timing attacks memcmp.
In reply to Kai JiQuoted 63 lines
From: Kai Ji [mailto:[email protected]]
Sent: Friday, 26 September 2025 18.02Bugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773Signed-off-by Kai Ji <[email protected]>--- lib/eal/include/rte_common.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)lib/eal/include/rte_common.h +4
-0@@ -700,6 +700,40 @@ rte_is_aligned(const void * const __rte_restrict ptr, const unsigned int align)return ((uintptr_t )ptr & (align -1 )) ==0 ; } +/** +* Constant-time memory inequality comparison. +* +* This function compares two memory regions in constant time, making it
+ * resistant to timing side-channel attacks. The execution time depends only
+ * on the length parameter, not on the actual data values being compared.
+ *
+ * This is particularly important for cryptographic operations where timing
+ * differences could leak information about secret keys, passwords, or other
+ * sensitive data.
+ *
+ * @param a
+ * Pointer to the first memory region to compare
+ * @param b
+ * Pointer to the second memory region to compare
+ * @param n
+ * Number of bytes to compare
+ * @return
+ * false if the memory regions are identical, true if they differ
+ */lib/eal/include/rte_common.h +14
-0+static inline bool +rte_consttime_memneq (const void *a,const void *b,size_t n) +{ +const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result !=0 ; +} +/*********** Macros for compile type checks ********/ /* Workaround for toolchain issues with missing C11 macro in FreeBSD
Quoted 3 lines
*/
--
2.34.1
My comments here still apply:
https://inbox.dpdk.org/dev/[email protected]/
Also, this is certainly not a common function, so don't put it in rte_commo.h. Put it in rte_memory.h as suggested.
-Morten
Re: [dpdk-dev v3 1/2] eal: Add rte_consttime_memneq() to prevent timing attacks memcmp.
Quoted 70 lines · On Fri, 26 Sep 2025 21:17:08 +0200 Morten Brørup <[email protected]>…
Quoted 63 lines
From: Kai Ji [mailto:[email protected]]
Sent: Friday, 26 September 2025 18.02Bugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773Signed-off-by Kai Ji <[email protected]>--- lib/eal/include/rte_common.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)lib/eal/include/rte_common.h +4
-0@@ -700,6 +700,40 @@ rte_is_aligned(const void * const __rte_restrict ptr, const unsigned int align)return ((uintptr_t )ptr & (align -1 )) ==0 ; } +/** +* Constant-time memory inequality comparison. +* +* This function compares two memory regions in constant time, making it
+ * resistant to timing side-channel attacks. The execution time depends only
+ * on the length parameter, not on the actual data values being compared.
+ *
+ * This is particularly important for cryptographic operations where timing
+ * differences could leak information about secret keys, passwords, or other
+ * sensitive data.
+ *
+ * @param a
+ * Pointer to the first memory region to compare
+ * @param b
+ * Pointer to the second memory region to compare
+ * @param n
+ * Number of bytes to compare
+ * @return
+ * false if the memory regions are identical, true if they differ
+ */lib/eal/include/rte_common.h +14
-0+static inline bool +rte_consttime_memneq (const void *a,const void *b,size_t n) +{ +const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result !=0 ; +} +/*********** Macros for compile type checks ********/ /* Workaround for toolchain issues with missing C11 macro in FreeBSD Quoted 3 lines
*/
--
2.34.1My comments here still apply:
https://inbox.dpdk.org/dev/[email protected]/
Quoted 1 line
Also, this is certainly not a common function, so don't put it in
rte_commo.h. Put it inrte_memory.has suggested.
Yes, Should be next to existing rte_memzero_explicit in rte_memory.h
PATCH v4 1/2 eal: Add mem equal and non-equal to prevent timing attacks memcmp.
In reply to Kai JiBugzilla ID: 1773
Cc: [email protected]
[0] https://bugs.dpdk.org/show_bug.cgi?id=1773
--- lib/eal/include/rte_memory.h | 68 ++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+)
lib/eal/include/rte_memory.h +68 -0
@@ -746,6 +746,74 @@ __rte_experimentalvoid rte_memzero_explicit (void *dst,size_t sz); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Constant-time memory inequality comparison. +* +* This function compares two memory regions in constant time, making it +* resistant to timing side-channel attacks. The execution time depends only +* on the length parameter, not on the actual data values being compared. +* +* This is particularly important for cryptographic operations where timing +* differences could leak information about secret keys, passwords, or other +* sensitive data. +* +* @param a +* Pointer to the first memory region to compare +* @param b +* Pointer to the second memory region to compare +* @param n +* Number of bytes to compare +* @return +* false if the memory regions are identical, true if they differ +*/ +__rte_experimental +static inline bool +rte_memneq_consttime (const void *a,const void *b,size_t n) +{ +const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result !=0 ; +} + +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Constant-time memory equality comparison. +* +* This function compares two memory regions in constant time, making it +* resistant to timing side-channel attacks. The execution time depends only +* on the length parameter, not on the actual data values being compared. +* +* This is particularly important for cryptographic operations where timing +* differences could leak information about secret keys, passwords, or other +* sensitive data. +* +* @param a +* Pointer to the first memory region to compare +* @param b +* Pointer to the second memory region to compare +* @param n +* Number of bytes to compare +* @return +* true if the memory regions are identical, false if they differ +*/ +__rte_experimental +static inline bool +rte_memeq_consttime (const void *a,const void *b,size_t n) +{ +return !rte_memneq_consttime (a, b, n); +} + #ifdef __cplusplus }#endif
Signature · 1 line
2.34.1
PATCH v4 2/2 crypto/ipsec-mb: use constant-time memory comparison
Replace memcmp() with rte_memneq_consttime() in cryptographic authentication verification operations across iipsec-mb drivers.
Note: OpenSSL crypto driver already uses CRYPTO_memcmp() which provides equivalent timing attack resistance and is left unchanged.
Note: scheduler driver memcmp stays unchanged as its not secret data comparison and actually faster with no timing attack risk.
Bugzilla ID: 1773
Cc: [email protected]
[0] https://bugs.dpdk.org/show_bug.cgi?id=1773
--- drivers/crypto/ipsec_mb/pmd_aesni_gcm.c | 5 ++--- drivers/crypto/ipsec_mb/pmd_aesni_mb.c | 6 +++--- drivers/crypto/ipsec_mb/pmd_snow3g.c | 4 ++-- drivers/crypto/ipsec_mb/pmd_zuc.c | 4 ++-- 4 files changed, 9 insertions(+), 10 deletions(-)
drivers/crypto/ipsec_mb/pmd_aesni_gcm.c +2 -3
@@ -206,7 +206,7 @@ post_process_gcm_crypto_op(struct ipsec_mb_qp *qp, tag, session->req_digest_length);#endif -if (memcmp (tag, digest, session->req_digest_length) !=0 ) +if (rte_memneq_consttime (tag, digest, session->req_digest_length)) op->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }else {if (session->req_digest_length != session->gen_digest_length) {
@@ -558,8 +558,7 @@ aesni_gcm_sgl_op_finalize_decryption(const struct aesni_gcm_session *s, ops.finalize_dec (&s->gdata_key, gdata_ctx, tmpdigest, s->gen_digest_length); -return memcmp (digest, tmpdigest, s->req_digest_length) ==0 ?0 - :EBADMSG ; +return rte_memneq_consttime (digest, tmpdigest, s->req_digest_length) ?EBADMSG :0 ; } static inline void
drivers/crypto/ipsec_mb/pmd_aesni_mb.c +3 -3
@@ -1902,7 +1902,7 @@ verify_docsis_sec_crc(IMB_JOB *job, uint8_t *status) crc = job->dst + crc_offset;/* Verify CRC (at the end of the message) */ -if (memcmp (job->auth_tag_output, crc,RTE_ETHER_CRC_LEN ) !=0 ) +if (rte_memneq_consttime (job->auth_tag_output, crc,RTE_ETHER_CRC_LEN )) *status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }
@@ -1910,7 +1910,7 @@ static inline void verify_digest(IMB_JOB *job, void *digest, uint16_t len, uint8_t *status) {/* Verify digest if required */ -if (memcmp (job->auth_tag_output, digest, len) !=0 ) +if (rte_memneq_consttime (job->auth_tag_output, digest, len)) *status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }
@@ -2305,7 +2305,7 @@ verify_sync_dgst(struct rte_crypto_sym_vec *vec,for (i =0 , k =0 ; i != vec->num; i++) {if (vec->status[i] ==0 ) { -if (memcmp (vec->digest[i].va, dgst[i], len) !=0 ) +if (rte_memneq_consttime (vec->digest[i].va, dgst[i], len)) vec->status[i] =EBADMSG ;else k++;
drivers/crypto/ipsec_mb/pmd_snow3g.c +2 -2
@@ -269,8 +269,8 @@ process_snow3g_hash_op(struct ipsec_mb_qp *qp, struct rte_crypto_op **ops, &session->pKeySched_hash, iv, src, length_in_bits, dst);/* Verify digest. */ -if (memcmp (dst, ops[i]->sym->auth.digest.data, -SNOW3G_DIGEST_LENGTH ) !=0 ) +if (rte_memneq_consttime (dst, ops[i]->sym->auth.digest.data, +SNOW3G_DIGEST_LENGTH )) ops[i]->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }else {
drivers/crypto/ipsec_mb/pmd_zuc.c +2 -2
@@ -185,8 +185,8 @@ process_zuc_hash_op(struct ipsec_mb_qp *qp, struct rte_crypto_op **ops,*/ for (i =0 ; i < processed_ops; i++)if (sessions[i]->auth_op ==RTE_CRYPTO_AUTH_OP_VERIFY ) -if (memcmp (dst[i], ops[i]->sym->auth.digest.data, -ZUC_DIGEST_LENGTH ) !=0 ) +if (rte_memneq_consttime (dst[i], ops[i]->sym->auth.digest.data, +ZUC_DIGEST_LENGTH )) ops[i]->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ;
Signature · 1 line
2.34.1
Re: [dpdk-dev v4 2/2] crypto/ipsec-mb: use constant-time memory comparison
Quoted 9 lines · On Mon, 29 Sep 2025 14:50:49 +0000 Kai Ji <[email protected]> wrote:
Replace
memcmp()withrte_memneq_consttime()in cryptographic authentication verification operations across iipsec-mb drivers.Note: OpenSSL crypto driver already uses
CRYPTO_memcmp()which provides equivalent timing attack resistance and is left unchanged.Note: scheduler driver memcmp stays unchanged as its not secret data comparison and actually faster with no timing attack risk.
Quoted 7 lines
Bugzilla ID: 1773
Cc: [email protected][0] https://bugs.dpdk.org/show_bug.cgi?id=1773
Signed-off-by Kai Ji <[email protected]>---
Thanks for doing this.
A couple other notes from my searching around.
The function memeq_consttime is in NetBSD (not FreeBSD) sorry if I got confused. OpenBSD has timingsafe_memcmp() and timingsafe_bcmp().
Also this on LWN:
Quoted 7 lines
You would use a constant-time version of memcmp. OpenBSD added
timingsafe_bcmpin 2009, and thentimingsafe_memcmpa few years later. (https://man.openbsd.org/timingsafe_memcmp.3) NetBSD hasconsttime_memequal. (https://man.netbsd.org/consttime_memequal.3) Apple and FreeBSD adopted the OpenBSD routines. I don't think either glibc or musl libc have adopted a similar interface. So on Linux or for portable software you'd probably want to useCRYPTO_memcmpfrom OpenSSL.You should of course be hashing the passwords with salts, and only comparing those hashes. In which case using a constant-time compare isn't that important as the attacker can't work backward from the short-circuiting compare to decipher the plaintext input. The hashing itself should be constant-time, assuming modern digests like SHA-256 or SHA-3, though it's possible the *length* of the input password would leak. But there are a gazillion ways for the length to leak, and when it comes to password-based authentication schemes that's the least of your worries.
Re: [dpdk-dev v4 1/2] eal: Add mem equal and non-equal to prevent timing attacks memcmp.
In reply to Kai JiQuoted 24 lines · On Mon, 29 Sep 2025 14:50:48 +0000 Kai Ji <[email protected]> wrote:
lib/eal/include/rte_memory.h +16
-0@@ -746,6 +746,74 @@ __rte_experimentalvoid rte_memzero_explicit (void *dst,size_t sz); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Constant-time memory inequality comparison. +* +* This function compares two memory regions in constant time, making it +* resistant to timing side-channel attacks. The execution time depends only +* on the length parameter, not on the actual data values being compared. +* +* This is particularly important for cryptographic operations where timing +* differences could leak information about secret keys, passwords, or other +* sensitive data. +* +* @param a +* Pointer to the first memory region to compare
lib/eal/include/rte_memory.h __rte_experimental · line 774
Quoted 10 lines
lib/eal/include/rte_memory.h +10
-0+* @param b +* Pointer to the second memory region to compare +* @param n +* Number of bytes to compare +* @return +* false if the memory regions are identical, true if they differ +*/ +__rte_experimental +static inline bool +rte_memneq_consttime (const void *a,const void *b,size_t n)
NAK
Please change to match BSD equivalent function (ie not not equal)
RE: [dpdk-dev v4 1/2] eal: Add mem equal and non-equal to prevent timing attacks memcmp.
In reply to Kai JiQuoted 10 lines
From: Kai Ji [mailto:[email protected]]
Sent: Monday, 29 September 2025 16.51Bugzilla ID: 1773
Cc: [email protected][0] https://bugs.dpdk.org/show_bug.cgi?id=1773
Signed-off-by Kai Ji <[email protected]>---
@Stephen: V4 also includes equal, which you was asking for.
Re: [dpdk-dev v4 1/2] eal: Add mem equal and non-equal to prevent timing attacks memcmp.
Quoted 6 lines · On Mon, 29 Sep 2025 19:48:19 +0200 Morten Brørup <[email protected]>…
Quoted 6 lines
From: Kai Ji [mailto:[email protected]]
Sent: Monday, 29 September 2025 16.51Bugzilla ID: 1773
Cc: [email protected]
Quoted 9 lines
Quoted 4 lines
[0] https://bugs.dpdk.org/show_bug.cgi?id=1773
Signed-off-by Kai Ji <[email protected]>---
Acked-by Morten Brørup <[email protected]>@Stephen: V4 also includes equal, which you was asking for.
The point is that we should only have the eq variant. Having the not equal is unnecessary addition.
RE: [dpdk-dev v4 1/2] eal: Add mem equal and non-equal to prevent timing attacks memcmp.
Quoted 17 lines
From: Stephen Hemminger [mailto:[email protected]]
Sent: Tuesday, 30 September 2025 00.49Quoted 11 lines · On Mon, 29 Sep 2025 19:48:19 +0200 Morten Brørup <[email protected]>…
Quoted 10 lines
From: Kai Ji [mailto:[email protected]]
Sent: Monday, 29 September 2025 16.51Bugzilla ID: 1773
Cc: [email protected][0] https://bugs.dpdk.org/show_bug.cgi?id=1773
Signed-off-by Kai Ji <[email protected]>---
Quoted 7 lines
Quoted 4 lines
Acked-by Morten Brørup <[email protected]>@Stephen: V4 also includes equal, which you was asking for.
The point is that we should only have the eq variant. Having the not equal is unnecessary addition.
Yes, I would tend to agree with Stephen on this.
PATCH v5 1/2 eal: introduce rte_timingsafe_memcmp() based on OpenBSD API
In reply to Kai JiBugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773
--- lib/eal/include/rte_memory.h | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+)
lib/eal/include/rte_memory.h +38 -0
@@ -746,6 +746,44 @@ __rte_experimentalvoid rte_memzero_explicit (void *dst,size_t sz); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Constant-time memory comparison. +* +* This function compares two memory regions in constant time, making it +* resistant to timing side-channel attacks. The execution time depends only +* on the length parameter, not on the actual data values being compared. +* +* This is particularly important for cryptographic operations where timing +* differences could leak information about secret keys, passwords, or other +* sensitive data. +* +* @param a +* Pointer to the first memory region to compare +* @param b +* Pointer to the second memory region to compare +* @param n +* Number of bytes to compare +* @return +* 0 if the memory regions are identical, non-zero if they differ +*/ +__rte_experimental +static inline int +rte_timingsafe_memcmp (const void *a,const void *b,size_t n) +{ +const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result; +} + #ifdef __cplusplus }#endif
Signature · 1 line
2.34.1
PATCH v5 2/2 crypto/ipsec-mb: use constant-time memory comparison
Replace memcmp() with rte_timingsafe_memcmp() in cryptographic authentication verification operations across iipsec-mb drivers.
Note: OpenSSL crypto driver already uses CRYPTO_memcmp() which provides equivalent timing attack resistance and is left unchanged.
Note: scheduler driver memcmp stays unchanged as its not secret data comparison and actually faster with no timing attack risk.
Bugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773
--- drivers/crypto/ipsec_mb/pmd_aesni_gcm.c | 5 ++--- drivers/crypto/ipsec_mb/pmd_aesni_mb.c | 6 +++--- drivers/crypto/ipsec_mb/pmd_snow3g.c | 2 +- drivers/crypto/ipsec_mb/pmd_zuc.c | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-)
drivers/crypto/ipsec_mb/pmd_aesni_gcm.c +2 -3
@@ -206,7 +206,7 @@ post_process_gcm_crypto_op(struct ipsec_mb_qp *qp, tag, session->req_digest_length);#endif -if (memcmp (tag, digest, session->req_digest_length) !=0 ) +if (rte_timingsafe_memcmp (tag, digest, session->req_digest_length) !=0 ) op->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }else {if (session->req_digest_length != session->gen_digest_length) {
@@ -558,8 +558,7 @@ aesni_gcm_sgl_op_finalize_decryption(const struct aesni_gcm_session *s, ops.finalize_dec (&s->gdata_key, gdata_ctx, tmpdigest, s->gen_digest_length); -return memcmp (digest, tmpdigest, s->req_digest_length) ==0 ?0 - :EBADMSG ; +return rte_timingsafe_memcmp (digest, tmpdigest, s->req_digest_length) !=0 ?EBADMSG :0 ; } static inline void
drivers/crypto/ipsec_mb/pmd_aesni_mb.c +3 -3
@@ -1902,7 +1902,7 @@ verify_docsis_sec_crc(IMB_JOB *job, uint8_t *status) crc = job->dst + crc_offset;/* Verify CRC (at the end of the message) */ -if (memcmp (job->auth_tag_output, crc,RTE_ETHER_CRC_LEN ) !=0 ) +if (rte_timingsafe_memcmp (job->auth_tag_output, crc,RTE_ETHER_CRC_LEN ) !=0 ) *status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }
@@ -1910,7 +1910,7 @@ static inline void verify_digest(IMB_JOB *job, void *digest, uint16_t len, uint8_t *status) {/* Verify digest if required */ -if (memcmp (job->auth_tag_output, digest, len) !=0 ) +if (rte_timingsafe_memcmp (job->auth_tag_output, digest, len) !=0 ) *status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }
@@ -2305,7 +2305,7 @@ verify_sync_dgst(struct rte_crypto_sym_vec *vec,for (i =0 , k =0 ; i != vec->num; i++) {if (vec->status[i] ==0 ) { -if (memcmp (vec->digest[i].va, dgst[i], len) !=0 ) +if (rte_timingsafe_memcmp (vec->digest[i].va, dgst[i], len) !=0 ) vec->status[i] =EBADMSG ;else k++;
drivers/crypto/ipsec_mb/pmd_snow3g.c +1 -1
@@ -269,7 +269,7 @@ process_snow3g_hash_op(struct ipsec_mb_qp *qp, struct rte_crypto_op **ops, &session->pKeySched_hash, iv, src, length_in_bits, dst);/* Verify digest. */ -if (memcmp (dst, ops[i]->sym->auth.digest.data, +if (rte_timingsafe_memcmp (dst, ops[i]->sym->auth.digest.data,SNOW3G_DIGEST_LENGTH ) !=0 ) ops[i]->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ;
drivers/crypto/ipsec_mb/pmd_zuc.c +1 -1
@@ -185,7 +185,7 @@ process_zuc_hash_op(struct ipsec_mb_qp *qp, struct rte_crypto_op **ops,*/ for (i =0 ; i < processed_ops; i++)if (sessions[i]->auth_op ==RTE_CRYPTO_AUTH_OP_VERIFY ) -if (memcmp (dst[i], ops[i]->sym->auth.digest.data, +if (rte_timingsafe_memcmp (dst[i], ops[i]->sym->auth.digest.data,ZUC_DIGEST_LENGTH ) !=0 ) ops[i]->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ;
Signature · 1 line
2.34.1
Re: [dpdk-dev v5 1/2] eal: introduce rte_timingsafe_memcmp() based on OpenBSD API
In reply to Kai JiQuoted 44 lines · Kai Ji
Bugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773Signed-off-by Kai Ji <[email protected]>--- lib/eal/include/rte_memory.h | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+)lib/eal/include/rte_memory.h +28
-0@@ -746,6 +746,44 @@ __rte_experimentalvoid rte_memzero_explicit (void *dst,size_t sz); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Constant-time memory comparison. +* +* This function compares two memory regions in constant time, making it +* resistant to timing side-channel attacks. The execution time depends only +* on the length parameter, not on the actual data values being compared. +* +* This is particularly important for cryptographic operations where timing +* differences could leak information about secret keys, passwords, or other +* sensitive data. +* +* @param a +* Pointer to the first memory region to compare +* @param b +* Pointer to the second memory region to compare +* @param n +* Number of bytes to compare +* @return +* 0 if the memory regions are identical, non-zero if they differ +*/ +__rte_experimental +static inline int +rte_timingsafe_memcmp (const void *a,const void *b,size_t n) +{ +const volatile uint8_t *pa = (const volatile uint8_t *)a;
lib/eal/include/rte_memory.h __rte_experimental · line 786
Quoted 10 lines
lib/eal/include/rte_memory.h +10
-0+const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result; +} +
Just wondering if it's worth doing:
#ifdef RTE_EXEC_ENV_FREEBSD
#define rte_timingsafe_memcmp timingsafe_memcmp
#else
...
#endif
to use the OS-provided function where possible.
/Bruce
Morten Brørup
NAKRE: [dpdk-dev v5 1/2] eal: introduce rte_timingsafe_memcmp() based on OpenBSD API
In reply to Kai JiQuoted 67 lines
From: Kai Ji [mailto:[email protected]]
Sent: Wednesday, 1 October 2025 17.33Bugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773Signed-off-by Kai Ji <[email protected]>--- lib/eal/include/rte_memory.h | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+)lib/eal/include/rte_memory.h +7
-0@@ -746,6 +746,44 @@ __rte_experimentalvoid rte_memzero_explicit (void *dst,size_t sz); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Constant-time memory comparison. +* +* This function compares two memory regions in constant time, making it
+ * resistant to timing side-channel attacks. The execution time depends only
+ * on the length parameter, not on the actual data values being compared.
+ *
+ * This is particularly important for cryptographic operations where timing
+ * differences could leak information about secret keys, passwords, or other
+ * sensitive data.
+ *
+ * @param a
+ * Pointer to the first memory region to compare
+ * @param b
+ * Pointer to the second memory region to compare
+ * @param n
+ * Number of bytes to compare
+ * @return
+ * 0 if the memory regions are identical, non-zero if they differ
+ */lib/eal/include/rte_memory.h +15
-1+__rte_experimental +static inline int +rte_timingsafe_memcmp (const void *a,const void *b,size_t n) +{ +const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result; +} + #ifdef __cplusplus }#endif --
Quoted 1 line
2.34.1
NAK.
This returns (binary) non-equality only. It does not return (tri-state) <0, 0, or >0, so it's not like memcmp or FreeBSD timingsafe_memcmp.
Also, please put the function ("memeq") first in the name, and then the extra property ("timingsafe") last, like rte_memzero_explicit. Like this:__rte_experimental
static inline boolrte_memeq_timingsafe(const void *a, const void *b, size_t n)
{
const volatile uint8_t *pa = (const volatile uint8_t *)a;
const volatile uint8_t *pb = (const volatile uint8_t *)b;
uint8_t result = 0;
size_t i;
for (i = 0; i < n; i++)
result |= pa[i] ^ pb[i];
return result == UINT8_C(0);
}Stephen, agree?
Re: [dpdk-dev v5 1/2] eal: introduce rte_timingsafe_memcmp() based on OpenBSD API
Quoted 89 lines · Morten Brørup
Quoted 67 lines
From: Kai Ji [mailto:[email protected]]
Sent: Wednesday, 1 October 2025 17.33Bugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773Signed-off-by Kai Ji <[email protected]>--- lib/eal/include/rte_memory.h | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+)lib/eal/include/rte_memory.h +7
-0@@ -746,6 +746,44 @@ __rte_experimentalvoid rte_memzero_explicit (void *dst,size_t sz); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Constant-time memory comparison. +* +* This function compares two memory regions in constant time, making it
+ * resistant to timing side-channel attacks. The execution time depends only
+ * on the length parameter, not on the actual data values being compared.
+ *
+ * This is particularly important for cryptographic operations where timing
+ * differences could leak information about secret keys, passwords, or other
+ * sensitive data.
+ *
+ * @param a
+ * Pointer to the first memory region to compare
+ * @param b
+ * Pointer to the second memory region to compare
+ * @param n
+ * Number of bytes to compare
+ * @return
+ * 0 if the memory regions are identical, non-zero if they differ
+ */lib/eal/include/rte_memory.h +15
-1+__rte_experimental +static inline int +rte_timingsafe_memcmp (const void *a,const void *b,size_t n) +{ +const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result; +} + #ifdef __cplusplus }#endif --Quoted 1 line
2.34.1
NAK.
This returns (binary) non-equality only. It does not return (tri-state) <0, 0, or >0, so it's not like memcmp or FreeBSDtimingsafe_memcmp.Also, please put the function ("memeq") first in the name, and then the extra property ("timingsafe") last, like
rte_memzero_explicit. Like this:__rte_experimental
static inline boolrte_memeq_timingsafe(const void *a, const void *b, size_t n){ const volatile uint8_t *pa = (const volatile uint8_t *)a; const volatile uint8_t *pb = (const volatile uint8_t *)b; uint8_t result = 0; size_t i; for (i = 0; i < n; i++) result |= pa[i] ^ pb[i]; return result == UINT8_C(0); }
Quoted 2 lines
Stephen, agree?
Not sure I agree with you on the naming. I'd rather see us adopt the BSD function (present on multiple BSDs) rather than rolling our own completely new function with new behaviour.
/Bruce
RE: [dpdk-dev v5 1/2] eal: introduce rte_timingsafe_memcmp() based on OpenBSD API
Quoted 101 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Thursday, 2 October 2025 10.10Quoted 9 lines · Morten Brørup
Quoted 9 lines
From: Kai Ji [mailto:[email protected]]
Sent: Wednesday, 1 October 2025 17.33Bugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773Signed-off-by Kai Ji <[email protected]>--- lib/eal/include/rte_memory.h | 38++++++++++++++++++++++++++++++++++++
Quoted 11 lines
Quoted 11 lines
1 file changed, 38 insertions(+)lib/eal/include/rte_memory.h +0
-0@@ -746,6 +746,44 @@ __rte_experimentalvoid rte_memzero_explicit (void *dst,size_t sz);Quoted 7 lines
lib/eal/include/rte_memory.h __rte_experimental
Quoted 7 lines
lib/eal/include/rte_memory.h +7
-0+/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Constant-time memory comparison. +* +* This function compares two memory regions in constant time, making
Quoted 7 lines
Quoted 7 lines
it
+ * resistant to timing side-channel attacks. The execution time depends only
+ * on the length parameter, not on the actual data values being compared.
+ *
+ * This is particularly important for cryptographic operationswhere
Quoted 2 lines
Quoted 2 lines
timing
+ * differences could leak information about secret keys,passwords, or
Quoted 11 lines
Quoted 11 lines
other
+ * sensitive data.
+ *
+ * @param a
+ * Pointer to the first memory region to compare
+ * @param b
+ * Pointer to the second memory region to compare
+ * @param n
+ * Number of bytes to compare
+ * @return
+ * 0 if the memory regions are identical, non-zero if theydiffer
Quoted 16 lines
Quoted 16 lines
+ */
lib/eal/include/rte_memory.h +15
-0+__rte_experimental +static inline int +rte_timingsafe_memcmp (const void *a,const void *b,size_t n) +{ +const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result; +} +Quoted 8 lines
Quoted 5 lines
#ifdef
__cplusplus
}
#endif
--
2.34.1NAK.
This returns (binary) non-equality only. It does not return (tri-state) <0, 0, or >0, so it's not like memcmp or FreeBSD
timingsafe_memcmp.Quoted 2 lines
Also, please put the function ("memeq") first in the name, and then
the extra property ("timingsafe") last, like
rte_memzero_explicit.Quoted 16 lines
Like this:
__rte_experimental
static inline boolrte_memeq_timingsafe(const void *a, const void *b, size_t n){ const volatile uint8_t *pa = (const volatile uint8_t *)a; const volatile uint8_t *pb = (const volatile uint8_t *)b; uint8_t result = 0; size_t i; for (i = 0; i < n; i++) result |= pa[i] ^ pb[i]; return result == UINT8_C(0); }
Quoted 8 lines
Quoted 2 lines
Stephen, agree?
Not sure I agree with you on the naming. I'd rather see us adopt the BSD
function (present on multiple BSDs) rather than rolling our own completely
new function with new behaviour.
I don't see any use for timing safe greater/less than comparison, only equality comparison. So I assume you are referring to NetBSD's consttime_memequal()?
Regarding the name of the function, I prefer consistent naming across DPDK, rather than aligning the names of a few functions that happen to exist in BSD with their names there. What happens when BSD introduces functions that already exist in DPDK?
Should we rename rte_memzero_explicit() to rte_explicit_bzero() to align with BSD?
I prefer rte_memeq_timingsafe() or rte_memeq_consttime(), but will not object to rte_consttime_memequal().
Quoted 2 lines
/Bruce
Re: [dpdk-dev v5 1/2] eal: introduce rte_timingsafe_memcmp() based on OpenBSD API
Quoted 110 lines · Morten Brørup
Quoted 101 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Thursday, 2 October 2025 10.10Quoted 9 lines · Morten Brørup
Quoted 9 lines
From: Kai Ji [mailto:[email protected]]
Sent: Wednesday, 1 October 2025 17.33Bugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773Signed-off-by Kai Ji <[email protected]>--- lib/eal/include/rte_memory.h | 38++++++++++++++++++++++++++++++++++++
Quoted 11 lines
Quoted 11 lines
1 file changed, 38 insertions(+)lib/eal/include/rte_memory.h +0
-0@@ -746,6 +746,44 @@ __rte_experimentalvoid rte_memzero_explicit (void *dst,size_t sz);Quoted 7 lines
lib/eal/include/rte_memory.h __rte_experimental
Quoted 7 lines
lib/eal/include/rte_memory.h +7
-0+/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Constant-time memory comparison. +* +* This function compares two memory regions in constant time, making
Quoted 7 lines
Quoted 7 lines
it
+ * resistant to timing side-channel attacks. The execution time depends only
+ * on the length parameter, not on the actual data values being compared.
+ *
+ * This is particularly important for cryptographic operationswhere
Quoted 2 lines
Quoted 2 lines
timing
+ * differences could leak information about secret keys,passwords, or
Quoted 11 lines
Quoted 11 lines
other
+ * sensitive data.
+ *
+ * @param a
+ * Pointer to the first memory region to compare
+ * @param b
+ * Pointer to the second memory region to compare
+ * @param n
+ * Number of bytes to compare
+ * @return
+ * 0 if the memory regions are identical, non-zero if theydiffer
Quoted 16 lines
Quoted 16 lines
+ */
lib/eal/include/rte_memory.h +15
-0+__rte_experimental +static inline int +rte_timingsafe_memcmp (const void *a,const void *b,size_t n) +{ +const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result; +} +Quoted 8 lines
Quoted 5 lines
#ifdef
__cplusplus
}
#endif
--
2.34.1NAK.
This returns (binary) non-equality only. It does not return (tri-state) <0, 0, or >0, so it's not like memcmp or FreeBSD
timingsafe_memcmp.Quoted 2 lines
Also, please put the function ("memeq") first in the name, and then
the extra property ("timingsafe") last, like
rte_memzero_explicit.Quoted 16 lines
Like this:
__rte_experimental
static inline boolrte_memeq_timingsafe(const void *a, const void *b, size_t n){ const volatile uint8_t *pa = (const volatile uint8_t *)a; const volatile uint8_t *pb = (const volatile uint8_t *)b; uint8_t result = 0; size_t i; for (i = 0; i < n; i++) result |= pa[i] ^ pb[i]; return result == UINT8_C(0); }Quoted 8 lines
Quoted 2 lines
Stephen, agree?
Not sure I agree with you on the naming. I'd rather see us adopt the BSD
function (present on multiple BSDs) rather than rolling our own completely
new function with new behaviour.
Quoted 9 lines
I don't see any use for timing safe greater/less than comparison, only equality comparison. So I assume you are referring to NetBSD's
consttime_memequal()?Regarding the name of the function, I prefer consistent naming across DPDK, rather than aligning the names of a few functions that happen to exist in BSD with their names there. What happens when BSD introduces functions that already exist in DPDK?
Should we renamerte_memzero_explicit()torte_explicit_bzero()to align with BSD?I prefer
rte_memeq_timingsafe()orrte_memeq_consttime(), but will not object torte_consttime_memequal().
Ok, point taken.
PATCH v6 1/2 eal: introduce rte_memeq_timingsafe() based on FreeBSD API
In reply to Kai JiBugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773
--- lib/eal/include/rte_memory.h | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+)
lib/eal/include/rte_memory.h +38 -0
@@ -746,6 +746,44 @@ __rte_experimentalvoid rte_memzero_explicit (void *dst,size_t sz); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Timing-safe memory equality comparison. +* +* This function compares two memory regions in constant time, making it +* resistant to timing side-channel attacks. The execution time depends only +* on the length parameter, not on the actual data values being compared. +* +* This is particularly important for cryptographic operations where timing +* differences could leak information about secret keys, passwords, or other +* sensitive data. +* +* @param a +* Pointer to the first memory region to compare +* @param b +* Pointer to the second memory region to compare +* @param n +* Number of bytes to compare +* @return +* true if the memory regions are identical, false if they differ +*/ +__rte_experimental +static inline bool +rte_memeq_timingsafe (const void *a,const void *b,size_t n) +{ +const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result ==UINT8_C (0 ); +} + #ifdef __cplusplus }#endif
Signature · 1 line
2.34.1
PATCH v6 2/2 crypto/ipsec-mb: use constant-time memory comparison
Replace memcmp() with rte_timingsafe_memcmp() in cryptographic authentication verification operations across iipsec-mb drivers.
Note: OpenSSL crypto driver already uses CRYPTO_memcmp() which provides equivalent timing attack resistance and is left unchanged.
Note: scheduler driver memcmp stays unchanged as its not secret data comparison and actually faster with no timing attack risk.
Bugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773
--- drivers/crypto/ipsec_mb/pmd_aesni_gcm.c | 5 ++--- drivers/crypto/ipsec_mb/pmd_aesni_mb.c | 6 +++--- drivers/crypto/ipsec_mb/pmd_snow3g.c | 4 ++-- drivers/crypto/ipsec_mb/pmd_zuc.c | 4 ++-- 4 files changed, 9 insertions(+), 10 deletions(-)
drivers/crypto/ipsec_mb/pmd_aesni_gcm.c +2 -3
@@ -206,7 +206,7 @@ post_process_gcm_crypto_op(struct ipsec_mb_qp *qp, tag, session->req_digest_length);#endif -if (memcmp (tag, digest, session->req_digest_length) !=0 ) +if (!rte_memeq_timingsafe (tag, digest, session->req_digest_length)) op->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }else {if (session->req_digest_length != session->gen_digest_length) {
@@ -558,8 +558,7 @@ aesni_gcm_sgl_op_finalize_decryption(const struct aesni_gcm_session *s, ops.finalize_dec (&s->gdata_key, gdata_ctx, tmpdigest, s->gen_digest_length); -return memcmp (digest, tmpdigest, s->req_digest_length) ==0 ?0 - :EBADMSG ; +return rte_memeq_timingsafe (digest, tmpdigest, s->req_digest_length) ?0 :EBADMSG ; } static inline void
drivers/crypto/ipsec_mb/pmd_aesni_mb.c +3 -3
@@ -1902,7 +1902,7 @@ verify_docsis_sec_crc(IMB_JOB *job, uint8_t *status) crc = job->dst + crc_offset;/* Verify CRC (at the end of the message) */ -if (memcmp (job->auth_tag_output, crc,RTE_ETHER_CRC_LEN ) !=0 ) +if (!rte_memeq_timingsafe (job->auth_tag_output, crc,RTE_ETHER_CRC_LEN )) *status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }
@@ -1910,7 +1910,7 @@ static inline void verify_digest(IMB_JOB *job, void *digest, uint16_t len, uint8_t *status) {/* Verify digest if required */ -if (memcmp (job->auth_tag_output, digest, len) !=0 ) +if (!rte_memeq_timingsafe (job->auth_tag_output, digest, len)) *status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }
@@ -2305,7 +2305,7 @@ verify_sync_dgst(struct rte_crypto_sym_vec *vec,for (i =0 , k =0 ; i != vec->num; i++) {if (vec->status[i] ==0 ) { -if (memcmp (vec->digest[i].va, dgst[i], len) !=0 ) +if (!rte_memeq_timingsafe (vec->digest[i].va, dgst[i], len)) vec->status[i] =EBADMSG ;else k++;
drivers/crypto/ipsec_mb/pmd_snow3g.c +2 -2
@@ -269,8 +269,8 @@ process_snow3g_hash_op(struct ipsec_mb_qp *qp, struct rte_crypto_op **ops, &session->pKeySched_hash, iv, src, length_in_bits, dst);/* Verify digest. */ -if (memcmp (dst, ops[i]->sym->auth.digest.data, -SNOW3G_DIGEST_LENGTH ) !=0 ) +if (!rte_memeq_timingsafe (dst, ops[i]->sym->auth.digest.data, +SNOW3G_DIGEST_LENGTH )) ops[i]->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ; }else {
drivers/crypto/ipsec_mb/pmd_zuc.c +2 -2
@@ -185,8 +185,8 @@ process_zuc_hash_op(struct ipsec_mb_qp *qp, struct rte_crypto_op **ops,*/ for (i =0 ; i < processed_ops; i++)if (sessions[i]->auth_op ==RTE_CRYPTO_AUTH_OP_VERIFY ) -if (memcmp (dst[i], ops[i]->sym->auth.digest.data, -ZUC_DIGEST_LENGTH ) !=0 ) +if (!rte_memeq_timingsafe (dst[i], ops[i]->sym->auth.digest.data, +ZUC_DIGEST_LENGTH )) ops[i]->status =RTE_CRYPTO_OP_STATUS_AUTH_FAILED ;
Signature · 1 line
2.34.1
Re: [dpdk-dev v6 2/2] crypto/ipsec-mb: use constant-time memory comparison
02/10/2025 17:32, Kai Ji:
Quoted 6 lines
Replace
memcmp()withrte_timingsafe_memcmp()in cryptographic authentication verification operations across iipsec-mb drivers.Note: OpenSSL crypto driver already uses
CRYPTO_memcmp()which provides equivalent timing attack resistance and is left unchanged.
Quoted 7 lines
Note: scheduler driver memcmp stays unchanged as its not secret data comparison and actually faster with no timing attack risk.
Bugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773Signed-off-by Kai Ji <[email protected]>
Applied with few minor edits, thanks.
RE: [dpdk-dev v6 1/2] eal: introduce rte_memeq_timingsafe() based on FreeBSD API
In reply to Kai JiQuoted 67 lines
From: Kai Ji [mailto:[email protected]]
Sent: Thursday, 2 October 2025 17.32Bugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773Signed-off-by Kai Ji <[email protected]>--- lib/eal/include/rte_memory.h | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+)lib/eal/include/rte_memory.h +7
-0@@ -746,6 +746,44 @@ __rte_experimentalvoid rte_memzero_explicit (void *dst,size_t sz); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Timing-safe memory equality comparison. +* +* This function compares two memory regions in constant time, making it
+ * resistant to timing side-channel attacks. The execution time depends only
+ * on the length parameter, not on the actual data values being compared.
+ *
+ * This is particularly important for cryptographic operations where timing
+ * differences could leak information about secret keys, passwords, or other
+ * sensitive data.
+ *
+ * @param a
+ * Pointer to the first memory region to compare
+ * @param b
+ * Pointer to the second memory region to compare
+ * @param n
+ * Number of bytes to compare
+ * @return
+ * true if the memory regions are identical, false if they differ
+ */lib/eal/include/rte_memory.h +15
-1+__rte_experimental +static inline bool +rte_memeq_timingsafe (const void *a,const void *b,size_t n) +{ +const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result ==UINT8_C (0 ); +} + #ifdef __cplusplus }#endif --
Quoted 1 line
2.34.1
Ji, Kai
Reviewed-by Morten BrørupRe: [dpdk-dev v6 1/2] eal: introduce rte_memeq_timingsafe() based on FreeBSD API
What needed to get it merged within RC1 window ?
________________________________
From: Morten Brørup <[email protected]>
Sent: Friday, October 03, 2025 08:35
To: Ji, Kai <[email protected]>; [email protected] <[email protected]>
Cc: [email protected] <[email protected]>; [email protected] <[email protected]>; Richardson, Bruce <[email protected]>; [email protected] <[email protected]>; [email protected] <[email protected]>
Subject: RE: [dpdk-dev v6 1/2] eal: introduce rte_memeq_timingsafe() based on FreeBSD API
Quoted 67 lines
From: Kai Ji [mailto:[email protected]]
Sent: Thursday, 2 October 2025 17.32Bugzilla ID: 1773
https://bugs.dpdk.org/show_bug.cgi?id=1773Signed-off-by Kai Ji <[email protected]>--- lib/eal/include/rte_memory.h | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+)lib/eal/include/rte_memory.h +7
-0@@ -746,6 +746,44 @@ __rte_experimentalvoid rte_memzero_explicit (void *dst,size_t sz); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Timing-safe memory equality comparison. +* +* This function compares two memory regions in constant time, making it
+ * resistant to timing side-channel attacks. The execution time depends only
+ * on the length parameter, not on the actual data values being compared.
+ *
+ * This is particularly important for cryptographic operations where timing
+ * differences could leak information about secret keys, passwords, or other
+ * sensitive data.
+ *
+ * @param a
+ * Pointer to the first memory region to compare
+ * @param b
+ * Pointer to the second memory region to compare
+ * @param n
+ * Number of bytes to compare
+ * @return
+ * true if the memory regions are identical, false if they differ
+ */lib/eal/include/rte_memory.h +15
-1+__rte_experimental +static inline bool +rte_memeq_timingsafe (const void *a,const void *b,size_t n) +{ +const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result ==UINT8_C (0 ); +} + #ifdef __cplusplus }#endif --
Quoted 1 line
2.34.1
Re: [dpdk-dev v2 1/2] eal: Add rte_consttime_memsq() to prevent timing attacks memcmp.
In reply to Kai JiQuoted 41 lines · On Fri, 26 Sep 2025 15:49:04 +0000 Kai Ji <[email protected]> wrote:
Bugzilla ID: 1773
Cc: [email protected][0] https://bugs.dpdk.org/show_bug.cgi?id=1773
Signed-off-by Kai Ji <[email protected]>--- lib/eal/include/rte_common.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)lib/eal/include/rte_common.h +23
-0@@ -700,6 +700,40 @@ rte_is_aligned(const void * const __rte_restrict ptr, const unsigned int align)return ((uintptr_t )ptr & (align -1 )) ==0 ; } +/** +* Constant-time memory inequality comparison. +* +* This function compares two memory regions in constant time, making it +* resistant to timing side-channel attacks. The execution time depends only +* on the length parameter, not on the actual data values being compared. +* +* This is particularly important for cryptographic operations where timing +* differences could leak information about secret keys, passwords, or other +* sensitive data. +* +* @param a +* Pointer to the first memory region to compare +* @param b +* Pointer to the second memory region to compare +* @param n +* Number of bytes to compare +* @return +* false if the memory regions are identical, true if they differ +*/ +static inline bool +rte_consttime_memneq (const void *a,const void *b,size_t n) +{
lib/eal/include/rte_common.h rte_is_aligned(const void * const __rte_restrict ptr, const unsigned int align) · line 735
Quoted 10 lines
lib/eal/include/rte_common.h +10
-0+const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result !=0 ; +}
New functions usually have to be marked experimental.
Since DPDK adopts many things from FreeBSD, perhaps the function should use the same naming conventions. That would mean
int rte_consttime_memequal(void *, void *, size_t len);
And will also need to update release notes.
Re: [dpdk-dev v2 1/2] eal: Add rte_consttime_memsq() to prevent timing attacks memcmp.
Quoted 57 lines · Stephen Hemminger
Quoted 41 lines · On Fri, 26 Sep 2025 15:49:04 +0000 Kai Ji <[email protected]> wrote:
Bugzilla ID: 1773
Cc: [email protected][0] https://bugs.dpdk.org/show_bug.cgi?id=1773
Signed-off-by Kai Ji <[email protected]>--- lib/eal/include/rte_common.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)lib/eal/include/rte_common.h +23
-0@@ -700,6 +700,40 @@ rte_is_aligned(const void * const __rte_restrict ptr, const unsigned int align)return ((uintptr_t )ptr & (align -1 )) ==0 ; } +/** +* Constant-time memory inequality comparison. +* +* This function compares two memory regions in constant time, making it +* resistant to timing side-channel attacks. The execution time depends only +* on the length parameter, not on the actual data values being compared. +* +* This is particularly important for cryptographic operations where timing +* differences could leak information about secret keys, passwords, or other +* sensitive data. +* +* @param a +* Pointer to the first memory region to compare +* @param b +* Pointer to the second memory region to compare +* @param n +* Number of bytes to compare +* @return +* false if the memory regions are identical, true if they differ +*/ +static inline bool +rte_consttime_memneq (const void *a,const void *b,size_t n) +{lib/eal/include/rte_common.h rte_is_aligned(const void * const __rte_restrict ptr, const unsigned int align) · line 735
Quoted 10 lines
lib/eal/include/rte_common.h +10
-0+const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i; + +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result !=0 ; +}New functions usually have to be marked experimental.
Quoted 6 lines
Since DPDK adopts many things from FreeBSD, perhaps the function should use the same naming conventions. That would mean
int
rte_consttime_memequal(void *, void *, size_t len);And will also need to update release notes.
+1 for removing the "not" from the name which avoids having double negatives in conditionals. Also agree with keeping consistency with BSD name.
/Bruce
Re: [dpdk-dev v2 1/2] eal: Add rte_consttime_memsq() to prevent timing attacks memcmp.
In reply to Kai JiQuoted 45 lines · On Fri, 26 Sep 2025 15:49:04 +0000 Kai Ji <[email protected]> wrote:
Bugzilla ID: 1773
Cc: [email protected][0] https://bugs.dpdk.org/show_bug.cgi?id=1773
Signed-off-by Kai Ji <[email protected]>--- lib/eal/include/rte_common.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)lib/eal/include/rte_common.h +27
-0@@ -700,6 +700,40 @@ rte_is_aligned(const void * const __rte_restrict ptr, const unsigned int align)return ((uintptr_t )ptr & (align -1 )) ==0 ; } +/** +* Constant-time memory inequality comparison. +* +* This function compares two memory regions in constant time, making it +* resistant to timing side-channel attacks. The execution time depends only +* on the length parameter, not on the actual data values being compared. +* +* This is particularly important for cryptographic operations where timing +* differences could leak information about secret keys, passwords, or other +* sensitive data. +* +* @param a +* Pointer to the first memory region to compare +* @param b +* Pointer to the second memory region to compare +* @param n +* Number of bytes to compare +* @return +* false if the memory regions are identical, true if they differ +*/ +static inline bool +rte_consttime_memneq (const void *a,const void *b,size_t n) +{ +const volatile uint8_t *pa = (const volatile uint8_t *)a; +const volatile uint8_t *pb = (const volatile uint8_t *)b; +uint8_t result =0 ; +size_t i;
lib/eal/include/rte_common.h rte_is_aligned(const void * const __rte_restrict ptr, const unsigned int align) · line 739
Quoted 10 lines
lib/eal/include/rte_common.h +7
-0+ +for (i =0 ; i < n; i++) + result |= pa[i] ^ pb[i]; + +return result !=0 ; +} +/*********** Macros for compile type checks ********/ /* Workaround for toolchain issues with missing C11 macro in FreeBSD */
Also need functional tests for any new function in the functional test suites. Just some basic tests, suggest using random data, and lengths; validate with memcmp. And/or see what freebsd already has.