HarmonyOS Next 开发AES加密解密和中文乱码处理 原创 精华

wangKirk
发布于 2025-8-1 15:54
浏览
0收藏

什么是 AES 对称加密

在密码学中,对称加密分为流加密(如 OFB、CFB 模式)和块加密(如 ECB、CBC 模式)。流加密需要将分组密码转化为流模式工作,而块加密(也称分组加密)则在处理超过一个块大小的数据时,需要借助填充链式加密模式来实现完整加密。

ECB 模式(Electronic Code Book,电子密码本)

ECB 是最早、最简单的加密模式,它将原始数据分组,每组大小与密钥长度一致,然后每组使用相同的密钥独立加密。由于其无关联性,它的安全性较低,但实现简单,常用于教学或数据结构无关紧要的场景。


HarmonyOS NEXT 中使用 AES 加密

官方示例:使用 GCM 模式自动生成密钥(Promise 写法)

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}`);
  });
}

AES ECB 模式加解密实现(固定密钥)

加密方法:

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 编码。


正确做法:使用 TextEncoderTextDecoder

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加密原文

中文正常解密,问题完美解决!


总结

  • 默认示例仅适用于 纯英文 场景
  • 处理 多字节字符(中文、emoji 等) 时,务必使用 TextEncoder/TextDecoder 并指定 UTF-8

本文介绍了在 HarmonyOS NEXT 中如何使用 AES 实现对称加密,特别是 ECB 模式下处理中文加解密可能出现乱码的原因,并提供了使用 TextEncoder/TextDecoder 的最佳实践方案。希望这篇文章能为你在开发过程中带来帮助,也欢迎订阅我的专栏。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
已于2025-8-1 16:05:29修改
收藏
回复
举报
回复
    相关推荐