Repository navigation
Zephyr: make the constant-time AES option cover GHASH and the Arm assembly - #11691
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The Arm predicate incorrectly disables constant-time AES on baseline Cortex-M targets that do not compile symmetric assembly.
2 open findings
What changed in this PR
Updates Zephyr’s AES configuration so constant-time mode also covers GHASH and avoids incompatible Arm assembly paths.
Changes:
- Adds selectable constant-time, 4-bit, and 8-bit GHASH implementations.
- Restricts constant-time AES with Arm assembly.
- Adds Zephyr test scenarios and release documentation.
| File | Description |
|---|---|
zephyr/Kconfig |
Defines GHASH choices and constant-time constraints. |
zephyr/user_settings.h |
Maps GHASH selections to wolfCrypt macros. |
zephyr/samples/wolfssl_test/sample.yaml |
Adds configuration test scenarios. |
.wolfssl_known_macro_extras |
Registers new Zephyr macros. |
ChangeLog.md |
Documents the behavior change. |
🧠 Review effort: Balanced
Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.
CONFIG_WOLFSSL_AES_CONSTANT_TIME left two holes that the option and wolfPSA's psa_config.h check both missed. GHASH. The module hardcoded GCM_SMALL, whose GMULT branches on every bit of the hash subkey H. WOLFSSL_AES_TOUCH_LINES and WC_AES_BITSLICED only change the AES block cipher core, so AES-GCM was not constant time with the option on. The only constant-time C GHASH is the masked bitwise multiply wolfCrypt builds when no GCM method is defined. Add a GHASH choice. It defaults to that bitwise multiply, and offers the 4-bit and 8-bit tables as opt-ins that depend on !WOLFSSL_AES_CONSTANT_TIME. GCM_SMALL is no longer offered on plain C builds: it is not constant time either, and in a host autoconf build its GMAC ran at 16.6 MiB/s against 162 MiB/s for the bitwise multiply and 726 MiB/s for the 4-bit table. Assembly. With CONFIG_WOLFCRYPT_ASM on Arm the Thumb2, ARM32 and AArch64 assembly replaces the C AES core outright, and it indexes 1 KB T-tables with secret data. wolfCrypt has no macro to drop only the AES assembly, and the build accepted touch-lines alongside it without a word: on mps2/an521 the image linked AES_encrypt_block and L_AES_Thumb2_te_data. GHASH under the Arm assembly is a table or the bitwise multiply that branches on H, never the masked one. So the constant-time option is no longer available where the module builds the Arm symmetric assembly - ARMv7-M and ARMv8-M mainline, 32-bit Cortex-A/R and AArch64 - and the GHASH choice defaults to the 4-bit table there, with GCM_SMALL kept as a tableless option. A hidden WOLFCRYPT_ARM_SYMMETRIC_ASM now holds that core list, and user_settings.h and CMakeLists.txt test it instead of repeating the condition. AArch64 parts with the crypto extension lose the option too, because Kconfig cannot see that compiler feature. ARMv6-M and ARMv8-M baseline keep it: they get assembly for the SP math only. x86_64 is unaffected: USE_INTEL_SPEEDUP leaves the C AES core in place, so touch-lines takes effect. FIPS v2 and v5 pin an aes.c older than the masked multiply: v5 builds it only under AES_GCM_GMULT_CT and v2 not at all. Both keep GCM_SMALL as their default, so a validated build keeps its boundary object. Under v5 the constant-time choice also defines AES_GCM_GMULT_CT; under v2 it is not offered, and neither is the 4-bit table, which v2's aes.c predates. FIPS v6 and later have the masked multiply by default and can still pick GCM_SMALL to keep an existing boundary object. A configuration that set both options now gets a Kconfig warning and the option turned off, instead of table-based AES under a constant-time label. New wolfssl_test scenarios cover the two tables and the constant-time AES core on qemu_x86, and the 8-bit table under the Thumb2 and AArch64 assembly. All thirteen wolfssl_test scenarios pass on qemu_x86, qemu_x86_64, qemu_cortex_a53 and mps2/an521/cpu0, and the symbols confirm each one linked the GHASH it selected.
Frauschi
force-pushed
the
zephyr-ghash-ct
branch
from
October 8, 2026 13:00
ffaeb29 to
3cea47a
Compare
SparkiDev
approved these changes
Oct 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Description
CONFIG_WOLFSSL_AES_CONSTANT_TIME(added for wolfPSA, which requires a constant-time AES) had two holes.GHASH. The Zephyr module hardcoded
GCM_SMALL, whoseGMULT()branches on every bit of the hash subkey H.WOLFSSL_AES_TOUCH_LINESandWC_AES_BITSLICEDonly change the AES block cipher core, so AES-GCM was not constant time with the option on. The only constant-time C GHASH is the masked bitwise multiply wolfCrypt builds when no GCM method is defined.Assembly. With
CONFIG_WOLFCRYPT_ASMon Arm, the Thumb2, ARM32 and AArch64 assembly replaces the C AES core outright and indexes 1 KB T-tables with secret data. The build accepted touch-lines alongside it without a word: onmps2/an521the image linkedAES_encrypt_blockandL_AES_Thumb2_te_data. GHASH under the Arm assembly is likewise never the masked multiply.Changes
WOLFSSL_AES_GCM_GHASHchoice: bitwise multiply (constant time, the new default), 4-bit table (GCM_TABLE_4BIT) and 8-bit table (GCM_TABLE). The tables depend on!WOLFSSL_AES_CONSTANT_TIME.GCM_SMALLis no longer offered on plain C builds: it is not constant time either, and in a host autoconf build its GMAC ran at 16.6 MiB/s against 162 MiB/s for the bitwise multiply and 726 MiB/s for the 4-bit table.WOLFSSL_AES_CONSTANT_TIMEis no longer available whereCONFIG_WOLFCRYPT_ASMbuilds the Arm symmetric assembly: ARMv7-M and ARMv8-M mainline, 32-bit Cortex-A/R and AArch64, through a hiddenWOLFCRYPT_ARM_SYMMETRIC_ASM, whichuser_settings.handCMakeLists.txtnow test instead of repeating the core list. The GHASH choice defaults to the 4-bit table there; the 8-bit table andGCM_SMALL(no table) stay selectable. AArch64 parts with the crypto extension lose the option too, because Kconfig cannot see that compiler feature. ARMv6-M and ARMv8-M baseline keep it, since they get assembly for the SP math only. x86_64 is unaffected:USE_INTEL_SPEEDUPkeeps the C AES core, so touch-lines takes effect.aes.colder than the masked multiply (v5 builds it only underAES_GCM_GMULT_CT, v2 not at all). Both keepGCM_SMALLas their default, so a validated build keeps its boundary object. Under v5 the constant-time choice also definesAES_GCM_GMULT_CT; under v2 it is not offered, and neither is the 4-bit table, which v2'saes.cpredates. FIPS v6 and later have the masked multiply by default and can still pickGCM_SMALLto keep an existing boundary object.Behaviour change: a configuration that set both
CONFIG_WOLFCRYPT_ASMandCONFIG_WOLFSSL_AES_CONSTANT_TIMEon one of those Arm cores now gets a Kconfig warning and the constant-time option off, where it used to get table-based AES under a constant-time label. The default GHASH moves fromGCM_SMALLto the bitwise multiply (no ASM) or the 4-bit table (Arm ASM).Testing
wolfssl_testscenarios:ghash_table_4bit,ghash_table_8bitandaes_constant_timeonqemu_x86, plusasm_thumb2_ghash_table_8bit(mps2/an521/cpu0) andasm_aarch64_ghash_table_8bit(qemu_cortex_a53).west twister -T zephyr/samples/wolfssl_testonqemu_x86,qemu_x86_64,qemu_cortex_a53andmps2/an521/cpu0: 13 of 13 pass. The linked symbols confirm each scenario got the GHASH it selected: the maskedGMULTwith noRtable by default, the 64- and 512-byteRtables for the 4-bit and 8-bit choices, and the assemblyGCM_gmult_lenon Thumb2 and AArch64.user_settings.honly, no bundle here): v5 defaults toGCM_SMALLand its constant-time choice yieldsAES_GCM_GMULT_CT; v2 refuses the constant-time choice and the 4-bit table; v6 defaults to constant time, acceptsGCM_SMALL, and refuses it alongside constant-time AES.GCM_SMALLunder the Thumb2 assembly onmps2/an521/cpu0: passes, linking the CGMULT.mps2/an521, and stays available on the ARMv6-Mnucleo_g071rb, which then compiles the C AES core andGMULT.Follow-up
wolfPSA's
src/psa_config.hcheck looks only at the AES core and countsWOLFSSL_ARMASMas a hardware backend, so it still accepts both a non-constant-time GHASH and the table-based Arm assembly. That fix belongs in wolfPSA and will be a separate PR.