• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { cryptoFramework } from "@kit.CryptoArchitectureKit";
17import Logger from "./Logger";
18import { arrayBufferToString, fromHexString, stringToUint8Array, TAG, uint8ArrayToShowStr } from "./Utils";
19
20// 加密数据结构
21class EncryptionData {
22  aesGcmTag: string = "";
23  encryptedText: string = "";
24}
25
26/**
27 * 生成AES密钥
28 * @returns AES密钥的16进制字符串
29 */
30export async function generateAesKey(): Promise<string> {
31  try {
32    // 创建对称密钥生成器
33    let symKeyGenerator: cryptoFramework.SymKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256');
34    // 通过密钥生成器随机生成对称密钥
35    let symKey = await symKeyGenerator.generateSymKey();
36    // 获取对称密钥的二进制数据,输出长度为256bit的字节流
37    let encodedKey: cryptoFramework.DataBlob = symKey.getEncoded();
38    let data: Uint8Array = encodedKey.data;
39    // 将二进制数据转为16进制string。
40    return uint8ArrayToShowStr(data);
41  } catch (error) {
42    Logger.error(TAG, 'AES create failed');
43    return "";
44  }
45}
46
47/**
48 * AES解密
49 * @param encryptedMessage 已经加密的数据
50 * @param aesKey AES密钥
51 * @returns 解密后的数据
52 */
53export async function aesGcmDecrypt(encryptedMessage: string, aesKey: string): Promise<string> {
54  let encryptionData: EncryptionData = JSON.parse(encryptedMessage);
55  try {
56    // 创建对称密钥生成器实例
57    let symKeyGenerator: cryptoFramework.SymKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256');
58    // 将AES密钥字符串转换为密钥类型
59    let symKeyBlob: cryptoFramework.DataBlob = { data: fromHexString(aesKey) };
60    let key: cryptoFramework.SymKey = await symKeyGenerator.convertKey(symKeyBlob);
61    // 指定算法名称(含密钥长度)、加密模式以及填充方法的组合
62    let cipherAlgName: string = 'AES256|GCM|PKCS7';
63    let cipher: cryptoFramework.Cipher = cryptoFramework.createCipher(cipherAlgName);
64    // 适用于GCM模式的加密参数
65    let globalGcmParams: cryptoFramework.GcmParamsSpec = genGcmParamsSpec(encryptionData.aesGcmTag);
66    // 	表示进行加密操作
67    let mode: cryptoFramework.CryptoMode = cryptoFramework.CryptoMode.DECRYPT_MODE;
68    // Cipher中init、update、doFinal为三段式接口,需要成组使用。其中init和doFinal必选,update可选。
69    // 初始化加解密的cipher对象
70    await cipher.init(mode, key, globalGcmParams);
71    // 将明文转换为Uint8Array,用于后续加密操作
72    let plainText: cryptoFramework.DataBlob = { data: fromHexString(encryptionData.encryptedText) };
73    // 分段更新加密或者解密数据操作,可选方法
74    let cipherTextBlob: cryptoFramework.DataBlob = await cipher.update(plainText);
75    await cipher.doFinal(null);
76    let tmpArr: Uint8Array = cipherTextBlob.data;
77    // 将加密后的密文转换为字符串
78    let decryptedText: string = arrayBufferToString(tmpArr);
79    return decryptedText;
80  } catch (error) {
81    Logger.error(TAG, `AES decrypt failed, ${error.code}, ${error.message}`);
82    return "";
83  }
84}
85
86/**
87 * AES加密
88 * @param textString 需要加密的数据
89 * @param aesKey AES密钥
90 * @returns
91 */
92export async function aesGcmEncrypt(textString: string, aesKey: string): Promise<string> {
93  try {
94    // 创建对称密钥生成器实例
95    let symKeyGenerator: cryptoFramework.SymKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256');
96    // 将AES密钥字符串转换为密钥类型
97    let symKeyBlob: cryptoFramework.DataBlob = { data: fromHexString(aesKey) };
98    let key: cryptoFramework.SymKey = await symKeyGenerator.convertKey(symKeyBlob);
99    // 指定算法名称(含密钥长度)、加密模式以及填充方法的组合
100    let cipherAlgName: string = 'AES256|GCM|PKCS7';
101    let cipher: cryptoFramework.Cipher = cryptoFramework.createCipher(cipherAlgName);
102    // 适用于GCM模式的加密参数
103    let globalGcmParams: cryptoFramework.GcmParamsSpec = genGcmParamsSpec();
104    // 	表示进行加密操作
105    let mode: cryptoFramework.CryptoMode = cryptoFramework.CryptoMode.ENCRYPT_MODE;
106    // Cipher中init、update、doFinal为三段式接口,需要成组使用。其中init和doFinal必选,update可选。
107    // 初始化加解密的cipher对象
108    await cipher.init(mode, key, globalGcmParams);
109    // 将明文转换为Uint8Array,用于后续加密操作
110    let plainText: cryptoFramework.DataBlob = { data: stringToUint8Array(textString) };
111    // 分段更新加密或者解密数据操作,可选方法
112    let cipherTextBlob: cryptoFramework.DataBlob = await cipher.update(plainText);
113    let tmpArr: Uint8Array = cipherTextBlob.data;
114    // 将加密后的密文转换为16进制字符串
115    let encryptedText: string = uint8ArrayToShowStr(tmpArr);
116    // 用于处理剩余数据和本次传入的数据,并最终结束加密或解密操作。
117    // 对于GCM模式的对称加密:一次加密流程中,如果将每一次update和doFinal的结果拼接起来,会得到“密文+authTag”,即末尾的16字节(GCM模式)或12字节(CCM模式)是authTag,
118    // 而其余部分均为密文。(也就是说,如果doFinal的data参数传入null,则doFinal的结果就是authTag)
119    // authTag需要填入解密时的GcmParamsSpec;密文则作为解密时的入参data。
120    let authTag: cryptoFramework.DataBlob = await cipher.doFinal(null);
121    let tmoTagArr: Uint8Array = authTag.data;
122    let aesGcmTag: string = uint8ArrayToShowStr(tmoTagArr);
123    // 将AES的加密结果转换为JSON对象
124    let aesEncryptResult: EncryptionData = { aesGcmTag: aesGcmTag, encryptedText: encryptedText };
125    return JSON.stringify(aesEncryptResult);
126  } catch (error) {
127    Logger.error(TAG, `AES encrypt failed, ${error.code}, ${error.message}`);
128    return "";
129  }
130}
131
132/**
133 * AES加密参数
134 * @param authTag 加解密参数,加密数据时不需要传参,会在调用cipher的doFinal方法时生成,解密时需要传入
135 * @returns
136 */
137export function genGcmParamsSpec(authTag?: string): cryptoFramework.GcmParamsSpec {
138  let arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // 12 bytes
139  let dataIv = new Uint8Array(arr);
140  let ivBlob: cryptoFramework.DataBlob = { data: dataIv };
141
142  arr = [0, 0, 0, 0, 0, 0, 0, 0]; // 8 bytes
143  let dataAad = new Uint8Array(arr);
144  let aadBlob: cryptoFramework.DataBlob = { data: dataAad };
145
146  arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // 16 bytes
147  let dataTag = new Uint8Array(arr);
148  // GCM的authTag在加密时从doFinal结果中获取,在解密时填入init函数的params参数中
149  let tagBlob: cryptoFramework.DataBlob = { data: authTag ? fromHexString(authTag) : dataTag };
150
151  let gcmParamsSpec: cryptoFramework.GcmParamsSpec = {
152    iv: ivBlob,
153    aad: aadBlob,
154    authTag: tagBlob,
155    algName: 'GcmParamsSpec'
156  };
157  return gcmParamsSpec;
158}