【鸿蒙实战开发】基于加解密算法框架的常见规格问题

288 篇文章 0 订阅
251 篇文章 0 订阅

往期知识点整理

场景描述

对于加解密在HarmonyOS和安卓相互转换,以及HarmonyOS、安卓互调的各种场景下使用密文密钥的问题。

应用经常会遇到如下的业务诉求:

场景一:SM2加解密,安卓和HarmonyOS的sm2密文,密钥格式不符,不能直接使用,需要一定的转换。

场景二:AES加解密,缺少基础的加解密示例,在原有的文档示例基础上不知道如何修改。

方案描述

场景一:

对于使用sm2加解密,安卓生成的密钥拿到HarmonyOS使用如何导入,密文如何去转换、HarmonyOS生成的密文如何拿到安卓去解密。

方案

1、对于传入的密钥中公钥是带04的的十六进制的130位字符串,在传入的时候,密钥参数对应的格式为 04+x+y,x和y的长度是一致的,私钥的十六进制就直接放入对应的参数即可

传入不带04的十六进制的128位字符串,对应的格式就是x+y,代码中 keyStr.startsWith(“04”) ? keyStr.slice(2) : keyStr正是为了判断这个。

2、对于安卓加密的密文,HarmonyOS这边的格式是ASN.1包裹的格式,因此HarmonyOS这边解密的时候,需要先序列化:HexStrTouint8Array(new SM2_Ciphertext().i2d_SM2_Ciphertext(“安卓的密文”));同理HarmonyOS生成的密文要先解码:new SM2_Ciphertext().d2i_SM2_Ciphertext(uint8ArrayToHexStr(HarmonyOS密文)),其中安卓的密文为十六进制字符串,HarmonyOS密文为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

}

使用过程中安卓和 HarmonyOS 的格式转换介绍

export async function test(data: string) {

  //十六进制的公私钥

  let pubKeyStr = "0453402B95F3584F36B9A7129A6B5C6109F2DBC7C94BE7858DB66C48AF38CB5C3B76883EE4BF18E270607191E233EAC0A95ECFB8EF6FE80C5F782DE24F018DEB5F"

  let priKeyStr = "5B9270E0ADF86A101167610FCCD375A6549DC14E9225951EF3A4640F26D6CD9C"

  //安卓加密后的密文

  let a = "53ce193ad865c6d97742da78b18a21d0ca66200fe080284d774d5500915be2425cea2f310c9a423bc2d08ce5c1e78a75cfd66d88688a0e2076a45614307e4372aa10b514841cfe7bff08fc82d96bdf35754696571e5fbedd552d1ab7c54bff796a0e3fd72902";

  //根据密钥参数生成对应的公私钥

  let pk = await convertStrToPubKey(pubKeyStr)

  let sk = await convertStrToPriKey(priKeyStr)

  //加密

  let encryptText = await encryptMessagePromise(pk, data)

  //将加密的密文数据解码转换为安卓可用数据(用于HarmonyOS和安卓的交接)

  let b = new SM2_Ciphertext().d2i_SM2_Ciphertext(uint8ArrayToHexStr(encryptText.data))

  console.log("解码后数据=======>" + b)

  //解密得到结果

  let res = await decryptMessagePromise(sk, encryptText)

  console.log("a=======>" + uint8ArrayToString(res.data))

  //针对安卓的密文处理,转成HarmonyOS可用uint8Array数组数据

  let c = HexStrTouint8Array(new SM2_Ciphertext().i2d_SM2_Ciphertext(a))

  //对安卓生成的的密文进行解密

  let resa = await decryptMessagePromise(sk, { data:c })

}

场景二:

缺少基础的加解密示例(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

分组模式适用的加解密方式所需参数备注
ECBAES、SM4、3DES没有偏移量等参数
CBC、CTR、OFB、CFBAES、SM4、3DES(不支持CTR)指明加解密参数iv。
* AES的iv长度为16字节
* 3DES的iv长度为8字节
* SM4iv长度为16字节。
GCMAES指明加解密参数iv,长度为116字节,常用为12字节。<br/>指明加解密参数aad,长度为0INT_MAX字节,常用为16字节。
指明加解密参数authTag,长度为16字节。
在GCM模式下,需要从加密后的数据中取出末尾16字节,作为解密时初始化的认证信息

效果图

核心代码

ECB 加解密模板

//加密

async function aesEncrypt(text:string,puKey:string): Promise<string>{

  let globalResult = ""

  try {

    //这里已AES加解密为例支持AES、SM4、3DES

    let cipherAlgName = 'AES128|ECB|PKCS7';

    // 创建加解密对象

    let globalCipher = cryptoFramework.createCipher(cipherAlgName);

    //这里已AES加解密为例支持AES、SM4、3DES

    let symAlgName = 'AES128';

    //创建密钥对象

    let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgName);

    //将传入的base格式的密钥转为Uint8Array数组

    let dataUint8Array = base.decodeSync(puKey)

    let keyBlob: cryptoFramework.DataBlob = { data: dataUint8Array }

    //导入外部密钥

    let promiseSymKey = await symKeyGenerator.convertKey(keyBlob)

    //初始化

    await globalCipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, promiseSymKey, null);

    //加密

    let result = await globalCipher.doFinal({data:stringToUint8Array(text)})

    //将加密结果转换为base64格式,用于保存或者传递

    globalResult = base.encodeToStringSync(result.data);

  } catch (err) {

    console.log(err.message)

  }

  return globalResult;

}

// 解密

async function aesDecrypt(text: string, key: string) {

  let globalResult = ""

  try {

    //这里已AES加解密为例支持AES、SM4、3DES

    let cipherAlgName = 'AES128|ECB|PKCS7';

    // 创建加解密对象

    let globalCipher = cryptoFramework.createCipher(cipherAlgName);

    //这里已AES加解密为例支持AES、SM4、3DES

    let symAlgName = 'AES128';

    //创建密钥对象

    let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgName);

    //将传入的base格式的密钥转为Uint8Array数组

    let dataUint8Array = base.decodeSync(key)

    let keyBlob: cryptoFramework.DataBlob = { data: dataUint8Array }

    //导入外部密钥

    let promiseSymKey = await symKeyGenerator.convertKey(keyBlob)

    await globalCipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, promiseSymKey, null);

    let plainText: cryptoFramework.DataBlob = { data: base.decodeSync(text) }

    let result = await globalCipher.doFinal(plainText)

    //将解密后的结果result解码之后得到明文

    globalResult = uint8ArrayToString(result.data);

    console.log("解密后的明文==》" + globalResult)

  } catch (err) {

    console.log(err.message)

  }

}

CBC 加解密模板

//加密

async function aesEncrypt(text: string, key: string, iv:string): Promise<string> {

  let globalResult = ""

  try {

    //这里已AES加解密为例支持AES、SM4、3DES

    let cipherAlgName = 'AES128|CBC|PKCS7';

    let globalCipher = cryptoFramework.createCipher(cipherAlgName);

    //这里已AES加解密为例支持AES、SM4、3DES

    let symAlgName = 'AES128';

    let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgName);

    let dataUint8Array = base.decodeSync(key)

    let keyBlob: cryptoFramework.DataBlob = { data: dataUint8Array }

    let promiseSymKey = await symKeyGenerator.convertKey(keyBlob)

    let ivData = stringToUint8Array(iv);

    let ivdata: cryptoFramework.DataBlob = { data: ivData }; //偏移

    let iv: cryptoFramework.IvParamsSpec = { iv: ivdata, algName: 'IvParamsSpec' } //cbc 模式的参数

    await globalCipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, promiseSymKey, iv);

    let plainText: cryptoFramework.DataBlob = { data: this.stringToUint8Array(text) }

    let result = await globalCipher.doFinal(plainText)

    globalResult = base.encodeToStringSync(result.data);

  } catch (err) {

    console.log(err.message)

  }

  return globalResult;

}

// 解密

async function aesDecrypt(text: string, key: string,iv:string) {

  let globalResult = ""

  try {

    let cipherAlgName = 'AES128|CBC|PKCS7';

    let globalCipher = cryptoFramework.createCipher(cipherAlgName);

    let symAlgName = 'AES128';

    let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgName);

    let dataUint8Array = base.decodeSync(key)

    let keyBlob: cryptoFramework.DataBlob = { data: dataUint8Array }

    let promiseSymKey = await symKeyGenerator.convertKey(keyBlob)

    // /*设置偏移量 */

    let ivData = stringToUint8Array(iv);

    let ivdata: cryptoFramework.DataBlob = { data: ivData }; //偏移

    let iv: cryptoFramework.IvParamsSpec = { iv: ivdata, algName: 'IvParamsSpec' } //cbc 模式的参数

    await globalCipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, promiseSymKey, globalCbcParams);

    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;

}

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;

}

总是有很多小伙伴反馈说:鸿蒙开发不知道学习哪些技术?不知道需要重点掌握哪些鸿蒙开发知识点? 为了解决大家这些学习烦恼。在这准备了一份很实用的鸿蒙全栈开发学习路线与学习文档给大家用来跟着学习。

针对一些列因素,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植……等)技术知识点。

《鸿蒙 (Harmony OS)开发学习手册》(共计892页):https://gitcode.com/HarmonyOS_MN/733GH/overview

如何快速入门?

1.基本概念
2.构建第一个ArkTS应用
3.……

开发基础知识:

1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……

在这里插入图片描述

基于ArkTS 开发

1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

在这里插入图片描述

鸿蒙开发面试真题(含参考答案):https://gitcode.com/HarmonyOS_MN/733GH/overview

在这里插入图片描述

OpenHarmony 开发环境搭建

图片

《OpenHarmony源码解析》:https://gitcode.com/HarmonyOS_MN/733GH/overview

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……
  • 系统架构分析
  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

图片

OpenHarmony 设备开发学习手册:https://gitcode.com/HarmonyOS_MN/733GH/overview

图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值