RE: [PATCH v2 04/17] hw/misc/aspeed_hace: Support the CTR mode for the crypto command

Kane Chen <[email protected]>
Newsgroups org.nongnu.qemu-arm,org.nongnu.qemu-devel
Message-ID <SI6PR06MB763107A6DB1D80EB841EE731F7DE2@SI6PR06MB7631.apcprd06.prod.outlook.com>
> -----Original Message-----
> From: Jamin Lin <[email protected]>
> Sent: Wednesday, July 15, 2026 11:33 AM
> To: Daniel P. Berrangé <[email protected]>; Cédric Le Goater
> <[email protected]>; Peter Maydell <[email protected]>; Steven Lee
> <[email protected]>; Troy Lee <[email protected]>; Kane Chen
> <[email protected]>; Andrew Jeffery
> <[email protected]>; Joel Stanley <[email protected]>; Eric Blake
> <[email protected]>; Markus Armbruster <[email protected]>; Fabiano
> Rosas <[email protected]>; Laurent Vivier <[email protected]>; Paolo Bonzini
> <[email protected]>; open list:All patches CC here
> <[email protected]>; open list:ASPEED BMCs
> <[email protected]>
> Cc: Jamin Lin <[email protected]>; Troy Lee
> <[email protected]>
> Subject: [PATCH v2 04/17] hw/misc/aspeed_hace: Support the CTR mode for
> the crypto command
> 
> The AST2600, AST1030 and later crypto engines add AES/DES/3DES CTR mode
> (HACE10[6:4] = 0b100) on top of the ECB/CBC modes shared with the AST2500.
> Decode the CTR selection, round the working buffers up to a whole block so the
> stream-like final block is still processed a block at a time, and write the
> counter advanced by the number of blocks consumed back to the context
> buffer so the driver can continue across requests.
> 
> Signed-off-by: Jamin Lin <[email protected]>
> ---
>  hw/misc/aspeed_hace.c | 50
> ++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 45 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index
> 3d3f1fc8dd..09d0515271 100644
> --- a/hw/misc/aspeed_hace.c
> +++ b/hw/misc/aspeed_hace.c
> @@ -42,6 +42,7 @@
>  #define  CRYPT_CMD_OP_MODE_MASK     (0x7 << 4)
>  #define  CRYPT_CMD_ECB              (0x0 << 4)
>  #define  CRYPT_CMD_CBC              (0x1 << 4)
> +#define  CRYPT_CMD_CTR              (0x4 << 4)
>  /* AES key length HACE10[3:2] */
>  #define  CRYPT_CMD_AES_KEY_LEN_MASK (0x3 << 2)
>  #define  CRYPT_CMD_AES256           (0x2 << 2)
> @@ -589,6 +590,9 @@ static bool crypt_decode_cmd(uint32_t cmd,
> QCryptoCipherAlgo *alg,
>      case CRYPT_CMD_CBC:
>          *mode = QCRYPTO_CIPHER_MODE_CBC;
>          break;
> +    case CRYPT_CMD_CTR:
> +        *mode = QCRYPTO_CIPHER_MODE_CTR;
> +        break;
>      default:
>          return false;
>      }
> @@ -652,6 +656,22 @@ static bool crypt_prepare_sg(AspeedHACEState *s,
> uint64_t addr,
>      return copied == len;
>  }
> 
> +/*
> + * Add @add to the big-endian counter block @ctr (@len bytes) in place,
> +so the
> + * CTR mode counter can be advanced by the number of blocks just
> consumed.
> + */
> +static void crypt_be_add(uint8_t *ctr, size_t len, uint64_t add) {
> +    size_t i = len;
> +
> +    while (i > 0 && add) {
> +        i--;
> +        add += ctr[i];
> +        ctr[i] = add & 0xff;
> +        add >>= 8;
> +    }
> +}
> +
>  /*
>   * Perform an AES/DES/3DES ECB/CBC operation. The source and destination
> are
>   * either single contiguous buffers (direct access mode) or scatter-gather
> @@ -677,6 +697,7 @@ static void do_crypt_operation(AspeedHACEState *s,
> uint32_t cmd)
>      uint64_t dst_addr;
>      size_t iv_offset;
>      size_t blocklen;
> +    size_t buf_len;
>      size_t keylen;
>      bool status;
> 
> @@ -729,8 +750,14 @@ static void do_crypt_operation(AspeedHACEState *s,
> uint32_t cmd)
>          return;
>      }
> 
> -    src_buf = g_malloc0(len);
> -    dst_buf = g_malloc0(len);
> +    /*
> +     * Round the working buffers up to a whole block. Block modes are
> already
> +     * block-aligned; the stream-like CTR mode may leave a partial final
> block
> +     * that the engine still processes a full block at a time.
> +     */
> +    buf_len = QEMU_ALIGN_UP(len, blocklen);
> +    src_buf = g_malloc0(buf_len);
> +    dst_buf = g_malloc0(buf_len);
> 
>      /* Gather the source into the bounce buffer, per the selected mode. */
>      src_addr = s->regs[R_CRYPT_SRC];
> @@ -751,7 +778,7 @@ static void do_crypt_operation(AspeedHACEState *s,
> uint32_t cmd)
>      }
> 
>      if (encrypt) {
> -        if (qcrypto_cipher_encrypt(cipher, src_buf, dst_buf, len,
> +        if (qcrypto_cipher_encrypt(cipher, src_buf, dst_buf, buf_len,
>                                     &local_err) < 0) {
>              qemu_log_mask(LOG_GUEST_ERROR, "%s: encrypt failed:
> %s\n",
>                            __func__, error_get_pretty(local_err)); @@
> -759,7 +786,7 @@ static void do_crypt_operation(AspeedHACEState *s,
> uint32_t cmd)
>              return;
>          }
>      } else {
> -        if (qcrypto_cipher_decrypt(cipher, src_buf, dst_buf, len,
> +        if (qcrypto_cipher_decrypt(cipher, src_buf, dst_buf, buf_len,
>                                     &local_err) < 0) {
>              qemu_log_mask(LOG_GUEST_ERROR, "%s: decrypt failed:
> %s\n",
>                            __func__, error_get_pretty(local_err)); @@
> -792,13 +819,26 @@ static void do_crypt_operation(AspeedHACEState *s,
> uint32_t cmd)
>           * output when encrypting, or of the input when decrypting. Write
> it
>           * back as the IV for the next request.
>           */
> -        next_iv = (encrypt ? dst_buf : src_buf) + len - blocklen;
> +        next_iv = (encrypt ? dst_buf : src_buf) + buf_len - blocklen;
>          if (address_space_write(&s->dram_as, ctx_addr + iv_offset,
>                                  MEMTXATTRS_UNSPECIFIED, next_iv,
> blocklen)) {
>              qemu_log_mask(LOG_GUEST_ERROR,
>                            "%s: Failed to write IV, addr=0x%"
> HWADDR_PRIx "\n",
>                            __func__, ctx_addr + iv_offset);
>          }
> +    } else if (mode == QCRYPTO_CIPHER_MODE_CTR) {
> +        /*
> +         * CTR chains on the counter, which advances by one per block.
> Add the
> +         * number of blocks processed (buf_len / blocklen) and write it
> back.
> +         */
> +        crypt_be_add(ctx + iv_offset, blocklen, buf_len / blocklen);
> +        if (address_space_write(&s->dram_as, ctx_addr + iv_offset,
> +                                MEMTXATTRS_UNSPECIFIED, ctx +
> iv_offset,
> +                                blocklen)) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: Failed to write IV, addr=0x%"
> HWADDR_PRIx "\n",
> +                          __func__, ctx_addr + iv_offset);
> +        }
>      }
>  }
> 
> --
> 2.43.0

Reviewed-by: Kane Chen <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.