马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?站点注册
×
PBIDEA:国密 SM4 对称加解密(ECB 与 CBC 两种模式)
在金融、政务等国内合规场景里,对称加密经常要求使用国密算法 SM4。PBIDEA 在 websuite.pbl 里提供了 sm4utils 对象,把 SM4 的 ECB / CBC / CTR / GCM 多种模式封装成了简单易用的函数,底层走 PbIdea.dll。本文只讲清楚一件事:如何用 sm4utils 做 SM4 的对称加解密,并得到一个可以存库或上链传输的密文。
一、为什么是 SM4
SM4 是国家密码管理局发布的分组密码算法,分组长度和密钥长度都是 128 位(16 字节),和 AES-128 强度相当。它属于对称算法:加密和解密使用同一个密钥,速度快,适合对大量业务数据做加解密。PBIDEA 的 sm4utils 帮我们屏蔽了 DLL 调用的细节,只暴露几个 PowerBuilder 函数。
二、sm4utils 的核心方法
sm4utils 是 autoinstantiate 的非可视对象,下面这些方法都是它的成员函数(来自 websuite.pbl/sm4utils.sru):
| 方法 | 作用 | | sm4_ecb(data, key, decrypto) | ECB 模式,decrypto=false 加密、true 解密 | | sm4_ecb(data, key, decrypto, padding) | ECB,可指定 padding(默认 PKCS7/PKCS5) | | sm4_cbc_encrypt(data, key, iv) | CBC 模式加密,需要 16 字节 IV | | sm4_cbc_decrypt(data, key, iv) | CBC 模式解密 | | BlobToHex(data) / HexToBlob(hex) | blob 与十六进制字符串互转 | | Base64Encode(data) / Base64Decode(b64) | blob 与 Base64 互转 |
注意:密钥、IV、明文进出函数时都是 blob 类型。字符串要用 PBIDEA 的全局函数 toUtf8("...") 转成 UTF-8 字节流;解密后拿到 blob,再用全局函数 fromUtf8(blob) 还原成字符串。toUtf8 / fromUtf8 是裸全局函数,不属于 sm4utils,不要把它们当作 sm4utils 的成员去调用。
三、ECB 模式:最简单的加解密
ECB 把明文按 16 字节分组各自加密,写法最直接,适合先理解接口:
- sm4utils sm
- blob lbl_plain, lbl_key, lbl_cipher, lbl_back
- string ls_key, ls_text, ls_dec
- ls_key = "1234567812345678" // SM4 密钥必须恰好 16 字节
- ls_text = "Hello SM4 国密"
- // 明文与密钥转成 blob
- lbl_plain = toUtf8(ls_text)
- lbl_key = toUtf8(ls_key)
- // 加密:decrypto=false
- lbl_cipher = sm.sm4_ecb(lbl_plain, lbl_key, false)
- // 解密:decrypto=true
- lbl_back = sm.sm4_ecb(lbl_cipher, lbl_key, true)
- ls_dec = fromUtf8(lbl_back)
- // ls_dec 应为 "Hello SM4 国密"
复制代码
四、CBC 模式:带 IV 的分组加密
CBC 在每组加密前用前一组的密文做异或,还需要一个初始化向量 IV(也是 16 字节)。它比 ECB 安全得多,生产环境推荐用它:
- sm4utils sm
- blob lbl_plain, lbl_key, lbl_iv, lbl_cipher, lbl_back
- string ls_key, ls_iv, ls_text, ls_dec
- ls_key = "1234567812345678" // 16 字节密钥
- ls_iv = "abcdefghijklmnop" // 16 字节 IV(应随机且唯一)
- ls_text = "敏感数据: 13800138000"
- lbl_plain = toUtf8(ls_text)
- lbl_key = toUtf8(ls_key)
- lbl_iv = toUtf8(ls_iv)
- // 加密
- lbl_cipher = sm.sm4_cbc_encrypt(lbl_plain, lbl_key, lbl_iv)
- // 解密
- lbl_back = sm.sm4_cbc_decrypt(lbl_cipher, lbl_key, lbl_iv)
- ls_dec = fromUtf8(lbl_back)
- // ls_dec 应为 "敏感数据: 13800138000"
复制代码
五、把密文变成可存储的字符串
sm4_* 返回的都是 blob,直接存库或放进 JSON 不方便,通常转成十六进制或 Base64:
- sm4utils sm
- blob lbl_cipher
- string ls_hex, ls_b64
- // 假设 lbl_cipher 已经加密得到
- ls_hex = sm.BlobToHex(lbl_cipher) // 转十六进制字符串
- ls_b64 = sm.Base64Encode(lbl_cipher) // 转 Base64 字符串
- // 反向:把字符串还原成 blob 再解密
- blob lbl_from_b64
- lbl_from_b64 = sm.Base64Decode(ls_b64)
复制代码
六、一个完整可运行的例子
把下面代码放进窗口按钮的 clicked 事件,配合几个输入框即可演示完整流程(CBC 模式):
- // cb_run clicked
- sm4utils sm
- blob lbl_plain, lbl_key, lbl_iv, lbl_cipher, lbl_dec
- string ls_result, ls_tip
- lbl_plain = toUtf8(sle_text.Text) // 明文
- lbl_key = toUtf8(sle_key.Text) // 16 字节密钥
- lbl_iv = toUtf8(sle_iv.Text) // 16 字节 IV(CBC 用)
- // 加密(推荐 CBC)
- lbl_cipher = sm.sm4_cbc_encrypt(lbl_plain, lbl_key, lbl_iv)
- // 展示为 Hex,便于复制存储
- ls_result = sm.BlobToHex(lbl_cipher)
- sle_out.Text = ls_result
- // 解密还原,确认可逆
- lbl_dec = sm.sm4_cbc_decrypt(lbl_cipher, lbl_key, lbl_iv)
- ls_tip = fromUtf8(lbl_dec)
- st_tip.Text = ls_tip
复制代码
布局上准备:sle_text(明文)、sle_key(16 字节密钥)、sle_iv(16 字节 IV)、sle_out(密文 Hex)、st_tip(解密回显)。
七、常见坑与注意事项
- 密钥长度固定 16 字节:用 toUtf8 转换时,字符串必须恰好 16 个字符(ASCII)或自行保证 16 字节;长度不对会导致加解密异常。
- ECB 不安全:相同明文会得到相同密文,容易暴露数据规律,仅适合学习或加密随机数据;生产请使用 CBC,或更安全的 GCM(sm4utils 提供 sm4_gcm_encrypt / sm4_gcm_decrypt)。
- IV 要随机且唯一:CBC 的 IV 不要求保密,但每次加密都应换新值、不重复;可把 IV 放在密文前面一起传输。
- padding 一致:默认 PKCS7/PKCS5 填充;若对接外部系统,可用 4 参重载 sm4_ecb(data, key, decrypto, padding) 显式指定,解密时保持与加密相同。
- 全局函数别写错:toUtf8 / fromUtf8 是 PBIDEA 全局函数,裸调用即可;BlobToHex / Base64Encode 等才是 sm4utils 的方法。
- 对象实例化:sm4utils 是 autoinstantiate 对象,直接声明 sm4utils sm 即可使用,无需 create;若习惯显式创建写 sm = create sm4utils 也完全合法。
八、小结
PBIDEA 的 sm4utils 让 PowerBuilder 程序原生支持国密 SM4:sm4_ecb 适合快速体验,sm4_cbc_encrypt / sm4_cbc_decrypt 是生产推荐;加解密以 blob 为桥梁,字符串经 toUtf8 进、经 fromUtf8 出;密文用 BlobToHex / Base64Encode 落地。记住「密钥 16 字节、IV 随机、CBC 优先」三条,就能把 SM4 稳稳用起来。 |