Closed stuartZhang closed 3 years ago
大神,我以【左填充对齐】的方式,当遇到【明文】长度不是 16 字节的整数倍时,左填充 0 至 utf-8 字节数组的左侧,再执行【sm4 - cbc 加密】;另一方面,在【解密】过程中,先执行【sm4 - cbc 解密】,再扣掉【明文】utf-8 字节数组左侧的 0 字节,再将 utf-8 字节数组 变换成 utf-8 字符串。
上面这个作法的确可以成功地【加密】与【解密】本文密码信息。但是,要求【前端】与【后端】都使用我这套实现。
我想问:关于【填充对齐】方式,是否有规范的作法或统一的标准?
这样的话,【前端】可以接着使用您的库和 rust + wasm 包,而【后端】可以使用 JAVA 实现的【sm4 - cbc 解密】包。别我在【前端】加密之后,因为对【填充对齐】的约定与假设不同,造成【后端】JAVA 版的【sm4 - cbc 解密】不能获得正确的值。
CBC
以及 ECB
分组工作模式,本身依然是块密码,需要自己手动对齐数据至块大小的倍数为此。
同时 CFB64
在和块大小为 16 Bytes 的块密码协同工作时,也需要自己手动处理对齐问题。
你如果不想要自己手动处理对齐问题,可以选择其它不需要手动处理对齐数据的分组工作模式。 或者自己解决对齐问题。
我无法帮你选择任何方案。
@stuartZhang You may check PKCS7 padding.
大神,我已经根据您提供的资料自己实现了 PKCS7 的块对齐。
pub fn encrypt_cbc(text: &str, iv: &str, key: Option<String>) -> String {
let key = match key {
Some(value) => value,
None => CIPHER_IV.to_string()
};
let mut cipher = Sm4Cbc::new(key.as_bytes(), iv.as_bytes());
let cipher_text = text.as_bytes();
// 开始 - PKCS7 Padding 填充模式
let original_len = cipher_text.len();
// 下面:计算与 16 位大小的整数倍,差了几位。
// 1. 若被加密明文长度正好是 16 位块的整数倍,就强制再追加 16 位补齐位。而且,每一位 u8 值就是 16
// 2. 若被加密明文长度不是 16 位块的整数倍,就追加差的哪几位。而且,每一位 u8 值就是差的位数的个数。
let pad_len = Sm4Cbc::BLOCK_LEN - original_len % Sm4Cbc::BLOCK_LEN;
let mut cipher_text1: Vec<u8> = Vec::with_capacity(original_len + pad_len);
// 优先填上明文内容
cipher_text1.extend_from_slice(cipher_text);
// 再补上块对齐的补位
for _ in 0..pad_len as u8 {
cipher_text1.push(pad_len as u8);
}
// 结束 - PKCS7 Padding 填充模式
cipher.encrypt(&mut cipher_text1);
base64::encode(cipher_text1)
}
大神,您的 crypto 库真心地佬强大了。
其次,我在使用其提供的 sm4 - cbc 模式时,注意到被加密【明文】(utf-8 英文字母,数字与下划线)的长度必须是 16 的整数倍。16 被定义在属性 Sm4Cbc::BLOCK_LEN 内。
然后,我照做了。
(1)将【明文】字符串(比如,
abcde,123
)转换成 &[u8] 数组。 (2)若 &[u8] 数组的长度不是 16 的整数倍,则将其扩容至 16 的整数倍。 (3)扩容的新数组元素,填充值为 0。我做的左侧填充。于是,sm4 加密之。运行正常。牛!!
接着,将加密之后的新 &[u8] 做 base64 编码。发送给后端 web server。
接下来,后端先 base64 解码;再使用 crypto 库 sm4 - cbc 模式的解密 Public API 将【密文】解密为【明文】 &[u8]
最后,再使用 String::from_utf8() 将 【明文】 &[u8] 变形回【明文】 字符串。
但是,在这里我的问题来了。解密之后的明文字符串是
\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}abcde,123
我分析:上面左侧一连串的 \u{0} 是我在加密过程中,给 &[u8] 数组左填充的 0。右侧的解决结果 abcde,123 是正确的。太牛了!!!
大神,对于潜在任意长度的【明文】 字符串,我如何才能避免或解决(加密过程中)由 &[u8] 数组扩容(长度必须是 16 的整数倍)填充值 0 造成的 解密结果里的 \u{0} 呀?
大神,我不知道我在上面的描述是否清晰。但,还是请求您的帮助。下面附上我的代码:
大神,我想在项目里使用您这个加密库。sm4 - cbc 模式就差最后这么一点就搞定了。希望获得您的指点与帮助。