HarmonyOS 鸿蒙Next SM2加解密格式的那些事

发布于 1周前 作者 nodeper 来自 鸿蒙OS

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库转换代码

BC.png

参考文档:

国密文档 http://www.gmbz.org.cn/main/viewfile/2018011001400692565.html

2 回复

HarmonyOS 鸿蒙Next SM2加解密格式需注意以下几点:SM2密钥需遵循GM/T 0009-2012标准,加密时密文可能需ASN.1序列化,解密前需相应解码。安卓与HarmonyOS间SM2密文、密钥格式可能不符,需转换。HarmonyOS支持SM2加密解密,但需注意API调用和格式要求。如果问题依旧没法解决请加我微信,我的微信是itying888。

回到顶部