目录
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,电码本)
2、CBC模式 (Cipher Block Chaining 密文分组链接模式)
四、初始向量
在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;
}
}
行者常至,为者常成!