Skip to content

arch/arm64: AES using the Armv8 Cryptography Extension - #20193

Merged
xiaoxiang781216 merged 1 commit into
apache:masterfrom
royzah:arm64-crypto-aes
Sep 21, 2026
Merged

xiaoxiang781216 merged 1 commit into
apache:masterfrom
royzah:arm64-crypto-aes

Conversation

@royzah

@royzah royzah commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Why

NuttX emits no AES instruction on any core. arm64 has no runtime feature dispatch, so a part that implements the Cryptography Extension still runs https://github.com/apache/nuttx/blob/master/crypto/rijndael.c, which indexes eight 256-entry tables with key-dependent values and so has cache-dependent timing.

How

aes_cypher() for ECB, CBC and CTR on AESE, AESD and the MixColumns pair, registered with /dev/crypto beside https://github.com/apache/nuttx/blob/master/arch/arm/src/stm32h7/stm32_crypto.c, https://github.com/apache/nuttx/blob/master/arch/arm/src/sam34/sam_crypto.c and https://github.com/apache/nuttx/blob/master/arch/xtensa/src/esp32/esp32_crypto.c.

ID_AA64ISAR0_EL1.AES is read on every call, returning -ENOTSUP rather than trapping.

Point
the first version defined the crypto/aes.h entry points same five symbols as https://github.com/apache/nuttx/blob/master/crypto/aes.c, independent Kconfig gates, so enabling both failed to link. The aes_cypher() shape has no such clash
SubWord borrows AESE with a zero round key that yields the substituted word only if ShiftRows has nothing to move, so the word is replicated across all four columns first
the CTR counter is the last four bytes as https://github.com/apache/nuttx/blob/master/crypto/xform.c does, so both agree on what a stream looks like

Open, and why this is still a draft: xform.c, gmac.c, cmac.c and key_wrap.c reach AES through AES_CTX and keep the table version. Gating crypto/aes.c off when an arch provides those entry points would cover them. Happy to add that here.

Tested

NIST SP 800-38A appendix F, executing the instructions under qemu-aarch64:

ok ECB-128 encrypt/decrypt    ok CBC-192 encrypt/decrypt
ok ECB-256 encrypt/decrypt    ok CTR-128 encrypt/decrypt
ok CBC-128 encrypt/decrypt    ok ECB/CBC/CTR-128 in-place
ok reject keysize 20    ok reject CFB    ok reject size 17

In-place matters because /dev/crypto can pass one buffer as both source and destination. tools/nxstyle clean.

@github-actions github-actions Bot added Arch: arm64 Issues related to ARM64 (64-bit) architecture Size: M The size of the change in this PR is medium labels Sep 19, 2026
@github-actions

github-actions Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

Comment thread arch/arm64/src/common/arm64_aes.c Outdated
@github-actions github-actions Bot added Size: L The size of the change in this PR is large and removed Size: M The size of the change in this PR is medium labels Sep 20, 2026
Comment thread arch/arm64/Kconfig Outdated
Comment thread arch/arm64/src/common/arm64_crypto.c Outdated
Comment thread arch/arm64/src/common/arm64_aes.c Outdated
@royzah

royzah commented Sep 20, 2026

Copy link
Copy Markdown
Contributor Author

Closing. @xiaoxiang781216 asked to remove all three files, which is the whole change, and I would rather take that than guess at a third shape for it.

No loss on my side: the work this came from uses ChaCha20-Poly1305, so it never needed AES. Happy to reopen if anyone wants arm64 AES later, and the duplicate-symbol clash with crypto/aes.c noted above is worth knowing about whoever does.

@royzah royzah closed this Sep 20, 2026
@royzah

royzah commented Sep 20, 2026

Copy link
Copy Markdown
Contributor Author

@xiaoxiang781216 one question before I leave this, so I get it right next time: was the objection the location?

Every AES backend in the tree is chip-specific (stm32h7/stm32_aes.c, esp32/esp32_aes.c, sam34/sam_aes.c), and arch/arm64/src/common/ holds only core arch support, no device drivers. I put it there because the Armv8 extension is architectural rather than a chip peripheral, but that does cut against the convention.

Or was it that the crypto extension is optional in Armv8-A and arm64 has no runtime detection, so a kernel built with it faults on a core without it?

Happy either way, just want the reason rather than a guess. Reopen if it is worth reshaping.

@xiaoxiang781216

xiaoxiang781216 commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Closing. @xiaoxiang781216 asked to remove all three files, which is the whole change, and I would rather take that than guess at a third shape for it.

No loss on my side: the work this came from uses ChaCha20-Poly1305, so it never needed AES. Happy to reopen if anyone wants arm64 AES later, and the duplicate-symbol clash with crypto/aes.c noted above is worth knowing about whoever does.

sorry, I make the comment not clear, I mean remove #ifdef CONFIG_ARM64_CRYPTO_AES which is redundant since makefile already do the check, not the whole source file.
So, let's reopen your pr.

@royzah

royzah commented Sep 21, 2026

Copy link
Copy Markdown
Contributor Author

Closing. @xiaoxiang781216 asked to remove all three files, which is the whole change, and I would rather take that than guess at a third shape for it.
No loss on my side: the work this came from uses ChaCha20-Poly1305, so it never needed AES. Happy to reopen if anyone wants arm64 AES later, and the duplicate-symbol clash with crypto/aes.c noted above is worth knowing about whoever does.

sorry, I make the comment not clear, I mean remove #ifdef CONFIG_ARM64_CRYPTO_AES which is redundant since makefile already do the check, not the whole source file. So, let's reopen your pr.

No problem, thanks for reopening.

default n is gone: 9239d05

The two #ifdef CONFIG_ARM64_CRYPTO_AES were already out, the symbol is only in Kconfig, Make.defs and MakeLists now.

NuttX emits no AES instruction on any arm64 core. There is no runtime
feature dispatch in arch/arm64, so every AES goes through crypto/rijndael.c
or crypto/aes.c, and the table-driven one indexes memory with key-dependent
values, so its timing follows the cache.

Provide aes_cypher() for ECB, CBC and CTR built on AESE, AESD and the
MixColumns pair, and register it with /dev/crypto as a hardware driver
alongside the existing stm32h7, sam34 and esp32 modules.

ID_AA64ISAR0_EL1.AES is read on every call, which returns -ENOTSUP rather
than trapping on a core without the extension.

Verified against the NIST SP 800-38A appendix F vectors for ECB-128,
ECB-256, CBC-128, CBC-192 and CTR-128, encrypt and decrypt, in place and
out of place.

Signed-off-by: Royyan Zahir <royzah@gmail.com>
@royzah
royzah marked this pull request as ready for review September 21, 2026 10:13
@xiaoxiang781216
xiaoxiang781216 merged commit 72928d5 into apache:master Sep 21, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: arm64 Issues related to ARM64 (64-bit) architecture Size: L The size of the change in this PR is large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants