首先,面向的问题是: Keystore 的生成很慢。
生成 Keystore 多慢呢,在 PC 端的浏览器上,从点击生成按钮开始大约要等 4 秒钟看到结果,这个还可以接受吧。
之后在一台 CPU 主频更低的笔记本上,需要约十几秒,还可以忍耐一下。
但在手机端 APP 上,手机配置低还可能导致 APP 闪退,直接就不能用了,所以就需要研究一下 Keystore 是怎么生成的,以及 Keystore 的参数分析。
关于 Keystore 是什么,可以搜索到的文章较多,但是解析 Keystore 的参数文章就很少,搜索到了简书上一篇文章 【HD-新钱包】-keystore参数详解,通过这篇文章有了一些了解,然后阅读了链接中的英文材料。
先说结论,主要是是 Keystore 中 crypto.kdfparams.n 这个字段影响生成 Keystore 的速度。现在默认的 n 值是 262144。
一个例子:
{
"crypto" : {
"cipher" : "aes-128-ctr",
"cipherparams" : {
"iv" : "83dbcc02d8ccb40e466191a123791e0e"
},
"ciphertext" : "d172bf743a674da9cdad04534d56926ef8358534d458fffccd4e6ad2fbde479c",
"kdf" : "scrypt",
"kdfparams" : {
"dklen" : 32,
"n" : 262144, // 在这里
"r" : 8,
"p" : 1,
"salt" : "ab0c7876052600dd703518d6fc3fe8984592145b591fc8fb5c6d43190334ba19"
},
"mac" : "2103ac29920d71da29f15d75b4a16dbe95cfd7ff8faea1056c33131d846e3097"
},
"id" : "3198bc9c-6672-5ab3-d995-4942343ae5b6",
"version" : 3
}
直接看 kdfparams 那部分,首先 kdf(key derivation function)使用 scrypt,kdfparams 顾名思义就是参数。
那么 n 有什么影响呢。
在使用 scrypt 这个算法计算 Derived key 的时候:
- 参数 r 决定了连续读大小(sequential read size),通常不应该修改。
- 参数 n 和 r 决定了占用的内存区域大小和哈希迭代次数(占用的内存大小为 128⋅n⋅r bytes,迭代次数为 2⋅n⋅r),所以可以修改的参数是 n。
当 n = 262144,r = 8,占用内存 268435456 bytes,就是 256MB,迭代次数就是 4194304 次。
那么 n 值为什么会是 262144,因为这个 scrypt 算法是用来加密你的私钥的,所以理论上越安全越好,所以这个 n 值其实是用来应对想要暴力破解你的 Keystore 的人的。
那么使用更大的 n 值生成 Keystore,在破解的时候需要的内存更大,计算的时间更长。这样破解者就需要购买更好的硬件,花费更长的时间来破解,破解的难度越大越好,时间和金钱成本过高,破解的收益 cover 不住破解的成本。
所以随着硬件的性能提高和价格的降低,n 值也会设定的越来越大。
当然,n 值也不能过大,因为 Keystore 需要能够在 PC 浏览器上或者在用户的手机上生成和使用,那么 n 值就得匹配用户手上主流的硬件设备,同时也得兼顾用户体验。
所以最后在想要兼容的性能稍差的测试机上试一试,我使用的测试机型号是 华为TRT-AL00(CPU频率 1.4GHz,内存 3GB)。
简单说一下最后的结果,当 n = 262144 时,会导致应用卡死闪退。最后减小 n 值,经过几轮测试,把 n 值定在了 65536,这样来兼容大部分低端配置的手机。