使用OpenSC的PKCS11-tool命令行工具对CloudHSM进行操作
本项目介绍如何使用 OpenSC 的 pkcs11-tool 命令行工具,结合 CloudHSM Client SDK 5 的 PKCS#11 库,在 Linux 原生命令行环境下完成对 CloudHSM 的加密与解密操作,填补官方 CloudHSM CLI 不支持加解密的空白,无需从 C 源码编译。内容涵盖 PKCS#11 SDK 和 pkcs11-tool 的安装、CloudHSM 初始化配置、密钥列出、使用 CloudHSM CLI 生成不可导出的 AES 密钥,以及通过 AES-CBC-PAD 机制完成文件加解密。文中还说明了 OpenSC 版本要求(≥0.23)、EXTRACTABLE 属性的已知行为差异,以及必须使用 --id 而非 --label 定位密钥等关键注意事项。
一、背景
CloudHSM 进行加密和解密一般是通过SDK进行,使用最多的是Java语言的JCE Provider SDK。除了在Java程序中调用外,在命令行下使用 java -jar xxxx.jar 命令也可以完成相应操作,当然,这样的交互命令不是命令行原生(Native Binary),而是在命令行下运行Java包。
CloudHSM 官方提供的 CloudHSM CLI 通常用于CloudHSM初始化、用户管理等操作,CloudHSM CLI 支持签名操作,但不支持加密和解密操作。因此不能将 CloudHSM CLI 直接用于数据加密。
如果要想在OS(一般生产环境是Linux)下执行操作系统原生的二进制程序完成加密等操作,通常是使用 CloudHSM PKCS#11 的SDK,基于 C 语言构建程序,经编译后在特定系统高版本下运行。这样的步骤相对繁琐,为了免去从源代码编译的过程,可使用 OpenSC 的 pkcs11-tool 命令行工具替代。
注意:Ubuntu 22.04 的软件源内置的 OpenSC 版本只有 0.22,只支持 –decrypt、–sign、–verify 等,不支持 –encrypt。也就是仅支持解密,不支持加密。因此如果需要命令行加密,那么需要 Ubuntu 24.04 安装 OpenSC 的 pkcs11-tool 软件包,其版本为 0.25(≥0.23 即支持 –encrypt 加密操作)。如果您的系统是 Ubuntu 22.04 不方便更换,那么还可以在 Ubuntu 22.04 系统上,下载 pkcs11-tool 最新版(大于 0.23 即可),然后本地编译,获得支持加密操作的可执行文件。
二、安装 CloudHSM 的 PKCS#11 SDK 和 PKCS11-tool
1、安装 CloudHSM 的 PKCS#11 SDK
注意:在之前一篇博客(点这里跳转)中介绍了Java代码使用 SunPKCS#11 库进行加密,即Java代码不引用CloudHSM JCE Provider SDK完成加密。本篇博客中要安装的是和这篇博客相同的库。如果您已经安装过,可跳过。
注意您的操作系统版本,本文末尾的参考文档有更多操作系统版本的下载地址。
# Ubuntu 24.04
wget https://s3.amazonaws.com/cloudhsmv2-software/CloudHsmClient/Noble/cloudhsm-pkcs11_latest_u24.04_amd64.deb
sudo apt install ./cloudhsm-pkcs11_latest_u24.04_amd64.deb
# Ubuntu 22.04
wget https://s3.amazonaws.com/cloudhsmv2-software/CloudHsmClient/Jammy/cloudhsm-pkcs11_latest_u22.04_amd64.deb
sudo apt install ./cloudhsm-pkcs11_latest_u22.04_amd64.deb
安装后 PKCS#11 库的路径为:/opt/cloudhsm/lib/libcloudhsm_pkcs11.so。
2、安装 OpenSC 的 pkcs11-tool
注意:本文开头的背景章节介绍了 OpenSC 的最低版本要求为 0.23 才可以支持加密操作,详见第一章背景章节。
OpenSC 是一套开源的 PKCS#11 封装,提供了多种操作系统预编译的二进制包,并且在 Ubuntu 系统内可直接通过 apt 命令安装。
sudo apt install opensc
即可完成安装。
三、基础操作
本文假设 CloudHSM 已经完成了初始化,并且设置了用于操作密钥的普通身份用户(非Admin用户)。
1、CloudHSM初始化和认证参数传递
在前文完成了 CloudHSM 的 PKCS#11 SDK 安装之后,还需要做初始化,初始化时候需要当前环境上有CloudHSM初始化时候用的CA证书文件。这里要替换 <HSM_IP> 为加密机的IP地址:
sudo /opt/cloudhsm/bin/configure-pkcs11 --hsm-ca-cert /opt/cloudhsm/etc/customerCA.crt
sudo /opt/cloudhsm/bin/configure-pkcs11 -a <HSM_IP>
如果是开发环境,CloudHSM 是单节点的集群,还需要关闭密钥可用性检查。如果是生产环境,大于1个节点,则不需要此命令。
sudo /opt/cloudhsm/bin/configure-pkcs11 --disable-key-availability-check
OpenSC 的 pkcs11-tool 通过 –login –pin 参数进行认证,PIN 格式为:<CU用户名>:<密码>。例如,CU 用户名为user01,密码为yourpassword,那么组合起来是:
pkcs11-tool --login --pin user01:yourpassword
2、列出 CloudHSM 上的密钥
pkcs11-tool \
--module /opt/cloudhsm/lib/libcloudhsm_pkcs11.so \
--login --pin user01:yourpassword \
--list-objects
返回的密钥即可看到密钥label标签信息。
注意:在
--list-objects的输出中可能出现warning: PKCS11 function C_GetAttributeValue(ALWAYS_AUTHENTICATE) failed: rv = CKR_ATTRIBUTE_TYPE_INVALID (0x12)。这是因为 OpenSC 的 pkcs11-tool 会尝试读取 PKCS#11 标准中的CKA_ALWAYS_AUTHENTICATE属性,而 CloudHSM Client SDK 5 的 PKCS#11 库不支持该可选属性。此 warning 可安全忽略,不影响密钥列出和后续加解密操作。
3、生成 AES128 密钥(此处需要 CloudHSM CLI 来生成,而非 OpenSC 的 pkcs11-tool)
注意:在 OpenSC 的 pkcs11-tool 工具中,针对密钥是否可导属性有一个已知问题,下面来详细讲述。
(1) CloudHSM 关于是否可导出参数的默认行为
CloudHSM SDK 的默认行为是:在没有显式声明导出参数 EXTRACTABLE 的时候,对称密钥默认设置为 EXTRACTABLE = true 即可导出,非对称密钥则默认是 EXTRACTABLE = false 不可导出。
(2) 使用 Java 代码和 JCE Provider SDK 的行为
之前在各种 Java sample code 中创建密钥时候,无论是对称密钥还是非对称密钥,一律显式声明 EXTRACTABLE = false 参数,强调密钥不可导出。由此在 CloudHSM 中创建密钥不可导出。
JCE Provider SDK 对用户显式声明传入的参数完全遵从。因此在 CloudHSM 中使用 JCE Provider 是最佳选择。
(3) OpenSC 的 pkcs11-tool 软件包的问题
OpenSC 的 pkcs11-tool 在创建对称密钥时,如果未指定 --extractable 选项,源码中会显式传入 CKA_EXTRACTABLE = FALSE。但是 CloudHSM Client SDK 5 对 C_GenerateKey 调用有一个特殊行为:对于 AES 等对称密钥,会忽略客户端传入的 CKA_EXTRACTABLE 值,强制按 SDK 默认策略(对称密钥=true)处理。因此通过 pkcs11-tool 创建的 AES 密钥,最终在 CloudHSM 中 EXTRACTABLE = true,可导出。pkcs11-tool 命令行本身也不提供覆盖该行为的参数。
以如下代码为例,创建好的AES密钥,在CloudHSM内的 EXTRACTABLE = true 是可导出的。
pkcs11-tool --module /opt/cloudhsm/lib/libcloudhsm_pkcs11.so \
--login --pin user01:yourpassword \
--keygen --key-type AES:16 \
--label "my-aes-key" \
--usage-decrypt \
如果您不希望密钥可导出,那么解决办法就是抛弃 OpenSC 的 pkcs11-tool,使用 PKCS#11 的 SDK,自行编写 C 语言代码,调用 C_GenerateKey,传递参数 CKA_EXTRACTABLE = FALSE。此时生成的密钥,在CloudHSM内就是 EXTRACTABLE = false 不可导出。
由于用 C 语言代码编写门槛较高,因此可回退到使用 CloudHSM CLI 来创建AES密钥并设置为不可导出,后续加密命令则继续回到 OpenSC 的 pkcs11-tool 工具。参考下一个小节。
(4) 使用 CloudHSM CLI 创建 AES 密钥
首先登录到 CloudHSM,执行如下命令启动CLI。
/opt/cloudhsm/bin/cloudhsm-cli interactive
以普通 user01 身份登录。执行如下命令:
login --username user01 --role crypto-user
输入 user01 的密码,登录成功。
执行如下命令生成一个密钥,注意这里设置了不可导出标签 EXTRACTABLE = false 即密钥不可导出。此外,参数 --key-length-bytes 16 设置为 16 则表示使用 AES128 密钥,设置为 32 则表示 AES256 密钥。
key generate-symmetric aes \
--key-length-bytes 16 \
--label "my-aes-128-key" \
--attributes extractable=false encrypt=true decrypt=true id=0x01
创建成功。从返回信息中可看到 EXTRACTABLE = false 不可导属性设置正确。这里使用了标签my-aes-128-key,此外额外添加了一个 id=0x01 的属性,后续将会继续使用。
注意:为什么要额外设置
id=0x01:OpenSC 的 pkcs11-tool 在执行--decrypt操作时,使用--label查找 AES 密钥会报错(CKR_KEY_TYPE_INCONSISTENT),导致解密失败。这是 pkcs11-tool 与 CloudHSM PKCS#11 实现组合产生的已知问题,在 OpenSC 0.26 版本中仍然存在。解决办法是:在创建密钥时显式设置id属性,后续加密和解密命令使用--id替代--label来定位密钥。
如果有多个密钥要查看详情,可以使用如下命令来组合,先查询密钥的 key-reference,然后代入命令查询单个密钥详情:
key list
key list --filter key-reference=xxxxxxxxxxxxxx --verbose
以上命令可看到密钥同时具有 label 标签和 id 这两个属性。后文 pkcs11-tool 使用 id 属性来检索密钥,做加密和解密操作。
4、使用 AES128 密钥加密文件
注意:本文开头的背景章节介绍了 OpenSC 的最低版本要求为 0.23 才可以支持加密操作,详见第一章背景章节。
在使用AES密钥加密时候,推荐使用 AES-CBC-PAD 算法,对长度不满16字节倍数的文件做填充。这是因为 AES 是分组密码,块大小固定为 16 字节。AES-CBC 模式在加密时逐块处理数据,要求输入数据长度必须是 16 字节的整数倍,否则加密会失败。为了支持任意长度的输入文件,这里使用 AES-CBC-PAD 模式,它会自动按照 PKCS#5/PKCS#7 标准将数据填充到 16 字节的整数倍,解密时自动去除填充。
首先创建一个文件用于加密测试。
echo 'Hello, CloudHSM is here!' > plaintext.txt
注意以下命令中,请替换CloudHSM的用户密钥、id、文件名等信息。
pkcs11-tool --module /opt/cloudhsm/lib/libcloudhsm_pkcs11.so \
--login --pin user01:yourpassword \
--encrypt --mechanism AES-CBC-PAD \
--id 01 \
--iv "00000000000000000000000000000000" \
--input-file plaintext.txt \
--output-file ciphertext.bin
关于
--iv参数:IV(Initialization Vector,初始化向量)是 CBC 模式加密的必需输入,长度必须是 16 字节(32 个十六进制字符,对应 AES 的 128 bit 块大小,与密钥长度 AES128/192/256 无关)。CBC 模式下,第一个明文块在加密前会先与 IV 做 XOR,其作用是让同一把密钥加密相同明文时产生不同密文,避免模式泄露。示例中 IV 全为 0 仅用于演示,便于加解密对照。生产环境中严禁使用全 0 或其他固定 IV,必须对每次加密使用密码学安全的随机 IV(例如openssl rand -hex 16),并与密文一同保存以供解密。IV 不是秘密,可以明文存储或传输(通常拼在密文前 16 字节),但不能复用。
5、解密
注意以下命令中,请替换CloudHSM的用户密钥、id、文件名等信息。
pkcs11-tool --module /opt/cloudhsm/lib/libcloudhsm_pkcs11.so \
--login --pin user01:yourpassword \
--decrypt --mechanism AES-CBC-PAD \
--id 01 \
--iv "00000000000000000000000000000000" \
--input-file ciphertext.bin \
--output-file decrypted.txt
四、参考文档
OpenSC Project - PKCS#11/MiniDriver
Install the PKCS #11 library for AWS CloudHSM Client SDK 5
Supported mechanisms for the PKCS #11 library for AWS CloudHSM Client SDK 5
最后修改于 2026-04-24