HarmonyOS 鸿蒙Next SM2加解密格式的那些事
HarmonyOS 鸿蒙Next SM2加解密格式的那些事
背景:
业务方在使用鸿蒙算法库侧SM2加密数据,进行云端服务侧解密时候,往往会出现解密失败情况。
原因:
因为不同端的数据格式不一致。
鸿蒙算法库侧:符合国密标准的ASN.1格式
云端服务侧(比如java BC库):裸密文C1C3C2直接拼接
数据分析:
鸿蒙算法库侧密文十六进制:307602202d99585268dde22bae157af805e869295c5f66e0d89555ec6e0640bc954646b702206b5dc6f77712286e5a9cc19ecd71aa80926d4b11b56d6e5b95056ee9d14ee560042057a7a7f75892cbea537e7581348e523698e2c96f8f73a97d802a9d1f72c66df4040e64e34ec3f9b32b46f245a90a417b
30:表示是ASN.1数据标志
76:后面长度(十六进制76转十进制也就是118)
0220:02 + 20(数据类型-INTEGER + 长度(十六进制20转十进制也就是32))
2d99585268dde22bae157af805e869295c5f66e0d89555ec6e0640bc954646b7:C1_X
0220:02 + 20(数据类型-INTEGER + 长度(十六进制20转十进制也就是32))
6b5dc6f77712286e5a9cc19ecd71aa80926d4b11b56d6e5b95056ee9d14ee560:C1_Y
0420:04 + 20(数据类型-OCTET_STRING + 长度(十六进制20转十进制也就是32))
57a7a7f75892cbea537e7581348e523698e2c96f8f73a97d802a9d1f72c66df4:C3
040e:04 + 0e(数据类型-OCTET_STRING + 长度(十六进制0e转十进制也就是14))
64e34ec3f9b32b46f245a90a417b:C2
云端服务侧(比如java BC库)密文十六进制:
042d99585268dde22bae157af805e869295c5f66e0d89555ec6e0640bc954646b76b5dc6f77712286e5a9cc19ecd71aa80926d4b11b56d6e5b95056ee9d14ee56057a7a7f75892cbea537e7581348e523698e2c96f8f73a97d802a9d1f72c66df464e34ec3f9b32b46f245a90a417b
04:表示未压缩
2d99585268dde22bae157af805e869295c5f66e0d89555ec6e0640bc954646b7:C1_X
6b5dc6f77712286e5a9cc19ecd71aa80926d4b11b56d6e5b95056ee9d14ee560:C1_Y
57a7a7f75892cbea537e7581348e523698e2c96f8f73a97d802a9d1f72c66df4:C3
64e34ec3f9b32b46f245a90a417b:C2
解决措施:
需要对加解密数据进行格式转换,以下三种方式均可。
1. 调用鸿蒙算法库的格式转换接口,鸿蒙(ts)只需要简单的js代码拼接处理即可。–API12开始支持
2. 鸿蒙(ts)通过js自己编写工具类解析ASN.1格式,自己拼接成C1C3C2格式数据。
3. 云端服务侧解密进行封装,把ASN.1格式转成裸密文C1C3C2格式。–参考链接 https://blog.csdn.net/weixin_43939128/article/details/105453286
示例代码(以下是方式一的例子)
interface SM2CipherTextSpec {
// 也被记作C1X
xCoordinate: bigint;
// 也被记作C1Y
yCoordinate: bigint;
// 也被记作C2
cipherTextData: Uint8Array;
// 也被记作C3
hashData: Uint8Array;
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>
伪代码:
import cryptoFramework from “@ohos.security.cryptoFramework”
import buffer from ‘@ohos.buffer’;
// 伪代码
function demo() {
// 1. SM2算法库加密获得DataBlob数据
let data: cryptoFramework.DataBlob;
// 2. 调用SM2密文转换接口获得SM2CipherTextSpec构造
let spec: cryptoFramework.SM2CipherTextSpec = cryptoFramework.SM2CryptoUtil.getCipherTextSpec(data, ‘C1C3C2’);
// 3. 自行拼接符合自己的裸密文格式,C1C3C2的十六进制为例子
let sm2Hex = getC1C3C2(spec);
// 4. C1C3C2十六进制可以调用云侧服务端了
}
function toHexWithPaddingZero(val: bigint) {
let length = 64;
let c1x = val.toString(16);
if (c1x.length > length) {
return c1x;
}
let padLength = length - c1x.length;
let returnVal = ‘’;
for (let i = 0; i < padLength; i++) {
returnVal += ‘0’
}
return returnVal += c1x;
}
function getC1C3C2(spec: cryptoFramework.SM2CipherTextSpec) {
let startPre = “04”;
// bigint 转十六进制需要补零,参考BC转换
let c1x = toHexWithPaddingZero(spec.xCoordinate);
let c1y = toHexWithPaddingZero(spec.yCoordinate);
let c3 = buffer.from(spec.hashData).toString(‘hex’);
let c2 = buffer.from(spec.cipherTextData).toString(‘hex’);
return startPre + c1x + c1y + c3 + c2;
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>
踩坑点:
1. BC库解密使用的是非压缩04,往往需要带上04前缀拼接,此动作如果服务端未处理,那么客户端第三步(鸿蒙ts)就得处理。
2. BC库在进行BigInteger转字节数组时,会进行补零操作,故js在BigInt转十六进制时候需要补齐64位,以下是BC库转换代码
参考文档:
国密文档 http://www.gmbz.org.cn/main/viewfile/2018011001400692565.html
HarmonyOS 鸿蒙Next SM2加解密格式需注意以下几点:SM2密钥需遵循GM/T 0009-2012标准,加密时密文可能需ASN.1序列化,解密前需相应解码。安卓与HarmonyOS间SM2密文、密钥格式可能不符,需转换。HarmonyOS支持SM2加密解密,但需注意API调用和格式要求。如果问题依旧没法解决请加我微信,我的微信是itying888。