Guomi CLI 使用说明

Copy Markdown View Source

命令行工具提供 SM2/SM3/SM4 国密算法的直接操作能力。所有算法均为纯 Elixir 实现,无需运行时 OpenSSL 支持。

安装

mix escript.build

编译后在项目目录生成 guomi(Windows 下为 guomi.exe)。

全局用法

guomi <command> [options] [input]

输入解析规则

  • 未提供 [input] 时,从标准输入读取。
  • [input]--- 时,从标准输入读取。
  • 一个或多个普通参数均以空格连接后作为消息内容。
  • 使用 --file <path> 显式读取文件;--file - 从标准输入读取。
  • --file 与普通位置参数不能同时使用。
  • SM2 的 --message 优先于上述输入来源。

因此 guomi sm3 --hex hello 会直接计算文本 hello,不会尝试打开同名文件。

命令一览

命令说明
sm3计算 SM3 哈希
sm4SM4 加密/解密
sm2SM2 密钥生成、签名/验签、加密/解密
version显示版本信息
help显示帮助信息

sm3 — SM3 哈希

用法

guomi sm3 [options] [input]

选项

选项说明
--hex十六进制输出(默认输出原始二进制)
--file <path>从文件读取输入;使用 - 表示 stdin
--help显示帮助信息

输入来源

SM3 遵循全局输入解析规则

示例

# 从 stdin 读取,输出十六进制哈希
echo -n "hello" | guomi sm3 --hex
#=> becbbfaae6548b8bf0cfcad5a27183cd1be6093b1cceccc303d9c61d0a645268

# 从多个参数读取消息
guomi sm3 --hex hello world

# 从文件读取
guomi sm3 --hex --file document.txt

# 输出原始二进制(默认)
echo -n "hello" | guomi sm3

参考

SM3("abc") 标准测试向量:

echo -n "abc" | guomi sm3 --hex
#=> 66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0

sm4 — SM4 加密/解密

用法

guomi sm4 [options] [input]

选项

选项说明
--mode <ecb|cbc|ctr>加密模式,默认 ecb
--key <hex>必填。16 字节密钥,十六进制编码
--iv <hex>CBC 模式必填。16 字节初始向量,十六进制编码
--counter <hex>CTR 模式必填。16 字节大端初始计数器,十六进制编码
--decrypt解密模式(默认加密)
--hex快捷方式:加密时输出 hex,解密时输入为 hex
--input-hex输入视为十六进制文本
--output-hex输出为十六进制文本
--padding <pkcs7|none>填充方式,默认 pkcs7
--file <path>从文件读取输入;使用 - 表示 stdin
--help显示帮助信息

安全提示

  • ECB 模式只适合测试或兼容遗留系统,不建议用于新数据加密
  • CBC 模式必须为每次加密使用不可预测且不复用的 16 字节 IV
  • 同一密钥下 IV 复用会完全破坏机密性
  • ECB/CBC 均不提供消息认证;应用层需要单独保证完整性
  • CTR 的同一 key/counter 组合不得复用;CTR 不使用 padding,也不提供消息认证

示例

# ECB 加密,输出原始密文
echo "secret data" | guomi sm4 --key 0123456789abcdef0123456789abcdef

# ECB 加密,输出十六进制密文
echo "secret data" | guomi sm4 --key 0123456789abcdef0123456789abcdef --hex

# ECB 解密(输入为十六进制密文)
guomi sm4 --decrypt --hex --key 0123456789abcdef0123456789abcdef < ciphertext.hex

# CBC 加密
echo "secret data" | guomi sm4 --mode cbc \
  --key 0123456789abcdef0123456789abcdef \
  --iv 00112233445566778899aabbccddeeff

# CBC 解密
guomi sm4 --decrypt --mode cbc \
  --key 0123456789abcdef0123456789abcdef \
  --iv 00112233445566778899aabbccddeeff < ciphertext.bin

# --hex 模式解密
guomi sm4 --decrypt --mode cbc \
  --key 0123456789abcdef0123456789abcdef \
  --iv 00112233445566778899aabbccddeeff \
  --hex < ciphertext.hex

# 显式控制 hex 输入/输出
echo -n "736563726574" | guomi sm4 \
  --input-hex --output-hex \
  --key 0123456789abcdef0123456789abcdef

# 无填充(输入必须是 16 字节对齐)
echo -n "abcdefghijklmnop" | guomi sm4 \
  --key 0123456789abcdef0123456789abcdef \
  --padding none

# CTR(任意长度;不要复用相同的 key/counter)
echo -n "secret" | guomi sm4 --mode ctr --output-hex \
  --key 0123456789abcdef0123456789abcdef \
  --counter 00112233445566778899aabbccddeeff

sm2 — SM2 密钥生成、签名/验签、加密/解密

用法

guomi sm2 [options] [input]

通用选项

选项说明
--generate生成密钥对
--sign签名
--verify验签
--encrypt加密
--decrypt解密
--private-key <hex>私钥(32 字节,十六进制)
--public-key <hex>公钥(65 字节,04 前缀 + 32 字节 x + 32 字节 y,十六进制)
--message <msg>待签名/验签/加密的消息文本
--file <path>从文件读取消息或密文;使用 - 表示 stdin
--signature <hex>签名值(64 字节 raw r || s,十六进制,仅验签)
--ciphertext <hex>密文(十六进制,仅解密)
--user-id <id>启用标准 ZA 签名/验签,并指定用户 ID(仅 --sign/--verify
--standard使用标准 C1 || C3 || C2 加密/解密格式(仅 --encrypt/--decrypt
--help显示帮助信息

兼容性说明

  • 默认(未提供 --user-id / --standard)保持旧兼容行为,避免无提示改变已有脚本
  • 旧签名使用 SM3 预哈希 + raw 64 字节 r || s 格式,不计算 ZA
  • 旧加密使用 Guomi 内部 C1 || C2 || C3 格式(C1=65 字节临时公钥, C3=32 字节 SM3 MAC)。当前实现对超过 32 字节的消息重复 XOR 掩码,会泄露相隔 32 字节的明文 XOR 关系;仅用于兼容和测试,不得用于敏感数据或生产协议
  • 旧格式不应假定可与 OpenSSL 或其他 SM2 实现互通
  • 提供 --user-id 时签名计算 SM3(ZA || message),与标准实现和库 API sign_standard/3 一致
  • 提供 --standard 时加密使用标准 SM3 KDF 与 C1 || C3 || C2 裸格式,与库 API encrypt_standard/2 一致;仍拒绝空消息

示例

# 生成密钥对
guomi sm2 --generate
#=>
# Private Key:
# <32-byte-hex>
# Public Key:
# <65-byte-hex>

# 签名(从 stdin 读取消息)
echo "message to sign" | guomi sm2 --sign --private-key <hex-key>

# 签名(从 --message 参数读取)
guomi sm2 --sign --private-key <hex-key> --message "hello"

# 验签
guomi sm2 --verify \
  --public-key <hex-pubkey> \
  --signature <hex-signature> \
  --message "hello"

# 验签(从文件读取消息)
guomi sm2 --verify \
  --public-key <hex-pubkey> \
  --signature <hex-signature> \
  --file message.txt

# 加密
echo "secret message" | guomi sm2 --encrypt --public-key <hex-pubkey>

# 解密
guomi sm2 --decrypt \
  --private-key <hex-privkey> \
  --ciphertext <hex-ciphertext>

# 解密(文件内容必须是 hex 文本)
guomi sm2 --decrypt \
  --private-key <hex-privkey> \
  --file ciphertext.hex

# 标准签名(显式 user ID,计算 ZA,可与标准实现互通)
echo "message to sign" | guomi sm2 --sign --user-id 1234567812345678 --private-key <hex-key>

# 标准验签(必须传入相同 user ID)
guomi sm2 --verify --user-id 1234567812345678 \
  --public-key <hex-pubkey> \
  --signature <hex-signature> \
  --message "hello"

# 标准加密(C1 || C3 || C2,标准 SM3 KDF,拒绝空消息)
echo "secret message" | guomi sm2 --encrypt --standard --public-key <hex-pubkey>

# 标准解密
guomi sm2 --decrypt --standard \
  --private-key <hex-privkey> \
  --ciphertext <hex-ciphertext>

常见问题

Q: guomi sm3 --hexguomi sm3 输出有什么区别?

--hex 输出 64 字符十六进制小写字符串,末尾换行。不指定时输出原始 32 字节二进制数据,适合管道传递。

Q: SM4 的 --hex--input-hex--output-hex 有什么区别?

标志加密时解密时
--hex输出 hex输入为 hex
--input-hex输入为 hex输入为 hex
--output-hex输出 hex输出 hex
输入/输出均为原始二进制输入/输出均为原始二进制

Q: SM2 生成的密钥对格式是什么?

  • 私钥: 32 字节大端整数,十六进制编码(64 字符)
  • 公钥: 65 字节,0x04 前缀 + 32 字节 x 坐标 + 32 字节 y 坐标,十六进制编码(130 字符)

Q: Windows 下 guomi 运行报 SetConsoleMode 错误怎么办?

这是 OTP 28 在 Windows 上的兼容性问题。在运行前设置环境变量可绕过:

set ELIXIR_ERL_OPTIONS=-noinput
guomi version

或一次性命令:

set ELIXIR_ERL_OPTIONS=-noinput && guomi version

Q: 返回码约定?

场景退出码
操作成功0
输入错误/参数缺失1
验签失败(签名无效)1
SM2 不支持1

当前版本为纯 Elixir 实现,受支持运行时上的 SM2 不支持 分支不会在正常操作中出现。

格式与兼容性速查

数据格式
SM3 摘要32 字节;--hex 时为 64 个小写十六进制字符
SM4 key / CBC IV16 字节,以 32 个十六进制字符传入
SM2 私钥32 字节大端整数,hex 编码

| SM2 公钥 | 65 字节未压缩点 0x04 || x || y,hex 编码 | | SM2 签名 | 64 字节 raw r || s,hex 编码 | | SM2 CLI 密文 | 默认为旧兼容 C1 \|\| C2 \|\| C3 格式;提供 --standard 时为标准 C1 \|\| C3 \|\| C2 格式,均以 hex 编码 |