场景描述
对于加解密在鸿蒙和安卓相互转换,以及鸿蒙安卓互调的各种场景下使用密文密钥的问题。
应用经常会遇到如下的业务诉求:
场景一:SM2加解密,安卓和鸿蒙的sm2密文,密钥格式不符,不能直接使用,需要一定的转换。
场景二:AES加解密,缺少基础的加解密示例,在原有的文档示例基础上不知道如何修改。
方案描述
场景一:
对于使用sm2加解密,安卓生成的密钥拿到鸿蒙使用如何导入,密文如何去转换、鸿蒙生成的密文如何拿到安卓去解密。
方案
1、对于传入的密钥中公钥是带04的的十六进制的130位字符串,在传入的时候,密钥参数对应的格式为 04+x+y,x和y的长度是一致的,私钥的十六进制就直接放入对应的参数即可
传入不带04的十六进制的128位字符串,对应的格式就是x+y,代码中 keyStr.startsWith("04") ? keyStr.slice(2) : keyStr正是为了判断这个。
2、对于安卓加密的密文,鸿蒙这边的格式是ASN.1包裹的格式,因此鸿蒙这边解密的时候,需要先序列化:HexStrTouint8Array(new SM2_Ciphertext().i2d_SM2_Ciphertext("安卓的密文"));同理鸿蒙生成的密文要先解码:new SM2_Ciphertext().d2i_SM2_Ciphertext(uint8ArrayToHexStr(鸿蒙密文)),其中安卓的密文为十六进制字符串,鸿蒙密文为Uint8Array数组
具体实现如下:
效果图
核心代码
根据密钥参数生成sm2私钥
export async function convertStrToPriKey(keyStr: string): Promise<cryptoFramework.PriKey> {
let sk = BigInt("0x" + keyStr)
let priKeySpec: cryptoFramework.ECCPriKeySpec = {
params: cryptoFramework.ECCKeyUtil.genECCCommonParamsSpec('NID_sm2'),
sk: sk,
algName: "SM2",
specType: cryptoFramework.AsyKeySpecType.PRIVATE_KEY_SPEC
}
let keypairGenerator = cryptoFramework.createAsyKeyGeneratorBySpec(priKeySpec)
return await keypairGenerator.generatePriKey()
}
根据密钥参数生成sm2公钥
export async function convertStrToPubKey(keyStr: string): Promise<cryptoFramework.PubKey> {
let pubKeyStr = keyStr.startsWith("04") ? keyStr.slice(2) : keyStr
let pkPart1 = pubKeyStr.slice(0, pubKeyStr.length / 2)
let pkPart2 = pubKeyStr.slice(pubKeyStr.length / 2)
let pk: cryptoFramework.Point = {
x: BigInt("0x" + pkPart1),
y: BigInt("0x" + pkPart2),
}
let pubKeySpec: cryptoFramework.ECCPubKeySpec = {
params: cryptoFramework.ECCKeyUtil.genECCCommonParamsSpec('NID_sm2'),
pk: pk,
algName: "SM2",
specType: cryptoFramework.AsyKeySpecType.PUBLIC_KEY_SPEC
}
let keypairGenerator = cryptoFramework.createAsyKeyGeneratorBySpec(pubKeySpec)
return await keypairGenerator.generatePubKey()
}
加密消息
async function encryptMessagePromise(publicKey: cryptoFramework.PubKey, plainText: string) {
let cipher = cryptoFramework.createCipher('SM2_256|SM3')
await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, publicKey, null)
let encryptData = await cipher.doFinal({ data:stringToUint8Array(plainText) })
return encryptData
}
解密消息
async function decryptMessagePromise(privateKey: cryptoFramework.PriKey, cipherText: cryptoFramework.DataBlob) {
let decoder = cryptoFramework.createCipher('SM2_256|SM3')
await decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, privateKey, null)
let decryptData = await decoder.doFinal(cipherText)
return decryptData
}
使用过程中安卓和鸿蒙的格式转换介绍
export async function test(data: string) {
//十六进制的公私钥
let pubKeyStr = "0453402B95F3584F36B9A7129A6B5C6109F2DBC7C94BE7858DB66C48AF38CB5C3B76883EE4BF18E270607191E233EAC0A95ECFB8EF6FE80C5F782DE24F018DEB5F"
l