HarmonyOS-AES加解密

前言

客户端开发中存在一些需要在传输过程中进行保护的重要信息,比如用户通讯录信息,用户日志等信息。这种情况下就需要采用适当的加密与解密方式。

作者:张保罗
链接:https://juejin.cn/post/7340152660224425996

常规的加密方式有AES,RSA 等。本篇中介绍对称加密方式AES,这种对称式加密方式中加密与解密使用相同密钥。

鸿蒙加解密算法框架详细介绍了完整的使用方法供参考

https://developer.harmonyos.com/cn/docs/documentation/doc-references-V3/js-apis-cryptoframework-0000001477981409-V3

鸿蒙官方加解密框架开发指导

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/cryptoframework-guidelines-0000001544703861-V2

效果展示

f5b058bf80860cb73ca07c27c2d00074.png

原理

  • AES加密
    AES的全称是Advanced Encryption Standard,是最常见的对称加密。AES为分组密码,分组密码也就是把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文。在AES标准规范中,分组长度只能是128位,也就是说,每个分组为16个字节(每个字节8位)。密钥的长度可以使用128位、192位或256位。

  • 对称AES加解密
    算法库目前提供了AES加解密常用的7种加密模式:ECB、CBC、OFB、CFB、CTR、GCM和CCM。AES为分组加密算法,分组长度大小为128位。实际应用中明文最后一组可能不足128位,不足数据可以使用各种padding模式做数据填充。下文中描述了各个padding的区别:

  1. NoPadding:不带填充;

  2. PKCS5:填充字符由一个字节序列组成,每个字节填充该填充字节序列的长度,规定是8字节填充;

  3. PKCS7:填充字符和PKCS5填充方法一致,但是可以在1-255字节之间任意填充;

相关概念

  1. 明文P(plainText):未经加密的数据

  2. 密钥K(key):用来加密明文的密码。在对称加密算法中,加密与解密的密钥是相同的,由双方协商产生,绝不可以泄漏

  3. 密文C(cipherText): 经过加密的数据

  4. 加密函数E(encrypt):C = E(K, P),即将明文和密钥作为参数,传入加密函数密文就可以获得密文

  5. 解密函数D(decrypt):P = D(K, C),即将密文和密钥作为参数,传入解密函数中,就可以获得明文

  6. 初始向量(IV,Initialization Vector):它的作用和MD5的“加盐”有些类似,目的是防止同样的明文块,始终加密成同样的密文块:

实现

  • 本例中实现了AES对用户输入的明文内容进行AES加密并显示

  • 对加密的内容进行解密并显示

  • 密钥和初始向量iv写死了,实际项目中可以根据自己的需要来实现密钥和iv的生成。比如用md5来生成

注意加密过程

由于aes加密后的字节数组,直接转String返回参数有可能存在乱码,所以对返回值做一下处理,将加密的结果转换为base64的字符串。同理,解密时候,需要把字符串先base64处理,再把解密后的内容进行aes解密操作。

加密实现
加密(从前往后):明文 -> 加密 -> base64处理 -> 密文


解密实现
解密(从后往前):明文 <- 解密 <- base64处理 <- 密文

代码

加密和解密方法

import util from '@ohos.util';
import cryptoFramework from '@ohos.security.cryptoFramework';
import Logger from './Logger';




const TAG: string = '[CipherModel]'
const AES128: string = 'AES128';
const AES128_CBC_PKCS5: string = 'AES128|CBC|PKCS5';
const AES128_PKCS7: string = 'AES128|PKCS7';


export class CipherModel {
  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;
  }


  uint8ArrayToString(array: Uint8Array) {
    let arrayString = '';
    for (let i = 0; i < array.length; i++) {
      arrayString += String.fromCharCode(array[i]);
    }
    return arrayString;
  }


  aesEncrypt(message: string, key: string, iv: string, callback) {
    let that = new util.Base64Helper();


    let paramsSpec: cryptoFramework.IvParamsSpec = { iv: { data: this.stringToUint8Array(iv) }, algName: "IvParamsSpec" }
    let aesGenerator = cryptoFramework.createSymKeyGenerator(AES128);
    let cipher = cryptoFramework.createCipher(AES128_CBC_PKCS5);
    let pubKey = that.decodeSync(key);
    let pubKeyBlob: cryptoFramework.DataBlob = { data: pubKey };
    aesGenerator.convertKey(pubKeyBlob, (err, symKey) => {
      if (err) {
        console.error("convertKey: error.");
        return;
      }
      cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, paramsSpec, (err, data) => {
        let input: cryptoFramework.DataBlob = { data: this.stringToUint8Array(message) };
        cipher.doFinal(input, (err, data) => {
          Logger.info(TAG, "EncryptOutPut is " + data.data);
          let result = that.encodeToStringSync(data.data)
          Logger.info(TAG, "result is " + result);
          callback(result)
        })
      })
    })
  }


  aesDecrypt(message: string, key: string, iv: string, callback) {
    let paramsSpec: cryptoFramework.IvParamsSpec = { iv: { data: this.stringToUint8Array(iv) }, algName: "IvParamsSpec" }


    let aesGenerator = cryptoFramework.createSymKeyGenerator(AES128);
    let cipher = cryptoFramework.createCipher(AES128_CBC_PKCS5);
    let that = new util.Base64Helper();
    let pubKey = that.decodeSync(key);
    let pubKeyBlob: cryptoFramework.DataBlob = { data: pubKey };
    aesGenerator.convertKey(pubKeyBlob, (err, symKey) => {
      if (err) {
        console.error("convertKey: error.");
        return;
      }
      cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, paramsSpec, (err, data) => {
        let newMessage = that.decodeSync(message);
        let input: cryptoFramework.DataBlob = { data: newMessage };
        cipher.doFinal(input, (err, data) => {
          Logger.info(TAG, "DecryptOutPut is " + data.data);
          let result = this.uint8ArrayToString(data.data)
          Logger.info(TAG, "result is " + result);
          callback(result)
        })
      })
    })
  }
}

点击加密按钮

Row() {
  Button('aes加密').align(Alignment.Start)
}.width('100%').margin({ left: 12, top: 12 })
.onClick( () => {
  this.cipherModel.aesEncrypt(
    this.originText,
    this.AES_ENCRYPT_KEY,
    this.AES_IV_STRING,
    (result: string) => {
      Logger.info(this.TAG, `this result = ${JSON.stringify(result)}`);
      this.cipherText = result;
    })
}
)

// 点击解密按钮

Row() {
  Button('aes解密').align(Alignment.Start)
}.width('100%').margin({ left: 12, top: 12 })
.onClick(() => {
  if(this.cipherText.toString().length === 0) {
    return;
  }
  this.cipherModel.aesDecrypt(this.cipherText,
    this.AES_ENCRYPT_KEY,
    this.AES_IV_STRING,
    (result: string) => {
    Logger.info(this.TAG, `this result = ${JSON.stringify(result)}`);
    this.decodedText = result;
  })
})

总结

本文中仅涉及了AES加解密的简单使用,并未根据项目实际需要来调整加密格式参数。如果项目中需要加密的信息数量较多或者需要较强的加密强度。请到官网查看最新版的相关文档,选择最合适的加密方法。

demo代码已上传github https://github.com/kainbro/LearnHamony

由于我还没找到鸿蒙工作,所以还没有拿到鸿蒙最新的sdk。此处使用的是官网的公开版本sdk 9。有些朋友项目中已经拿到华为内部鸿蒙版本,api可能略有不同,请根据最新sdk自行调整变更的api。

关注我获取更多知识或者投稿

377c2cc0a51c80ab5d716a3187553914.jpeg

16daf585671aaef85e9226a58f4f2e54.jpeg

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值