HarmonyOS 鸿蒙Next API9 (ArkTS) 加密框架 cryptoFramework 所有【对称加密算法组合】测试——避坑指南
HarmonyOS 鸿蒙Next API9 (ArkTS) 加密框架 cryptoFramework 所有【对称加密算法组合】测试——避坑指南
最近需要加密处理数据,因此测试了API 9中现有的加密框架cryptoFramework支持的所有75种“对称加密算法”(非对称加密测试还未完成,后面再补)。总结如下:
一、对称加密算法组合因素:
* 算法类型:3DES, AES 两种
* 密钥长度:3DES-192 一种;AES-128/192/256 三种
* 分组模式:3DES-ECB, CBC, OFB, CFB 四种;AES-ECB, CBC, CTR, OFB, CFB, GCM, CCM 七种
填充模式:都是 NoPadding/PKCS5/PKCS7 三种
=》合计:3DES 12种组合;AES 63种组合。
二、经验:经测试,67种成功,8种不成功。
测试数据:明文为小字符串,有纯英文和中英混合两种(30个字符以内),共计150次测试。
* 测试流程:(ArkTS代码需要导入:import cryptoFramework from “@ohos.security.cryptoFramework”)
1) 创建Cipher对象:this.cipher = cryptoFramework.createCipher(algName);
2) 生成对称密钥:
let skg: cryptoFramework.SymKeyGenerator = cryptoFramework.createSymKeyGenerator(alg);
skg.generateSymKey((err, symKey) => {…}); //… 表示处理报错,或将结果赋值给对称密钥变量
3) 根据分组模式创建相应ParamsSpec类的子类对象或null为参数:
this.paramsSpec = {algName: “GcmParamsSpec”, iv: {data: stringToUint8Array(iv)}, aad: {data: stringToUint8Array(aad)},
authTag: {data:stringToUint8Array(authTag)}}; //以GCM分组为例;CCM分组改 algName: “IvParamsSpec”;ECB 直接赋值 null;其它分组去掉 aad 和 authTag 项即可。
注意:不同分组 iv, aad, authTag的长度是不同的。后面详述 。
4) 初始化Cipher对象(前两步提供所需参数symKey, paramsSpec):
this.cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, this.symKey, this.paramsSpec, (err) =>{…}); //… 表示判断报错进行处理,或进入下一步
5) 进行加密:理论上可先执行this.cipher.update(…) 最后执行 doFinal(…) 完成整个加密过程,不过是对于明文数据较大情况,本测试明文较小,可直接调用doFinal().
this.cipher.doFinal({data: stringToUint8Array(data)}, (err, output) => {…}); //这里有个坑,后面详述
6) 提取密文(及(GCM/CCM模式下所需) authTag),转换为字符串,然后进入解密阶段:
提取密文示例:非GCM/CCM模式下密文提取: this.scramble = uint8ArrayToString(data);
GCM/CCM模式密文提取:this.scramble = uint8ArrayToString(data.subarray(0, data.byteLength - 16)); //此为GCM情况,CCM将16改为12
authTag提取: this.authTag = uint8ArrayToString(data.subarray(-16)); //此为GCM模式的authTag提取,CCM改16为12
7) 按需重新准备ParamsSpec对象(仅GCM/CCM模式下需要):用加密时的iv, add 及上一步提取的 authTag 创建新的ParamsSpec类的子类对象,见第3)步
8) 重新初始化Cipher对象,与第4)步类似,只要将 ENCRYPT_MODE 改为 DECRYPT_MODE,paramsSpec用上一步新创建的。
9) 调用 doFinal() 进行解密,数据用加密结果提取的密文转换而来的 scramble 即可,见第5) 6) 步;对于输出结果进行转换,形成可显示的字符串数据。
doFinal() 返回变量 output,取其属性data,即 output.data 为解密所得,类型为 DataBlob,想得到 string 类型需要转换,此处也有个坑,后面详述。
* 加/解密用时:成功的加密算法组合对于本测试所用小字符串进行加密和解密都较为快捷,在模拟器上运行加、解密耗时都在30毫秒以内;之后可能测试大量小数据加密和单个大数据加密耗时对比,有了再补充吧。
* 未成功算法组合8种:四种(算法+密钥长度) 与 ECB或CBC+NoPadding的组合都不能正常执行 doFinal() 操作,原因未找到,应该和测试代码和配置无关(因为其它相似配置完美通过),现已提交论坛,看官方有无说法,有知道的同学也请分享一下。
三、坑位详解:
1、有关字符串和DataBlob之间的相互转换:先说 DataBlob,看文档就是个“无符号8位整数数组(Uint8Array)的包装类,类似C、Java的 byte[],若理解错误请指正哈。
=》加解密流程中所需参数 iv, aad, authTag, 加解密所用数据都是需要提供DataBlobo类型的参数,而代码中常用的多为字符串或数值类型;因而需要先转换一下;
官方文档示例中提供了两个转换方法:stringToUint8Array() 和 uint8ArrayToString(),测试发现对于纯英文字符串工作正常,对于带中文的字符串出现乱码(中文部分乱码,英文部分正常)。经深入测试分析,发现对于这两个方法只能处理单字节Unicode字符,两个以上字节的字符被截去高位部分,因此出现乱码。搜索万能的互联网,找到一篇文章,提供了更好的转换代码:https://zhuanlan.zhihu.com/p/444177696?utm_id=0。其中的 encode(), decode()分别将字符串转换成Uint8Array及反向转换。经测试对于纯英文或中英混合字符串都可正确转换。注意:原文中的decode()代码中有个小bug,case7中7前面需要有空格,没有也能运行不报错,但输出吃字符,避坑!
=》官方示例中提供的两个转换方法也有用,对于iv, aad, authTag 的转换可用;测试中是从数字/大小写英文字母/(键盘上所有)英文符号 中随机抽取n个字符作为这三个参数转换前的字符串;同样在加密完成后密文到字符串的转换以及 提取的authTag到字符器的转换都是用 uint8ArrayToString(),而非 decode(),而且一定不要用 decode(),否则可能会出现闪退,原因未细究,估计和 Unicode 编码的 CodePoint 未完整覆盖所有字节有关,导致 decode()中调用 String.fromCodePoint() 时异常有关。
=》总结一下这四个方法的应用场景:辅助参数的转换用官方两个转换方法s->u或u->s;密文转换成字符串以保存时用官方s->u转换方法;密文字符串解密时用官方s->u转换方法转换后作为解密方法参数;加密时明文导入用encode方法,解密时输出还原为明文用 decode方法;这样对于纯英文,或带中文的内容都可正确处理。
2、有关 iv, aad, authTag 的生成和使用注意事项:
=》生成:官方文档中未细说如何生成,本测试中是用随机提取字符的方式生成,创建一个包括所有键盘上的英文字符(数字/字母/符号)的字符串,从中随机提取组成规定长度的字符串,然后在创建ParamsSpec对象时用stringToUint8Array()转换一下。
=》注意不同分组模式下所需的各参数的字符串长度,列出如下:(生成字符串时按这个长度生成即可)
GCM: iv 12, add 8, authTag 16; CCM: iv 7, aad 8, authTag 12; 其它分组(除ECB外):3DES算法 iv 8,AES算法时 iv 16
3、总结一下:此加解密框架对于对称加/解密操作还是比较容易上手的,思路也比较清晰;坑不多,主要是编码转换问题;用于文件或数据库加密存储不是比较容易的;网络传输未测试;有机会也会补充。
最后,希望对需要的同学有用。。。
有关和NoPadding组合不能正常执行doFinal()的问题自己找到原因了。
ECB和CBC分组模式下,如果填充采用NoPadding选项,则输入的明文必须在长度上符合以下要求,否则加密无法成功:
3DES分组长度为64B,故明文转化为字节流后必须是8字节的整数倍,否则doFinal()报错;
AES分组长度为128B,明文转化为字节流后必须是16字节的整数倍,否则doFinal()报错。
希望对小伙伴们避坑有帮助!
我这里CBC|NoPadding, doFinal()后的Uint8Array值不对。
那就选PKCS5 | PKCS7 之一替换NoPadding,由API帮助你补足,虽然自己也能做但有现成的直接用吧,也省却调试时间,除非想自己搞透填充机制和方法。
对于HarmonyOS 鸿蒙Next API9 (ArkTS) 加密框架 cryptoFramework 的所有【对称加密算法组合】测试,以下是一些避坑指南:
- 算法与密钥组合:cryptoFramework支持3DES和AES两种算法类型。3DES有192位密钥长度,AES则有128/192/256三种。注意,不是所有组合都能成功,测试发现部分ECB或CBC与NoPadding的组合无法执行doFinal()操作,原因待官方确认。
- 分组模式与填充:3DES支持ECB、CBC、OFB、CFB四种分组模式,AES则更多,包括ECB、CBC、CTR、OFB、CFB、GCM、CCM。填充模式主要有NoPadding、PKCS5、PKCS7三种。
- 参数配置:不同分组模式的参数配置有所不同,例如GCM和CCM需要额外的aad和authTag参数。配置错误可能导致加密失败。
- 数据转换:在加密和解密过程中,字符串和DataBlob之间的转换是常见问题。官方提供的stringToUint8Array()和uint8ArrayToString()方法在处理中文时可能出现乱码,建议使用更健壮的转换方法。
- 测试环境:确保单元测试环境配置正确,包括必要的权限和依赖库。
鸿蒙Next教程已发布,可以先学学:https://www.itying.com/goods-1204.html