From 0e4d8f30a4f1a7bddb043ae10e9509dcdc728aa5 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Thu, 8 Oct 2026 17:28:41 +1000 Subject: [PATCH] sm4.c: use the common GHASH path for SM4-GCM on ARM assembly builds Fix the SM4-GCM usage of GMULT(). Fix sm4_gcm_calc_h too. --- .github/workflows/sm-aarch64-asm.yml | 88 ++++++++++++++++++++++++++++ sm4.c | 43 ++------------ 2 files changed, 94 insertions(+), 37 deletions(-) create mode 100644 .github/workflows/sm-aarch64-asm.yml diff --git a/.github/workflows/sm-aarch64-asm.yml b/.github/workflows/sm-aarch64-asm.yml new file mode 100644 index 0000000..9b241c3 --- /dev/null +++ b/.github/workflows/sm-aarch64-asm.yml @@ -0,0 +1,88 @@ +name: SM AArch64 Assembly Test + +# The ShangMi code has target specific paths that none of the other workflows +# reach: they all run on x86_64 and none enables WOLFSSL_ARMASM. SM4-GCM in +# particular borrows wolfSSL's GHASH from aes.c, whose ARM build keeps the hash +# subkey in a different representation and reflects it inside the bulk assembly +# rather than in the caller. This job builds for aarch64 and runs the SM +# self-tests there, so that the GHASH subkey handling and the non-12-byte nonce +# path - where the initial counter is itself a GHASH - stay covered. +# +# Built with the aarch64 cross toolchain and run under qemu-user, which is how +# wolfSSL's own multi-arch workflow covers this architecture. A native +# ubuntu-*-arm runner would also work and is faster, at the cost of being a +# different runner pool from every other job here. + +on: + push: + branches: [ '**' ] + pull_request: + branches: [ 'main', 'master', 'release/**' ] + schedule: + - cron: '0 5 * * *' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + resolve: + uses: ./.github/workflows/_resolve-wolfssl.yml + + build: + name: aarch64 ${{ matrix.config.name }} (wolfSSL ${{ matrix.wolfssl-ref }}) + needs: resolve + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + wolfssl-ref: ${{ fromJson(needs.resolve.outputs.refs) }} + config: + # The assembly build is the point of this workflow. + - name: armasm + flags: '--enable-armasm' + - name: armasm-sp-asm + flags: '--enable-armasm --enable-sp --enable-sp-asm' + # Same vectors, same architecture, C code only: tells an assembly + # fault apart from something that is wrong on aarch64 generally. + - name: c-only + flags: '' + env: + SM_FLAGS: >- + --enable-sm3 --enable-sm4-ecb --enable-sm4-cbc --enable-sm4-ctr + --enable-sm4-gcm --enable-sm4-ccm --enable-sm2 + QEMU_LD_PREFIX: /usr/aarch64-linux-gnu + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y autoconf automake libtool \ + crossbuild-essential-arm64 qemu-user qemu-user-binfmt + + - name: Checkout wolfsm + uses: actions/checkout@v4 + + - name: Build wolfSSL with wolfsm for aarch64 + run: | + set -euo pipefail + git clone --depth 1 --branch ${{ matrix.wolfssl-ref }} \ + https://github.com/wolfSSL/wolfssl.git ../wolfssl + ./install.sh ../wolfssl + cd ../wolfssl + ./autogen.sh + ./configure --host=aarch64-linux-gnu CC=aarch64-linux-gnu-gcc \ + $SM_FLAGS ${{ matrix.config.flags }} + make -j"$(nproc)" + + - name: wolfCrypt test (SM2/SM3/SM4 algorithm self-tests) + working-directory: ../wolfssl + run: ./wolfcrypt/test/testwolfcrypt + + - name: SM benchmark + working-directory: ../wolfssl + run: ./wolfcrypt/benchmark/benchmark -sm2 -sm3 -sm4-cbc -sm4-gcm -sm4-ccm diff --git a/sm4.c b/sm4.c index 69a33e3..ae015fe 100644 --- a/sm4.c +++ b/sm4.c @@ -1248,28 +1248,14 @@ int wc_Sm4CtrEncrypt(wc_Sm4* sm4, byte* out, const byte* in, word32 sz) */ static void sm4_gcm_calc_h(wc_Sm4* sm4, byte* iv) { -#if defined(__aarch64__) && defined(WOLFSSL_ARMASM) - word32* pt = (word32*)sm4->gcm.H; -#endif - /* Encrypt all zeros IV to create hash key for GCM. */ sm4_encrypt(sm4->ks, iv, sm4->gcm.H); -#if !defined(__aarch64__) || !defined(WOLFSSL_ARMASM) - #if defined(GCM_TABLE) || defined(GCM_TABLE_4BIT) - /* Generate table from hash key. */ - GenerateM0(&sm4->gcm); - #endif /* GCM_TABLE */ -#else - /* Reverse the bits of H for use in assembly. */ - __asm__ volatile ( - "LD1 {v0.16b}, [%[h]] \n" - "RBIT v0.16b, v0.16b \n" - "ST1 {v0.16b}, [%[out]] \n" - : [out] "=r" (pt) - : [h] "0" (pt) - : "cc", "memory", "v0" - ); -#endif +#if defined(GCM_TABLE) || defined(GCM_TABLE_4BIT) + /* Generate table from hash key. Plain H is what GHASH() and GenerateM0() + * take, on every target: aes.c reflects H only inside the bulk assembly + * calls and undoes it before storing. */ + GenerateM0(&sm4->gcm); +#endif /* GCM_TABLE */ } /* Increment counter for GCM. @@ -1324,9 +1310,6 @@ static void sm4_gcm_encrypt_c(wc_Sm4* sm4, byte* out, const byte* in, word32 sz, else { /* Counter is GHASH of nonce. */ GHASH(&sm4->gcm, NULL, 0, nonce, nonceSz, counter, SM4_BLOCK_SIZE); -#ifdef WOLFSSL_ARMASM - GMULT(counter, sm4->gcm.H); -#endif } /* Encrypt the initial counter for GMAC. */ sm4_encrypt(sm4->ks, counter, encCounter); @@ -1384,13 +1367,7 @@ static void sm4_gcm_encrypt_c(wc_Sm4* sm4, byte* out, const byte* in, word32 sz, } /* Calculate GHASH on additional authentication data and cipher text. */ -#ifndef WOLFSSL_ARMASM GHASH(&sm4->gcm, aad, aadSz, out, sz, tag, tagSz); -#else - GHASH(&sm4->gcm, aad, aadSz, out, sz, counter, SM4_BLOCK_SIZE); - GMULT(counter, sm4->gcm.H); - XMEMCPY(tag, counter, tagSz); -#endif /* XOR the encrypted initial counter into tag. */ xorbuf(tag, encCounter, tagSz); @@ -1437,18 +1414,10 @@ static int sm4_gcm_decrypt_c(wc_Sm4* sm4, byte* out, const byte* in, word32 sz, else { /* Counter is GHASH of nonce. */ GHASH(&sm4->gcm, NULL, 0, nonce, nonceSz, counter, SM4_BLOCK_SIZE); -#ifdef WOLFSSL_ARMASM - GMULT(counter, sm4->gcm.H); -#endif } /* Calculate GHASH on additional authentication data and cipher text. */ -#ifndef WOLFSSL_ARMASM GHASH(&sm4->gcm, aad, aadSz, in, sz, calcTag, sizeof(calcTag)); -#else - GHASH(&sm4->gcm, aad, aadSz, in, sz, calcTag, SM4_BLOCK_SIZE); - GMULT(calcTag, sm4->gcm.H); -#endif /* Encrypt the initial counter. */ sm4_encrypt(sm4->ks, counter, scratch); /* XOR the encrypted initial counter into calculated tag. */