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}