场景描述
对于加解密在鸿蒙和安卓相互转换,以及鸿蒙安卓互调的各种场景下使用密文密钥的问题。
应用经常会遇到如下的业务诉求:
场景一: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私钥
根据密钥参数生成sm2公钥
加密消息
解密消息
使用过程中安卓和鸿蒙的格式转换介绍
场景二:
缺少基础的加解密示例(AES|ECB|PKCS7 demo)
方案
对于不同的分组模式下表中给出了相应的参数适用说明,代码以AES128为例,这里的密钥传入的为base64格式,偏移量IV为字符串,对于格式的可以参考格式转换。对于GCM的参数设置,这里给了IV的,其余参数参考IV的写法即可。模板中使用的加解密算法以及密钥规格可以参考以下链接:
对称密钥加解密算法规格:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/crypto-sym-encrypt-decrypt-spec-0000001774120458-V5?catalogVersion=V5
对称密钥生成和转换规格:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/crypto-sym-key-generation-conversion-spec-0000001821000065-V5
分组模式 | 适用的加解密方式 | 所需参数 | 备注 |
ECB | AES、SM4、3DES | 没有偏移量等参数 |
|
CBC、CTR、OFB、CFB | AES、SM4、3DES(不支持CTR) | 指明加解密参数iv。 - AES的iv长度为16字节 - 3DES的iv长度为8字节 - SM4iv长度为16字节。 |
|
GCM | AES | 指明加解密参数iv,长度为1~16字节,常用为12字节。 指明加解密参数aad,长度为0~INT_MAX字节,常用为16字节。 指明加解密参数authTag,长度为16字节。 | 在GCM模式下,需要从加密后的数据中取出末尾16字节,作为解密时初始化的认证信息 |
效果图


核心代码
ECB加解密模板
CBC加解密模板
GCM加解密模板
//GCM的参数设置
function genGcmParamsSpec() {
let arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // 12 bytes
let dataIv = new Uint8Array(arr);
let ivBlob: cryptoFramework.DataBlob = { data: dataIv };
arr = [0, 0, 0, 0, 0, 0, 0, 0]; // 8 bytes
let dataAad = new Uint8Array(arr);
let aadBlob: cryptoFramework.DataBlob = { data: dataAad };
arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // 16 bytes
let dataTag = new Uint8Array(arr);
let tagBlob: cryptoFramework.DataBlob = {
data: dataTag
};
// GCM的authTag在加密时从doFinal结果中获取,在解密时填入init函数的params参数中
let gcmParamsSpec: cryptoFramework.GcmParamsSpec = {
iv: ivBlob,
aad: aadBlob,
authTag: tagBlob,
algName: "GcmParamsSpec"
};
return gcmParamsSpec;
}
//加密
export async function aesEncryptGCM(text: string, key: string,iv:string): Promise<string> {
let globalResult = ""
try {
let cipherAlgName = 'AES128|GCM|PKCS5';
let globalCipher = cryptoFramework.createCipher(cipherAlgName);
let symAlgName = 'AES128';
let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgName);
let dataUint8Array = stringToUint8Array(key)
let keyBlob: cryptoFramework.DataBlob = { data: dataUint8Array }
let promiseSymKey = await symKeyGenerator.convertKey(keyBlob)
let getParamsSpec: cryptoFramework.GcmParamsSpec = genGcmParamsSpec();
getParamsSpec.iv = { data: stringToUint8Array(iv) }
await globalCipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, promiseSymKey, getParamsSpec);
let plainText: cryptoFramework.DataBlob = { data: stringToUint8Array(text) }
let res = await globalCipher.doFinal(plainText)
authTag = res.data.subarray(res.data.length - 16, res.data.length)//authTag
let a = res.data.subarray(0, res.data.length - authTag.length);//密文
globalResult = base.encodeToStringSync(a);
} catch (err) {
console.log(err.message)
}
return globalResult;
}
// 解密
export async function aesDecryptGCM(text: string, key: string) {
let globalResult = ""
try {
let cipherAlgName = 'AES128|GCM|PKCS5';
let globalCipher = cryptoFramework.createCipher(cipherAlgName);
let symAlgName = 'AES128';
let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgName);
let dataUint8Array = stringToUint8Array(key)
let keyBlob: cryptoFramework.DataBlob = { data: dataUint8Array }
let promiseSymKey = await symKeyGenerator.convertKey(keyBlob)
let getParamsSpec: cryptoFramework.GcmParamsSpec = genGcmParamsSpec();
getParamsSpec.authTag = {data:authTag}
getParamsSpec.iv = { data: stringToUint8Array(iv) }
await globalCipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, promiseSymKey, getParamsSpec);
let plainText: cryptoFramework.DataBlob = { data: base.decodeSync(text) }
let result = await globalCipher.doFinal(plainText)
globalResult = uint8ArrayToString(result.data);
console.log("解密后的明文==》" + globalResult)
} catch (err) {
console.log(err.message)
}
return globalResult;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.