鸿蒙OS开发问题:(ArkTS)【 RSA加解密,解决中文乱码等现象】

电子说

1.3w人已加入

描述

RSA加解密开始构建工具类就是举步维艰,官方文档虽然很全,但是还是有很多小瑕疵,在自己经过几天的时间,彻底解决了中文乱码的问题、分段加密的问题。

首先看官方示例代码(以RSA非对称加解密(多次调用doFinal实现分段)为例:):

import cryptoFramework from "@ohos.security.cryptoFramework"

function stringToUint8Array(str) {
  var arr = [];
  for (var i = 0, j = str.length; i < j; ++i) {
    arr.push(str.charCodeAt(i));
  }
  var tmpArray = new Uint8Array(arr);
  return tmpArray;
}

// 字节流转成可理解的字符串
function uint8ArrayToString(array) {
  let arrayString = '';
  for (let i = 0; i < array.length; i++) {
    arrayString += String.fromCharCode(array[i]);
  }
  return arrayString;
}

function encryptLongMessagePromise() {
  let globalPlainText = "This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
  "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
  "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
  "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
  "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
  "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
  "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
  "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!";
  let globalCipherOutput;
  let globalDecodeOutput;
  var globalKeyPair;
  let plainTextSplitLen = 64; // RSA每次加解密允许的原文长度大小与密钥位数和填充模式等有关,详细规格内容见overview文档
  let cipherTextSplitLen = 128; // RSA密钥每次加密生成的密文数据长度计算方式:密钥位数/8
  let keyGenName = "RSA1024";
  let cipherAlgName = "RSA1024|PKCS1";
  let asyKeyGenerator = cryptoFramework.createAsyKeyGenerator(keyGenName); // 创建非对称密钥生成器对象
  let cipher = cryptoFramework.createCipher(cipherAlgName); // 创建加密Cipher对象
  let decoder = cryptoFramework.createCipher(cipherAlgName); // 创建解密Decoder对象
  return new Promise((resolve, reject) = > {
    setTimeout(() = > {
      resolve("testRsaMultiDoFinal");
    }, 10);
  }).then(() = > {
    return asyKeyGenerator.generateKeyPair(); // 生成rsa密钥
  }).then(keyPair = > {
    globalKeyPair = keyPair; // 保存到密钥对全局变量
    return cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, globalKeyPair.pubKey, null);
  }).then(async () = > {
    globalCipherOutput = [];
    // 将原文按64字符进行拆分,循环调用doFinal进行加密,使用1024bit密钥时,每次加密生成128B长度的密文
    for (let i = 0; i < (globalPlainText.length / plainTextSplitLen); i++) {
      let tempStr = globalPlainText.substr(i * plainTextSplitLen, plainTextSplitLen);
      let tempBlob = { data : stringToUint8Array(tempStr) };
      let tempCipherOutput = await cipher.doFinal(tempBlob);
      globalCipherOutput = globalCipherOutput.concat(Array.from(tempCipherOutput.data));
    }
    console.info(`globalCipherOutput len is ${globalCipherOutput.length}, data is: ${globalCipherOutput.toString()}`);
    return;
  }).then(() = >{
    return decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, globalKeyPair.priKey, null);
  }).then(async() = > {
    globalDecodeOutput = [];
    // 将密文按128B进行拆分解密,得到原文后进行拼接
    for (let i = 0; i < (globalCipherOutput.length / cipherTextSplitLen); i++) {
      let tempBlobData = globalCipherOutput.slice(i * cipherTextSplitLen, (i + 1) * cipherTextSplitLen);
      let message = new Uint8Array(tempBlobData);
      let tempBlob = { data : message };
      let tempDecodeOutput = await decoder.doFinal(tempBlob);
      globalDecodeOutput += uint8ArrayToString(tempDecodeOutput.data);
    }
    if (globalDecodeOutput === globalPlainText) {
      console.info(`encode and decode success`);
    } else {
      console.info(`encode and decode error`);
    }
    return;
  }).catch(error = > {
    console.error(`catch error, ${error.code}, ${error.message}`);
  })
}
let plainTextSplitLen = 64; // RSA每次加解密允许的原文长度大小与密钥位数和填充模式等有关,详细规格内容见overview文档

注意点:在解密中,这句代码就是产生中文乱码的关键。

鸿蒙OS开发更多内容↓点击HarmonyOS与OpenHarmony技术
鸿蒙技术文档开发知识更新库gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md在这。或+mau123789学习,是v喔

鸿蒙OS

globalDecodeOutput += uint8ArrayToString(tempDecodeOutput.data);

好,加上我的代码

加密:

/**
 * 测试RSA加密
 */
export function textRsaEncryption(value: string) {
  let keyGenName = "RSA1024";
  let cipherAlgName = "RSA1024|PKCS1";
  //64 RSA每次加解密允许的原文长度大小与密钥位数和填充模式等有关,详细规格内容见overview文档
  let plainTextSplitLen = 117;
  let globalKeyPair; //密钥对
  let globalEncryptionOutput; //加密输出
  let arrTest = StringUtils.string2Uint8Array1(value);
  //创建非对称密钥生成器对象
  let asyKeyGenerator = cryptoFramework.createAsyKeyGenerator(keyGenName);
  // 创建加密Cipher对象
  let cipherEncryption = cryptoFramework.createCipher(cipherAlgName);

  return new Promise((resolve, reject) = > {
    setTimeout(() = > {
      resolve("textRsaEncryption");
    }, 10);
  })
    .then(() = > {
      let base64 = Base64.getInstance()
      let pubKeyBlob = { data: new Uint8Array(base64.decode(publicKey)) }
      let priKeyBlob = { data: new Uint8Array(base64.decode(privateKey)) }
      return asyKeyGenerator.convertKey(pubKeyBlob, priKeyBlob);
    })
    .then(keyPair = > {
      globalKeyPair = keyPair; // 保存到密钥对全局变量
      return cipherEncryption.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, globalKeyPair.pubKey, null);
    }).then(async () = > {
      globalEncryptionOutput = [];

      // 将原文按64字符进行拆分,循环调用doFinal进行加密,使用1024bit密钥时,每次加密生成128B长度的密文
      for (let i = 0; i < (arrTest.length / plainTextSplitLen); i++) {
        let tempArr = arrTest.slice(i * plainTextSplitLen, (i + 1) * plainTextSplitLen);
        let tempBlob = { data: tempArr };
        let tempCipherOutput = await cipherEncryption.doFinal(tempBlob);
        globalEncryptionOutput = globalEncryptionOutput.concat(Array.from(tempCipherOutput.data));
      }
      let base64 = Base64.getInstance()
      let enStr = base64.encode(globalEncryptionOutput)
      LogUtils.i("加密总长度:" + globalEncryptionOutput.length + "n生成加密串:n" + enStr)
      return enStr
    })
    .catch(error = > {
      LogUtils.i(`加密异常, ${error.code}, ${error.message}`);
    })
}复制

解密:

/**
 * 测试RSA解密
 */
export function textRsaDecryption(value: string) {
  let keyGenName = "RSA1024";
  let cipherAlgName = "RSA1024|PKCS1";
  // RSA密钥每次加密生成的密文数据长度计算方式:密钥位数/8
  let cipherTextSplitLen = 128;
  let globalKeyPair; //密钥对
  //创建非对称密钥生成器对象
  let asyKeyGenerator = cryptoFramework.createAsyKeyGenerator(keyGenName);
  // 创建解密Decoder对象
  let cipherDecryption = cryptoFramework.createCipher(cipherAlgName);

  return new Promise((resolve, reject) = > {
    setTimeout(() = > {
      resolve("textRsaEncryption");
    }, 10);
  })
    .then(() = > {
      let base64 = Base64.getInstance()
      let pubKeyBlob = { data: new Uint8Array(base64.decode(publicKey)) }
      let priKeyBlob = { data: new Uint8Array(base64.decode(privateKey)) }
      return asyKeyGenerator.convertKey(pubKeyBlob, priKeyBlob);
    })
    .then(keyPair = > {
      globalKeyPair = keyPair; // 保存到密钥对全局变量
      return cipherDecryption.init(cryptoFramework.CryptoMode.DECRYPT_MODE, globalKeyPair.priKey, null);
    }).then(async () = > {
      let base64 = Base64.getInstance()
      let globalCipherOutput1 = new Uint8Array(base64.decode(value))
      let len = globalCipherOutput1.length
      //解密输出
      let globalDecryptionOutput = new Uint8Array(len);
      let globalOffset = 0
      // 将密文按128B进行拆分解密,得到原文后进行拼接
      for (let i = 0; i < (len / cipherTextSplitLen); i++) {
        let tempBlobData = globalCipherOutput1.subarray(i * cipherTextSplitLen, (i + 1) * cipherTextSplitLen);
        let message = new Uint8Array(tempBlobData);
        let tempBlob = { data: message };
        let tempDecodeOutput = await cipherDecryption.doFinal(tempBlob);
        //存入数组 解决边累加边转中文时 字节错乱出现乱码
        globalDecryptionOutput.set(tempDecodeOutput.data, globalOffset)
        //偏移量
        globalOffset += tempDecodeOutput.data.byteLength
      }
      let result = StringUtils.uint8Array2String(globalDecryptionOutput)
      LogUtils.i("解密串:cipherAlgName[" + cipherAlgName + "]n" + result);
    })
    .catch(error = > {
      LogUtils.i(`解密异常,cipherAlgName[${cipherAlgName}] ${error.code}, ${error.message}`);
    })
}复制

运行代码:

Text("RSA加解密联测")
          .TextNormalStyle()
          .fontSize(16)
          .fontWeight(FontWeight.Normal)
          .fontColor(Color.White)
          .textAlign(TextAlign.Center)
          .margin({ left: 5 })
          .layoutWeight(1)
          .onClick(() =  > {
            let globalPlainText = ""
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "一二三四五六七八九十"
            globalPlainText += "123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/123456789/"
            globalPlainText += "SDK向DevEco Studio提供全量API,DevEco Studio识别开发者项目中选择的设备形态,找到该设备的支持能力集,筛选支持能力集包含的API并提供API联想"
            //
            textRsaEncryption(globalPlainText)
              .then(enStr =  > {
                if (enStr) textRsaDecryption(enStr)
              })
          })
      }
      .width('100%')
      .height(50)
      .margin({ top: 10 })
      .padding(5)复制

运行结果:

鸿蒙OS

终于大功告成!!

审核编辑 黄宇

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分