当前位置:   article > 正文

鸿蒙开发AES加密解密和中文乱码处理_鸿蒙 sha256 unkonwn algname

鸿蒙 sha256 unkonwn algname

目录

什么是AES对称加密

官方文档

鸿蒙开发中如何使用AES加密

AES加密:

AES解密:

使用加密观察结果

解密过程出现中文乱码如何处理

思考:会不会在字符串转字节流的时候出现了问题

完美解决中文加密解密乱码问题


什么是AES对称加密

        对称/分组密码一般分为流加密(如OFB、CFB等)和块加密(如ECB、CBC等)。对于流加密,需要将分组密码转化为流模式工作。对于块加密(或称分组加密),如果要加密超过块大小的数据,就需要涉及填充和链加密模式。

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

ECB模式是最早采用和最简单的模式,它将加密的数据分成若干组,每组的大小跟加密密钥长度相同,然后每组都用相同的密钥进行加密

官方文档

加解密算法库框架开发指导

鸿蒙开发中如何使用AES加密

官方文档中使用方法:

  1. // AES GCM模式示例,自动生成密钥(promise写法)
  2. function testAesGcm() {
  3. return new Promise((resolve, reject) => {
  4. setTimeout(() => {
  5. resolve('testAesGcm');
  6. }, 10)
  7. }).then(() => {
  8. // 生成对称密钥生成器
  9. let symAlgName = 'AES128';
  10. let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgName);
  11. if (symKeyGenerator == null) {
  12. console.error('createSymKeyGenerator failed');
  13. return;
  14. }
  15. console.info(`symKeyGenerator algName: ${symKeyGenerator.algName}`);
  16. // 通过密钥生成器随机生成128位长度的对称密钥
  17. let promiseSymKey = symKeyGenerator.generateSymKey();
  18. // 构造参数
  19. globalGcmParams = genGcmParamsSpec();
  20. // 生成加解密生成器
  21. let cipherAlgName = 'AES128|GCM|PKCS7';
  22. try {
  23. globalCipher = cryptoFramework.createCipher(cipherAlgName);
  24. console.info(`cipher algName: ${globalCipher.algName}`);
  25. } catch (error) {
  26. console.error(`createCipher failed, ${error.code}, ${error.message}`);
  27. return;
  28. }
  29. return promiseSymKey;
  30. }).then(key => {
  31. let encodedKey = key.getEncoded();
  32. console.info('key hex:' + uint8ArrayToShowStr(encodedKey.data));
  33. globalKey = key;
  34. return key;
  35. }).then(key => {
  36. // 初始化加解密操作环境:开始加密
  37. let mode = cryptoFramework.CryptoMode.ENCRYPT_MODE;
  38. let promiseInit = globalCipher.init(mode, key, globalGcmParams); // init
  39. return promiseInit;
  40. }).then(() => {
  41. let plainText = {data : stringToUint8Array('this is test!')};
  42. let promiseUpdate = globalCipher.update(plainText); // update
  43. return promiseUpdate;
  44. }).then(updateOutput => {
  45. globalCipherText = updateOutput;
  46. let promiseFinal = globalCipher.doFinal(null); // doFinal
  47. return promiseFinal;
  48. }).then(authTag => {
  49. // GCM模式需要从doFinal的输出中取出加密后的认证信息并填入globalGcmParams,在解密时传入init()
  50. globalGcmParams.authTag = authTag;
  51. return;
  52. }).then(() => {
  53. // 初始化加解密操作环境:开始解密
  54. let mode = cryptoFramework.CryptoMode.DECRYPT_MODE;
  55. let promiseInit = globalCipher.init(mode, globalKey, globalGcmParams); // init
  56. return promiseInit;
  57. }).then(() => {
  58. let promiseUpdate = globalCipher.update(globalCipherText); // update
  59. return promiseUpdate;
  60. }).then(updateOutput => {
  61. console.info('decrypt plainText: ' + uint8ArrayToString(updateOutput.data));
  62. let promiseFinal = globalCipher.doFinal(null); // doFinal
  63. return promiseFinal;
  64. }).then(finalOutput => {
  65. if (finalOutput == null) { // 使用finalOutput.data前,先判断结果是否为null
  66. console.info('GCM finalOutput is null');
  67. }
  68. }).catch(error => {
  69. console.error(`catch error, ${error.code}, ${error.message}`);
  70. })
  71. }

AES加密:

  1. //AES加密
  2. function aesECBEncrypt(plaintext) {
  3. let key = '12345678901234==';
  4. let ivKey = '12345678901234==';
  5. let cipherAlgName = 'AES128|ECB|PKCS7';
  6. let symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES128')
  7. let ivParam: cryptoFramework.IvParamsSpec = {
  8. algName: 'IvParamsSpec',
  9. iv: {
  10. data: stringToUint8Array(ivKey, 16)
  11. }
  12. }
  13. var cipher;
  14. // 生成密钥
  15. return symKeyGenerator.convertKey({
  16. data: stringToUint8Array(key)
  17. }).then(symKey => {
  18. // 创建加密器
  19. try {
  20. cipher = cryptoFramework.createCipher(cipherAlgName);
  21. console.info(`xx cipher algName: ${cipher.algName}`);
  22. } catch (error) {
  23. console.error(`xx createCipher failed, ${error.code}, ${error.message}`);
  24. return null
  25. }
  26. // 初始化加密器
  27. return cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, ivParam)
  28. .then(() => {
  29. // 开始加密
  30. return cipher.doFinal({
  31. data: stringToUint8Array(plaintext)
  32. })
  33. })
  34. .then(output => {
  35. let base64 = new util.Base64Helper();
  36. let result = base64.encodeToStringSync(output.data);
  37. return new Promise((resolve) => {
  38. resolve(result)
  39. })
  40. }).catch(err => {
  41. return new Promise((_, reject) => {
  42. reject(err)
  43. })
  44. })
  45. }).catch(err => {
  46. return new Promise((_, reject) => {
  47. reject(err)
  48. })
  49. })
  50. }

AES解密:

  1. //AES解密
  2. function aesECBDecrypt(encrypttext) {
  3. let key = '12345678901234==';
  4. let ivKey = '12345678901234==';
  5. let cipherAlgName = 'AES128|ECB|PKCS7';
  6. let symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES128')
  7. let ivParam: cryptoFramework.IvParamsSpec = {
  8. algName: 'IvParamsSpec',
  9. iv: {
  10. data: stringToUint8Array(ivKey, 16)
  11. }
  12. }
  13. var cipher;
  14. return symKeyGenerator.convertKey({
  15. data: stringToUint8Array(key)
  16. }).then(symKey => {
  17. try {
  18. cipher = cryptoFramework.createCipher(cipherAlgName);
  19. console.info(`xx cipher algName: ${cipher.algName}`);
  20. } catch (error) {
  21. console.error(`xx createCipher failed, ${error.code}, ${error.message}`);
  22. return null
  23. }
  24. return cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, ivParam)
  25. .then(() => {
  26. let base64 = new util.Base64Helper();
  27. let result = base64.decodeSync(encrypttext);
  28. return cipher.doFinal({
  29. data: result
  30. })
  31. })
  32. .then(output => {
  33. let result = uint8ArrayToString(output.data)
  34. return new Promise((resolve) => {
  35. resolve(result)
  36. })
  37. }).catch(err => {
  38. return new Promise((_, reject) => {
  39. reject(err)
  40. })
  41. })
  42. }).catch(err => {
  43. return new Promise((_, reject) => {
  44. reject(err)
  45. })
  46. })
  47. }

使用加密观察结果

调用:

  1. aboutToAppear() {
  2. let xxx;
  3. let globalPlainText = "This is a long plainTest! This is a long plainTest! This is a long plainTest!";
  4. console.log('Aes加密===原文is :' + globalPlainText)
  5. aesECBEncrypt(globalPlainText).then(res=>{
  6. console.log('Aes加密===加密后的密文is :' + res)
  7. xxx = res;
  8. }).catch(err => {
  9. console.log('Aes加密===catch :' + err)
  10. })
  11. setTimeout(function() {
  12. console.log('Aes加密=================================== ' )
  13. aesECBDecrypt(xxx).then(res=>{
  14. console.log('Aes加密===解密后的原文is: ' + res)
  15. }).catch(err => {
  16. console.log('Aes加密===解密:catch: ' + err)
  17. })
  18. }, 3000);
  19. }

结果:

  1. I 0FEFE/JsApp: Aes加密===原文is :This is a long plainTest! This is a long plainTest! This is a long plainTest!
  2. I 0FEFE/JsApp: Aes加密===加密后的密文is :zbusam9rOBPmJ072ENhEO9DCPD/DeSJOYvFGHOmYazQ7pFjUXUMW7aUfhyYtqVLQuflFtPW5Y8MG06n1C0stQJybjSA68it6TNVWP6GBkk8=
  3. I 0FEFE/JsApp: Aes加密===================================
  4. I 0FEFE/JsApp: Aes加密===解密后的原文is: This is a long plainTest! This is a long plainTest! This is a long plainTest!

可以看到打印出来是没有任何问题的,但是当我在加密原文中加入中文后出现了意想不到的结果,将 globalPlainText改为:This is a long plainTest! AES加密原文 ;观察打印结果

  1. I 0FEFE/JsApp: Aes加密===原文is :This is a long plainTest! AES加密原文
  2. I 0FEFE/JsApp: Aes加密===加密后的密文is :zbusam9rOBPmJ072ENhEO+8AvpCHJdNUxFsgzFxHMM55off1zCchwYL/C/3DHvPm
  3. I 0FEFE/JsApp: Aes加密===================================
  4. I 0FEFE/JsApp: Aes加密===解密后的原文is: This is a long plainTest! AES Æ

what ? 英文没问题,为啥换成中文就不行了?

解密过程出现中文乱码如何处理

百思不得其解,官方文档明明就是这么写的,难道是官方文档有问题?

uint8ArrayToString、 stringToUint8Array在文档中出现过多次,也有实例,文档中的使用:

  1. // 字节流以16进制输出
  2. function uint8ArrayToShowStr(uint8Array) {
  3. return Array.prototype.map
  4. .call(uint8Array, (x) => ('00' + x.toString(16)).slice(-2))
  5. .join('');
  6. }
  7. // 字节流转成可理解的字符串
  8. function uint8ArrayToString(array) {
  9. let arrayString = '';
  10. for (let i = 0; i < array.length; i++) {
  11. arrayString += String.fromCharCode(array[i]);
  12. }
  13. return arrayString;
  14. }

思考:会不会在字符串转字节流的时候出现了问题

String转16进制的原理是将字符串中每个字符转换为16进制的形式,

UTF-8编码:一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。中文标点占三个字节,英文标点占一个字节。

使用Java进行16进制转换的时候我们都知道会将内容先统一编码,再使用StringBuilder转16进制

  1. bytel] bytes = chinese.getBytes(Charset.forName("UTF-8"));
  2. StringBuilder hex= new StringBuilder();

但是刚刚的AES加密uint8ArrayToShowStr函数中没有统一指定编码格式,那如果一个中文占用了3个字符,岂不是无法解码,果然问题出在这,在翻阅鸿蒙util文档中我发现了TextEncoder:
文档中对TextEncoder是这么介绍的:

​ 该模块主要提供常用的工具函数,实现字符串编解码(TextEncoder,TextDecoder)这不就是我们想要的嘛 ​

完美解决中文加密解密乱码问题

修改字符串转成字节流 互相转换的函数如下:

  1. // 字符串转成字节流
  2. function stringToUint8Array(str, len = null) {
  3. let textEncoder = new util.TextEncoder();
  4. //获取点流并发出 UTF-8 字节流 TextEncoder 的所有实例仅支持 UTF-8 编码
  5. return textEncoder.encodeInto(str);
  6. }
  7. // 字节流转成可理解的字符串
  8. function uint8ArrayToString(array) {
  9. let textDecoder = util.TextDecoder.create("utf-8", { ignoreBOM: true })
  10. return textDecoder.decodeWithStream(new Uint8Array(array), { stream: false });
  11. }

 继续执行代码观察日志

  1. I 0FEFE/JsApp: Aes加密===原文is :This is a long plainTest! AES加密原文
  2. I 0FEFE/JsApp: Aes加密===加密后的密文is :zbusam9rOBPmJ072ENhEO5JErEY5X7HP2L/WPwARmlMV0PoGgXX+6ZhohYdJLhKt
  3. I 0FEFE/JsApp: Aes加密===================================
  4. I 0FEFE/JsApp: Aes加密===解密后的原文is: This is a long plainTest! AES加密原文

日志中可以看出,中文加密的密文也能被完整的解密出来,至此这篇文章页到了尾声,希望我的文章能够帮到你。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/717420
推荐阅读
相关标签
  

闽ICP备14008679号