AES分段加解密,分组模式采用CBC,填充方式采用PKCS7,对超大量数据进行分段加解密

AES分段加解密

HarmonyOS
2024-05-28 21:27:00
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
宇宙无敌超英俊

本文主要介绍AES的分段加解密,分组模式采用CBC,填充方式采用PKCS7,对超大量数据进行分段加解密。

使用的核心API

AES的生成规格

AES的分段加解密开发步骤

核心代码解释

我们需要注意:在进行对称加解密操作的时候,如果开发者对各个分组模式不够熟悉,建议对每次update和doFinal的结果都判断是否为null,并在结果不为null时取出其中的数据进行拼接,形成完整的密文/明文。这是因为选择的分组模式等各项规格都可能对update和doFinal结果产生影响。update只要凑满一个新的分组就会有输出,如果没有凑满则此次update输出为null,把当前还没被加/解密的数据留着,等下一次update/doFinal传入数据的时候,拼接起来继续凑分组。

最后doFinal的时候,会把剩下的还没加/解密的数据,根据createCipher时设置的padding模式进行填充,补齐到分组的整数倍长度,再输出剩余加解密结果。

根据数据量,可以不调用update(即init完成后直接调用doFinal)或多次调用update。

算法库目前没有对update(单次或累计)的数据量设置大小限制,建议对于大数据量的对称加解密,可以采用多次update的方式传入数据。

核心代码如下:

import cryptoFramework from '@ohos.security.cryptoFramework'; 
import { BusinessError } from '@ohos.base'; 
import buffer from '@ohos.buffer'; 
  
  
  
// 字符串转成字节流 
function stringToUint8Array(str: string) { 
  return new Uint8Array(buffer.from(str, 'utf-8').buffer); 
} 
  
// 字节流转成可理解的字符串 
function uint8ArrayToString(array: Uint8Array) { 
  // 将UTF-8编码转换成Unicode编码 
  let out: string = ""; 
  let index: number = 0; 
  let len: number = array.length; 
  while (index < len) { 
    let character = array[index++]; 
    switch (character >> 4) { 
      case 0: 
      case 1: 
      case 2: 
      case 3: 
      case 4: 
      case 5: 
      case 6: 
      case 7: 
        out += String.fromCharCode(character); 
        break; 
      case 12: 
      case 13: 
        out += String.fromCharCode(((character & 0x1F) << 6) | (array[index++] & 0x3F)); 
        break; 
      case 14: 
        out += String.fromCharCode(((character & 0x0F) << 12) | ((array[index++] & 0x3F) << 6) | ((array[index++] & 0x3F) << 0)); 
        break; 
      default: 
        break; 
    } 
  } 
  return out; 
} 
  
function genIvParamsSpec() { 
  let arr = [71,67,48,86,67,57,77,86,84,53,55,72,72,85,52,68]; 
  let dataIv = new Uint8Array(arr); 
  let ivBlob: cryptoFramework.DataBlob = { data: dataIv }; 
  let ivParamsSpec: cryptoFramework.IvParamsSpec = { 
    algName: "IvParamsSpec", 
    iv: ivBlob 
  }; 
  return ivParamsSpec; 
} 
  
async function testAesMultiUpdate(plainText: string) { 
    let symAlgName = 'AES128'; 
    let length = 30; 
    let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgName); 
    // 创建 Cipher 实例。 
    let cipherAlgName = 'AES128|CBC|PKCS7'; 
    let globalCipher = cryptoFramework.createCipher(cipherAlgName); 
    let globalCipherText: cryptoFramework.DataBlob; 
    let globalKey: cryptoFramework.SymKey; 
    let globalPlainText = ''; 
    let result = new Uint8Array(); 
    let str = ""; 
    let data: cryptoFramework.DataBlob 
    let startEecrypt = 0 
    let endEecrypt = 0 
    let startDecrypt = 0 
    let endDecrypt = 0 
  
    // 使用密钥生成器随机生成 128 位对称密钥。 
    let promiseSymKey = await symKeyGenerator.generateSymKey(); 
    await globalCipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, promiseSymKey, genIvParamsSpec()); 
    let updateOutput: cryptoFramework.DataBlob; 
  
    while (plainText.length > 0) { 
      const contentCurr = plainText.substring(0, length); // 超过长度会取最长 
      plainText = plainText.substring(length, plainText.length); // 起始点大于长度会返回"" 
      let messageBlob: cryptoFramework.DataBlob = { data: stringToUint8Array(contentCurr) }; 
      updateOutput = await globalCipher.update(messageBlob); 
      if (updateOutput != null) { 
        let mergeText = new Uint8Array(result.length + updateOutput.data.length); 
        mergeText.set(result); 
        mergeText.set(updateOutput.data, result.length); 
        result = mergeText; 
      } 
    } 
  
    globalCipherText = { data: result } 
    startEecrypt = new Date().getTime() 
    data = await globalCipher.doFinal(null); 
    endEecrypt = new Date().getTime() 
    console.log("TEST==jiami" + (endEecrypt - startEecrypt)) 
    let mergeText = new Uint8Array(result.length + data.data.length); 
    mergeText.set(result); 
    mergeText.set(data.data, result.length); 
    result = mergeText; 
  
    let resultTemp = new Uint8Array(); 
    let contentTemp = result; 
    console.log("TEST==加密成功") 
    await globalCipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, promiseSymKey, genIvParamsSpec()); 
  
  
    console.log("TEST==长度" + contentTemp.length) 
  
    while (contentTemp.length > 0) { 
      const contentCurr = contentTemp.slice(0, length); // 超过长度会取最长 
      contentTemp = contentTemp.slice(length, contentTemp.length); // 起始点大于长度会返回"" 
      let messageBlob: cryptoFramework.DataBlob = { data: contentCurr }; 
      let updateOutput = await globalCipher.update(messageBlob); // 按细分市场更新。 
      if (updateOutput != null) { 
        let mergeText = new Uint8Array(resultTemp.length + updateOutput.data.length); 
        mergeText.set(resultTemp); 
        mergeText.set(updateOutput.data, resultTemp.length); 
        resultTemp = mergeText; 
      } 
    } 
  
    //明文结果 
    str = uint8ArrayToString(resultTemp) 
    startEecrypt = new Date().getTime() 
    let mingwen: cryptoFramework.DataBlob 
    mingwen = await globalCipher.doFinal(null); 
    endEecrypt = new Date().getTime() 
    console.log("TEST== jiemi:" + (endEecrypt - startEecrypt)) 
  
    if (mingwen != null) { 
      str = str + uint8ArrayToString(mingwen.data); 
    } 
    AlertDialog.show({ message: str }); 
    console.info(`decrypt output: ${str}`); 
    endEecrypt = new Date().getTime() 
    console.log("TEST== startEecrypt:" + startEecrypt) 
    console.log("TEST== endEecrypt:" + endEecrypt) 
  
  
}

实现效果

适配的版本信息

  • IDE:DevEco    Studio 4.1.3.500
  • SDK:API11
分享
微博
QQ
微信
回复
2024-05-29 22:38:19
相关问题
AES加解密长字符串是否需要分段
444浏览 • 1回复 待解决
SM4采用OFB模式进行加解密
741浏览 • 1回复 待解决
SM4 CBC模式加解密,有好的方案吗?
902浏览 • 1回复 待解决
HarmonyOS AES加解密与java无法通用
350浏览 • 1回复 待解决
如何使用SM4的CBC模式加解密
722浏览 • 1回复 待解决
HarmonyOS 如何进行DES加解密
327浏览 • 1回复 待解决
如何进行不同规格的AES加解密
647浏览 • 1回复 待解决
HarmonyOS 加解密 demo
350浏览 • 1回复 待解决
多种加密方式实现加解密
892浏览 • 1回复 待解决
加解密问题的定位指导
237浏览 • 1回复 待解决
ARKUI采用什么模式进行开发?
232浏览 • 1回复 待解决
HarmonyOS 有RSA加解密相关吗
295浏览 • 0回复 待解决