JHHK

欢迎来到我的个人网站
行者常至 为者常成

AES实现

目录

AES介绍

一、介绍

AES是块加密,秘钥长度可变,有128/192/256三种长度,有ECB和CBC两种工作模式。

需要注意的是:AES的块大小始终是128位(16字节),这是AES标准的一部分。虽然AES支持不同长度的密钥(128位、192位和256位),但块大小始终是128位。

二、填充模式

1、PKCS7Padding

AES是块加密,当最后一组无法对齐时就需要进行填充,以块128位(16字节)的块大小加密为例。
假如最后一个数据块为abcd,只有四个字节,需要填充16-4=12字节,用0x10(十六进制)表示。
填充内容为:0x0C 0x0C 0x0C 0x0C 0x0C 0x0C 0x0C 0x0C 0x0C 0x0C 0x0C 0x0C
假如最后一组已经对齐:abcdabcdabcdabcd,则填充一块长度为块大小的数据
填充内容为:0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10

2、PKCS5Padding

与PKCS7Padding相比,PKCS5Padding只支持64位(8字节)的块大小的填充。
假如最后一组为abcde,填充后为:abcde333
假如最后组已经对齐abcdabcd,那么填充应该为:abcdabcd88888888

三、两种工作模式介绍

1、ECB模式(Electronic Codebook,电码本)

img

2、CBC模式 (Cipher Block Chaining 密文分组链接模式)

img

四、初始向量

在AES加密中,无论使用何种模式(如CBC),初始向量(IV)的长度始终为128位,即16字节。这是因为AES的块大小固定为128位。

代码实现

两个关键的类型:

// 存放Uint8的数组,也就是字节流
let keyArray: Uint8Array = base64Helper.decodeSync(key);


// cryptoFramework.DataBlob对字节流Uint8Array包装了一层,在鸿蒙中这个类型很常用,很多接口的参数需要传入这个类型。
let symKeyBlob: cryptoFramework.DataBlob = { data: keyArray };

具体实现如下:

import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { buffer, util } from '@kit.ArkTS';
import { NetEnvManager } from 'net';


export default class AesUtil {

  // 对秘钥进行处理,处理成鸿蒙对应的类型: cryptoFramework.SymKey。
  static genSymKey(): cryptoFramework.SymKey  {
    let base64Helper = new util.Base64Helper()
    let env = NetEnvManager.getInstance().getEnv();
    let key:string=""
    if(env=== NetEnvManager.ENV_PROD){ //正式环境
      key="xxxxxxxxxxxxxxxxxxx(长度是44字节的base64字符串,base64解码后长度是32字节,即256位的秘钥)"
    }else{
      key="xxxxxxxxxxxxxxxxxxx(长度是44字节的base64字符串,base64解码后长度是32字节,即256位的秘钥)"
    }

    // 存放Uint8的数组,也就是字节流
    let keyArray: Uint8Array = base64Helper.decodeSync(key);

    // cryptoFramework.DataBlob对字节流Uint8Array包装了一层,在鸿蒙中这个类型很常用,很多接口的参数需要传入这个类型。
    let symKeyBlob: cryptoFramework.DataBlob = { data: keyArray };
    let aesGenerator = cryptoFramework.createSymKeyGenerator('AES256');
    let symKey = aesGenerator.convertKeySync(symKeyBlob);
    return symKey;
  }


  // 对iv进行处理,处理成鸿蒙对应的类型: cryptoFramework.IvParamsSpec。
  static genIvParamsSpec(): cryptoFramework.IvParamsSpec {
    let env = NetEnvManager.getInstance().getEnv();
    let iv:string=""
    if(env=== NetEnvManager.ENV_PROD){ //正式环境
      iv="xxxxxxxxxxxxxxxx(长度是16字节即128位的初始向量)"
    }else{
      iv="xxxxxxxxxxxxxxxx(长度是16字节即128位的初始向量)"
    }
    let ivBlob: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(iv, 'utf-8').buffer) };
    let ivParamsSpec: cryptoFramework.IvParamsSpec = {
      algName: "IvParamsSpec",
      iv: ivBlob
    };
    return ivParamsSpec;
  }


  // 对明文进行处理,处理成鸿蒙对应的字节流类型: cryptoFramework.DataBlob。
  static genPlainText(plainText: string): cryptoFramework.DataBlob{
    let plainData: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(plainText, 'utf-8').buffer) };
    return plainData;
  }


  // 对密文进行处理,处理成鸿蒙对应的字节流类型: cryptoFramework.DataBlob。
  // 密文是hexstring所以两个长度是一字节,需要进行处理
  static hexStringToByte(cipherText: string): cryptoFramework.DataBlob{
    const len = cipherText.length;
    const cipherArray = new Uint8Array(len / 2);
    for (let i = 0; i < len; i += 2) {
      const byteString = cipherText.substring(i, i+2);
      cipherArray[i / 2] = parseInt(byteString, 16);
    }
    let cipherData: cryptoFramework.DataBlob = { data: cipherArray };
    return cipherData;
  }



static byteToHexString(byteArray: Uint8Array): string {
    let str: string = ""
    for (let i = 0; i < byteArray.length; i++) {
      let tmp: string = ""
      let num: number = byteArray[i]
      tmp = num.toString(16)
      if (tmp.length == 1) {
        tmp = "0" + tmp
      }
      str += tmp
    }
    return str
}



  // 加密消息
  static encryptMessage(plainText: string): string {

    // 处理对称密钥
    let symKey = AesUtil.genSymKey();

    // 处理iv
    let ivParamsSpec = AesUtil.genIvParamsSpec();

    // 处理明文数据
    let plainData: cryptoFramework.DataBlob = AesUtil.genPlainText(plainText);

    let cipher = cryptoFramework.createCipher('AES256|CBC|PKCS7');
    cipher.initSync(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, ivParamsSpec);
    let cipherData = cipher.doFinalSync(plainData);
    // 没有用到byteToHexString这个方法,直接使用系统提供的方法转为hex
    let cipherText = buffer.from(cipherData.data).toString('hex')
    return cipherText;
  }


  // 解密消息
  static decryptMessage(cipherText:string): string {
    // 处理对称密钥
    let symKey = AesUtil.genSymKey();

    // 处理iv
    let ivParamsSpec = AesUtil.genIvParamsSpec();

    // 密文数据
    let cipherData = AesUtil.hexStringToByte(cipherText);

    let decoder = cryptoFramework.createCipher('AES256|CBC|PKCS7');
    decoder.initSync(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, ivParamsSpec);
    let plainData = decoder.doFinalSync(cipherData);
    let plainText = buffer.from(plainData.data).toString('utf-8')
    return plainText;
  }
}

行者常至,为者常成!





R
Valine - A simple comment system based on Leancloud.