PBIDEA:国密 SM4 对称加解密(ECB 与 CBC 两种模式)
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 稳稳用起来。
页:
[1]