liboqs icon indicating copy to clipboard operation
liboqs copied to clipboard

Absence of explicit deletion from memory of intermediate values

Open amossys-1 opened this issue 5 months ago • 9 comments

As of version 0.13.0 of liboqs, we found that there is no explicit deletion of intermediate sensitive data in memory for at least the following mechanisms:

  • KEM:
    • Classic McEliece
    • HQC
    • NTRU Prime
  • Signature:
    • CROSS
    • Falcon
    • ML-DSA
    • SPHINCS+

Furthermore, the liboqs implementation of the SHA-3 family does not contain a secure deletion of the internal state. As a consequence, a copy of sensitive values might still be present in memory in the heap when liboqs is compiled to use this implementation of the SHA-3 family. For example, the release of the internal state for SHAKE256 is:

static void SHA3_shake256_inc_ctx_release(OQS_SHA3_shake256_inc_ctx *state) {
	OQS_MEM_aligned_free(state->ctx);
}

And the function OQS_MEM_aligned_free() is a wrapper around a simple free().

amossys-1 avatar Jun 10 '25 15:06 amossys-1

Thanks for reporting this. We'd have different priorities for fixing this in the different algorithms. Here are some comments on that:

  • SHA3: High priority to fix, since this is used by many PQ algorithms and the code lives within the OQS code base.
  • ML-DSA: We plan to switch from the PQ-Crystals ML-DSA implementation to the PQ Code Package mldsa-native implementation in a couple of months once mldsa-native is ready.
  • SPHINCS+: We plan to remove this in a few months when we add SLH-DSA.
  • Falcon: Eventually NIST should release the FN-DSA spec and we'd want to update the code to that, at which point in time we'd want to have the behaviour you've mentioned fixed. Unclear what implementation would be the basis of FN-DSA in liboqs going forward.
  • CROSS: Still an experimental algorithm in the NIST PQC signatures competition, so lower priority. Implementation coming from upstream so we'd want them to make the change there or we'd have to patch it in, depending on how extensive the changes are.
  • HQC: Eventually NIST should release the HQC spec and we'd want to update the code to that, at which point in time we'd want to have the behaviour you've mentioned fixed. Unclear what implementation would be the basis of HQC in liboqs going forward.
  • NTRU Prime: Currently no plans to remove / substantially change this algorithm, so should be fixed either in liboqs or in upstream. How extensive are the changes?
  • Classic McEliece: Currently no plans to remove / substantially change this algorithm, so should be fixed either in liboqs or in upstream. How extensive are the changes?

dstebila avatar Jun 12 '25 14:06 dstebila

Thank you for your response.

We are glad to know that the ML-DSA will migrate to the PQ Code Package such as ML-KEM.

The changes for NTRU Prime and Classic McEliece would require to identify which functions allocate and manipulate sensitive data that are not used outside.

For example, random polynomial generation in NTRU Prime generates random data, then it is copied to the output buffer, but the values are not cleared from the stack.

Since there are many implementations for various security levels, it might be a little bit extensive.

amossys-1 avatar Jun 13 '25 07:06 amossys-1

If you are interested in helping with any of these, we'd be grateful to receive your assistance.

dstebila avatar Jun 16 '25 13:06 dstebila

Are explicit_bzero and memset_s the preferred methods in C code to zeroize memory? I'm happy to take a crack at some pieces of this - but wanted to get a sense of what the requirements are first.

aidenfoxivey avatar Jun 19 '25 20:06 aidenfoxivey

IE in this context one should probably rewrite OQS_MEM_aligned_free to include a call to memset_s, correct? That way the memory is zeroized before it is handed back to the system allocator to dole out.

static void SHA3_shake256_inc_ctx_release(OQS_SHA3_shake256_inc_ctx *state) {
	OQS_MEM_aligned_free(state->ctx);
}

aidenfoxivey avatar Jun 19 '25 20:06 aidenfoxivey

We have the OQS_MEM_cleanse function for this purpose, which will select one of memset_s and explicit_bzero if available.

SWilson4 avatar Jun 19 '25 20:06 SWilson4

We have the OQS_MEM_cleanse function for this purpose, which will select one of memset_s and explicit_bzero if available.

So it would just be a matter of placing those before the OQS_MEM_aligned_free within SHA3's routines for example?

aidenfoxivey avatar Jun 19 '25 20:06 aidenfoxivey

We have the OQS_MEM_cleanse function for this purpose, which will select one of memset_s and explicit_bzero if available.

So it would just be a matter of placing those before the OQS_MEM_aligned_free within SHA3's routines for example?

Yes, I believe so. If this is a common pattern, we could also create a secure aligned free function which combines the two.

SWilson4 avatar Jun 19 '25 21:06 SWilson4

Sorted out (part of?) the SHA3 implementation in https://github.com/open-quantum-safe/liboqs/pull/2171/commits/3491e9be0d6cf879592d9aee7fc10ba021865b89

aidenfoxivey avatar Jun 20 '25 00:06 aidenfoxivey