
回复
在密码学中,对称加密分为流加密(如 OFB、CFB 模式)和块加密(如 ECB、CBC 模式)。流加密需要将分组密码转化为流模式工作,而块加密(也称分组加密)则在处理超过一个块大小的数据时,需要借助填充和链式加密模式来实现完整加密。
ECB 是最早、最简单的加密模式,它将原始数据分组,每组大小与密钥长度一致,然后每组使用相同的密钥独立加密。由于其无关联性,它的安全性较低,但实现简单,常用于教学或数据结构无关紧要的场景。
function testAesGcm() {
return new Promise((resolve) => {
setTimeout(() => resolve('testAesGcm'), 10);
}).then(() => {
let symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES128');
if (!symKeyGenerator) {
console.error('createSymKeyGenerator failed');
return;
}
let promiseSymKey = symKeyGenerator.generateSymKey();
globalGcmParams = genGcmParamsSpec();
let cipher = cryptoFramework.createCipher('AES128|GCM|PKCS7');
globalCipher = cipher;
return promiseSymKey;
}).then((key) => {
globalKey = key;
return globalCipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, key, globalGcmParams);
}).then(() => {
let plainText = { data: stringToUint8Array('this is test!') };
return globalCipher.update(plainText);
}).then((updateOutput) => {
globalCipherText = updateOutput;
return globalCipher.doFinal(null);
}).then((authTag) => {
globalGcmParams.authTag = authTag;
return globalCipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, globalKey, globalGcmParams);
}).then(() => {
return globalCipher.update(globalCipherText);
}).then((updateOutput) => {
console.info('解密结果: ' + uint8ArrayToString(updateOutput.data));
return globalCipher.doFinal(null);
}).catch((error) => {
console.error(`加解密过程出错: ${error.code}, ${error.message}`);
});
}
function aesECBEncrypt(plaintext) {
const key = '12345678901234==';
const ivKey = '12345678901234==';
const cipherAlgName = 'AES128|ECB|PKCS7';
const symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES128');
const ivParam = {
algName: 'IvParamsSpec',
iv: {
data: stringToUint8Array(ivKey, 16)
}
};
return symKeyGenerator.convertKey({
data: stringToUint8Array(key)
}).then((symKey) => {
const cipher = cryptoFramework.createCipher(cipherAlgName);
return cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, ivParam).then(() => {
return cipher.doFinal({
data: stringToUint8Array(plaintext)
});
}).then((output) => {
const base64 = new util.Base64Helper();
return base64.encodeToStringSync(output.data);
});
});
}
function aesECBDecrypt(encryptText) {
const key = '12345678901234==';
const ivKey = '12345678901234==';
const cipherAlgName = 'AES128|ECB|PKCS7';
const symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES128');
const ivParam = {
algName: 'IvParamsSpec',
iv: {
data: stringToUint8Array(ivKey, 16)
}
};
return symKeyGenerator.convertKey({
data: stringToUint8Array(key)
}).then((symKey) => {
const cipher = cryptoFramework.createCipher(cipherAlgName);
return cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, ivParam).then(() => {
const base64 = new util.Base64Helper();
const decoded = base64.decodeSync(encryptText);
return cipher.doFinal({ data: decoded });
}).then((output) => {
return uint8ArrayToString(output.data);
});
});
}
aboutToAppear() {
let globalPlainText = "This is a long plainTest! AES加密原文";
console.log('原文:' + globalPlainText);
aesECBEncrypt(globalPlainText).then(res => {
console.log('加密结果:' + res);
return aesECBDecrypt(res);
}).then(decrypted => {
console.log('解密结果:' + decrypted);
}).catch(err => {
console.log('错误:' + err);
});
}
当原文中包含中文时,使用 String.fromCharCode
转换字节流会出现乱码问题。原因是:中文字符在 UTF-8 中占用 3 个字节,但原始函数没有处理编码问题。
官方提供的方法:
function uint8ArrayToString(array) {
let arrayString = '';
for (let i = 0; i < array.length; i++) {
arrayString += String.fromCharCode(array[i]);
}
return arrayString;
}
该方式在处理中文时无法正确解码,因为未处理 UTF-8 编码。
TextEncoder
和 TextDecoder
function stringToUint8Array(str) {
const encoder = new util.TextEncoder();
return encoder.encodeInto(str);
}
function uint8ArrayToString(array) {
const decoder = util.TextDecoder.create("utf-8", { ignoreBOM: true });
return decoder.decodeWithStream(new Uint8Array(array), { stream: false });
}
测试结果:
原文:This is a long plainTest! AES加密原文
加密后:zbusam9rOBPmJ072ENhEO5JErEY5X7HP2L/WPwARmlMV0PoGgXX+6ZhohYdJLhKt
解密后:This is a long plainTest! AES加密原文
中文正常解密,问题完美解决!
本文介绍了在 HarmonyOS NEXT 中如何使用 AES 实现对称加密,特别是 ECB 模式下处理中文加解密可能出现乱码的原因,并提供了使用 TextEncoder/TextDecoder 的最佳实践方案。希望这篇文章能为你在开发过程中带来帮助,也欢迎订阅我的专栏。