【鸿蒙实战开发】HarmonyOS非对称加密-RSA

45 篇文章 0 订阅
38 篇文章 0 订阅

1. 介绍

本篇将介绍RSA非对称加密,官方也给出了一些样例使用代码,可供开发者参考。

本篇从实践出发,完整的通过代码方式来深入了解HarmonyOS中的非对称加密用法。

在这里插入图片描述

2. 基础概念

字符串样例:RSA1024|PKCS1|MD5|MGF1_MD5

1.密钥算法 : RSA
2.密文组长度 : 1024
3.填充模式 : PKCS1
4.摘要: MD5
5.摘要掩码: MGF1_MD5

关于“RSA算法”,“填充模式”, “摘要”, "摘要掩码"的具体概念,可自行搜索。

3. 实践

加密使用的测试数据源有三个,具体见下图

1.“92字节” (即,占用了92个字节的字符串)
2.“117字节” (即,占用了117个字节的字符串)
3.“128字节” (即,占用了128个字节的字符串)

3.1 MMI入口

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3.2 RSA加解密

●RSA加密算法密文分组长度有七种:512,718,1024,2048,3072,4096,8192;
●支持3种填充模式:NoPadding, PKCS1, PKCS1_OAEP;
●在PCKCS1_OAEP填充模式下,支持六种摘要:MD5, SHA1, SHA224, SHA256, SHA384, SHA512;
●在PCKCS1_OAEP填充模式下,支持六种摘要掩码:MGF1_MD5, MGF1_SHA1, MGF1_SHA224, MGF1_SHA256, MGF1_SHA384, MGF1_SHA512
本篇仅以1024密文组长度做为实践验证,默认选择“128字节”数据集

片段代码以 “RSA1024|PKCS1_OAEP|MD5|MGF1_MD5” 为例

在这里插入图片描述

3.2.1 加密

生成对动态密钥

//导入加密框架
import cryptoFramework from '@ohos.security.cryptoFramework';

......

//创建密钥生成器,参数为(密钥算法+密文组长度+素数,如:RSA1024|PRIMES_2)
let symKeyGenerator = cryptoFramework.createAsyKeyGenerator('RSA1024|PRIMES_2');

//生成对称密钥
let promiseSymKey = symKeyGenerator.generateKeyPair();

//获取密钥
promiseSymKey( key => {
   
 //密钥对
 this.keyPair = rsaKeyPair;

})

初始化Cipher

//创建Cipher
globalCipher = cryptoFramework.createCipher('RSA1024|PKCS1_OAEP|MD5|MGF1_MD5');

//使用公钥初始化Cipher
let mode = cryptoFramework.CryptoMode.ENCRYPT_MODE; 
globalCipher.init(mode, this.keyPair.pubKey, null)

加密

//文字转换为Uint8Array
const encoder = new util.TextEncoder()
let u8a_encoder = encoder.encodeInto('测试')

//封装Uint8Array 数据,必须是一个带data属性的对象
let plainText = { data: u8a_encoder };

//开始加密
let promiseUpdate = globalCipher.doFinal(plainText);

//获取加密结果
promiseUpdate( result => {

   //密文
   let this.cipherText = result.data
   
})

至此,加密已经结束。

3.2.2 解密

生成密钥对象

//创建密钥生成器,参数为(密钥算法+密文组长度+素数,如:RSA1024|PRIMES_2)
let symKeyGenerator = cryptoFramework.createSymKeyGenerator('RSA1024|PRIMES_2');

//密钥生成器使用密钥数据,开始生成密钥对象
symKeyGenerator.convertKey(this.keyPair.pubKey.getEncoded(), this.keyPair.priKey.getEncoded()).then( key => {

   //key 为生成的密钥对象
   
})

初始化Cipher

//创建Cipher
globalCipher = cryptoFramework.createCipher('RSA1024|PKCS1_OAEP|MD5|MGF1_MD5');

//初始化Cipher,参数keyPair.priKey由第一步生成的
let mode = cryptoFramework.CryptoMode.DECRYPT_MODE;
globalCipher.init(mode, keyPair.priKey
, null)

解密

//this.cipherText 代表密文,本篇文章中,此值来源于上述加密结果
globalCipher.doFinal({ data: this.cipherText })

3.2.3 注意点

这些是基于RSA1024场景下,实践出的结论

1.NoPadding填充模式下,明文字节长度必须为128个字节长度
2.PKCS1填充模式下,明文字节长度最大为117个字节
3.PKCS1_OAEP填充模式下,明文字节长度最大为92个字节
4.摘要和摘要掩码只有在PKCS1_OAEP填充模式下,才会出现在初始化Cipher参数中

3.2.4 源码

import cryptoFramework from '@ohos.security.cryptoFramework';
import util from '@ohos.util';
import Logger from '../../common/Logger';
import OriginData from './OriginData';
import emitter from "@ohos.events.emitter";

/**
 * 非对称密钥
 *    密钥算法:RSA
 *    密钥规格格式:(密钥算法名称 + 密钥长度) | 素数
 *    密钥长度:512,718,1024, 2048, 3072, 4096, 8192
 *    密钥规格列表:AES512|PRIMES_2, RSA768|PRIMES_2, RSA1024|PRIMES_2, RSA1024|PRIMES_3, RSA2048|PRIMES_2
 *               RSA2048|PRIMES_3, RSA3072|PRIMES_2, RSA3072|PRIMES_3, RSA4096|PRIMES_2, RSA4096|PRIMES_3
 *               RSA4096|PRIMES_4, RSA8192|PRIMES_2, RSA8192|PRIMES_3, RSA8192|PRIMES_4, RSA8192|PRIMES_5
 *
 * 非对称对称加密
 *    加密算法:RSA
 *    加密规格格式:密钥算法名称 + 密钥长度 + 填充模式 + [摘要 + 摘要掩码]
 *    密钥长度:512,718,1024, 2048, 3072, 4096, 8192
 *    填充模式:NoPadding,PKCS1,PKCS1_OAEP
 *    摘要: MD5, SHA1, SHA224, SHA256, SHA384, SHA512
 *    摘要掩码: MGF1_MD5, MGF1_SHA1, MGF1_SHA224, MGF1_SHA256, MGF1_SHA384, MGF1_SHA512
 *    加密规格样例:RSA512|NoPadding,RSA512|PKCS1,RSA512|PKCS1_OAEP|MD5|MGF1_SHA224
 *
 *
 */
class TestAsyRSAEncryptDecrypt {

  private  keyPair: cryptoFramework.KeyPair;

  private cipherText: Uint8Array;

  private algorithmWithLength: string = 'RSA1024'
  private paddingMode: string = 'NoPadding' //NoPadding,PKCS5,PKCS1_OAEP
  private digest: string = 'MD5' //MD5、SHA1、SHA224、SHA256、SHA384、SHA512
  private digestMask: string = 'MGF1_MD5' //MGF1_MD5、MGF1_SHA1、MGF1_SHA224、MGF1_SHA256、MGF1_SHA384、MGF1_SHA512

  //对称加密:RSA1024|PKCS1_OAEP|MD5|MGF1_MD5
  testAsyRASEncrypt(paddingMode: string, digest: string, digestMask, dataSource:number) {

    let globalCipher: cryptoFramework.Cipher

    let originData: string

    if(dataSource == 92){
      originData = OriginData.RSA_1024_CONTENT_92
    } else if(dataSource == 117){
      originData = OriginData.RSA_1024_CONTENT_117
    } else {
      originData = OriginData.RSA_1024_CONTENT_128
    }

    this.paddingMode = paddingMode
    this.digest = digest
    this.digestMask = digestMask

    let symKeyGenerator = cryptoFramework.createAsyKeyGenerator(this.algorithmWithLength+'|PRIMES_2');

    let promiseSymKey = symKeyGenerator.generateKeyPair();

    promiseSymKey.then( rsaKeyPair => {

      this.keyPair = rsaKeyPair;

      let p: string = ''

      for(let a of rsaKeyPair.priKey.getEncoded().data){
        p = p.concat(a+',')
      }
      Logger.d('原始私钥',p)

      let spec = ''
      if(this.paddingMode == 'PKCS1_OAEP'){
        spec = this.algorithmWithLength + '|' + this.paddingMode + '|' + this.digest + '|' + this.digestMask
      } else {
        spec = this.algorithmWithLength + '|' + this.paddingMode
      }

      console.log('加密规格:', spec)

      globalCipher = cryptoFramework.createCipher(spec);

      let mode = cryptoFramework.CryptoMode.ENCRYPT_MODE;

      return globalCipher.init(mode, this.keyPair.pubKey, null);

    }).then(() => {

        const encoder = new util.TextEncoder()
        let u8a_encoder = encoder.encodeInto(originData)

        Logger.d('开始加密')

        let plainText = { data: u8a_encoder };
        let promiseUpdate = globalCipher.doFinal(plainText);

        return promiseUpdate;

      }).then(updateOutput => {

        if(updateOutput != null && updateOutput.data != null){
          this.cipherText = updateOutput.data
          console.log('密文:', this.cipherText)
        }

      }).then(() => {

        this.testSymAESDecrypt()
        return

      }).catch( error => {
         console.error(`catch error, ${error.code}, ${error.message}`);
         this.notificationStatus('加密中-error',  error.code + '-' +  error.message)
      })

  }

  //非对称解密: RSA1024|PKCS1_OAEP|MD5|MGF1_MD5
  testSymAESDecrypt() {

    let globalCipher: cryptoFramework.Cipher

    let symKeyGenerator = cryptoFramework.createAsyKeyGenerator(this.algorithmWithLength);

    // 根据指定的二进制密钥数据,生成对称密钥对象
    symKeyGenerator.convertKey(this.keyPair.pubKey.getEncoded(), this.keyPair.priKey.getEncoded())
      .then( keyPair => {
        console.log('解密-初始化Cipher')
        let spec = ''
        if(this.paddingMode == 'PKCS1_OAEP'){
          spec = this.algorithmWithLength + '|' + this.paddingMode + '|' + this.digest + '|' + this.digestMask
        } else {
          spec = this.algorithmWithLength + '|' + this.paddingMode
        }
        globalCipher = cryptoFramework.createCipher(spec);

        let mode = cryptoFramework.CryptoMode.DECRYPT_MODE;

        let p: string = ''

        for(let a of keyPair.priKey.getEncoded().data){
          p = p.concat(a+',')
        }

        Logger.d('解密私钥',p)

        globalCipher.init(mode, keyPair.priKey, null);
        return

      })
      .then(() => {

        console.log('开始解密', '密文')
        return globalCipher.doFinal({ data: this.cipherText });

      })
      .then( updateOutput => {

        let textDecoder = util.TextDecoder.create()
        let key = textDecoder.decodeWithStream(updateOutput.data);

        Logger.d('解密完成1: ', key);
        this.notificationStatus('解密完成', key)

      })
      .catch(error => {
        console.error(`catch error, ${error.code}, ${error.message}`);
        this.notificationStatus('解密中-error',  error.code + '-' +  error.message)
      })

  }

   notificationStatus(status:string, result: string){
     // 定义一个eventId为1的事件,事件优先级为Low
     let event = {
       eventId: 202404063287,
       priority: emitter.EventPriority.HIGH
     };

     let eventData = {
       data: {
         "content": result,
         'status': status,
       }
     };

     // 发送eventId为1的事件,事件内容为eventData
     emitter.emit(event, eventData);
   }
}

export default new TestAsyRSAEncryptDecrypt();

3.4 实践结果

以1024长度分组,“92字节”,“117字节”, “128字节”作为数据源

数据集

//117字节,PKCS1 M最大
public static readonly RSA_1024_CONTENT_117: string =
        "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567"

//92字节,PKCS1_OAEP 最大
public static readonly RSA_1024_CONTENT_92: string =
  "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012"

//128字节,RSA|NoPadding 固定
public static readonly RSA_1024_CONTENT_128: string =
  "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
  + "1234567890123456789012345678"

组合实验结果

1.NoPadding填充模式下,使用“128字节”数据源, ✅
2.PKCS1填充模式下,使用“117字节”数据源 ,✅
3.PKCS1_OAEP填充模式下,使用“92字节”数据源 ,组合所有摘要和摘要掩码,✅

写在最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、openHarmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

鸿蒙(HarmonyOS NEXT)最新学习路线

在这里插入图片描述

有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

《鸿蒙 (OpenHarmony)开发入门教学视频》

在这里插入图片描述

《鸿蒙生态应用开发V3.0白皮书》

在这里插入图片描述

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

在这里插入图片描述

《鸿蒙开发基础》

●ArkTS语言
●安装DevEco Studio
●运用你的第一个ArkTS应用
●ArkUI声明式UI开发
.……
在这里插入图片描述

《鸿蒙开发进阶》

●Stage模型入门
●网络管理
●数据管理
●电话服务
●分布式应用开发
●通知与窗口管理
●多媒体技术
●安全技能
●任务管理
●WebGL
●国际化开发
●应用测试
●DFX面向未来设计
●鸿蒙系统移植和裁剪定制
……
在这里插入图片描述

《鸿蒙进阶实战》

●ArkTS实践
●UIAbility应用
●网络案例
……
在这里插入图片描述

获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料

  • 20
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值