我需要在NodeJS应用程序中使用用户密码来实现对称加密。使用crypto.createCipheriv()
时,我是否需要对密码短语执行某种密钥派生以获得key
参数的值,或者仅按原样传递用户的密码短语就足够了,这是由实施来照顾?
答案 0 :(得分:2)
密码不应直接用作密钥,但可以将其用于产生带有KDF的密钥。这是因为期望密钥具有一定的大小,并且因为密码弱-它们仅使用有限的一组字节,并且通常包含单词。这使得它们容易受到暴力攻击和字典攻击。 KDF不仅产生强密钥,而且还引入了使蛮力攻击不切实际的工作因素。
createCipheriv()
不会修改键的内容或大小。文档中未提及,但遵循源代码(从createCipheriv
:source到Cipheriv
:source,到createCipherWithIV
:{{3 }},到prepareSecretKey
:source),我们看到密钥是按原样使用的。因此,密钥应该具有正确的大小,并且应该具有足够的复杂性。
Crypto提供了两个基于密码的KDF,即scrypt和PBKDF2。最好使用scrypt,因为它在CPU和内存资源方面非常昂贵,并且可以针对并行处理进行调整,而PBKDF2仅消耗CPU资源。两个KDF都需要加盐,盐应该长而随机。
使用source创建密钥:
const keySize = 16; // for AES-128
const salt = crypto.randomBytes(16);
const key = crypto.scryptSync('password', salt, keySize);
使用scrypt
创建密钥:
const keySize = 16; // for AES-128
const salt = crypto.randomBytes(16);
const key = crypto.pbkdf2Sync('password', salt, 10000, keySize, 'sha256');
其中“ sha256”是基础哈希,而10000是建议的最小迭代次数,它确定了工作因子。在scrypt中,常规工作因子是一个可选参数,默认值为16384(2 ^ 14),可以在options['cost']
中进行设置,在这里我们还可以设置块大小和并行化。根据操作系统的不同,这些值可以增加很多。每次操作大约需要100毫秒。
最后,Argon2被认为是非常好的KDF,像scrypt一样,可以针对CPU和内存消耗以及并行处理进行调整。尽管Argon2在crypto
中不可用,但它是由其他Node.js软件包提供的。
答案 1 :(得分:0)
破解密码的难度更多地取决于所使用的算法,而不是密码的长度。 (省略暴力攻击)
密钥扩展不能提高安全性,因为开始时您仍然具有相同的短密码。为了安全起见,请立即假设您有侵入程序,并且应用程序代码已泄漏。也就是说,所有标准算法和自定义算法都是公开的。
而且您仍然必须使用密码扩展名,因为大多数算法都要求密码具有特定的长度。
TL; DR:最好的方法是将密码处理到二进制缓冲区(字符串)中。
对称加密正是基于这样一个事实,即拥有秘密就可以执行反向操作。 对称表示操作是可逆的。
您的编程语言,框架或库都没关系。
在打包加密邮件的阶段有些差异。在base64中添加IV和内容的地方,您可能会收到原始消息或格式精美的消息。
您还必须以相同方式处理密钥。但这是关于编码big endian
和little endian
以及字符编码,例如:utf-8
,latin2
IV
是一项附加保护,旨在为相同的传入消息和机密生成不同的加密消息。但是,正如您在本节的最后一段中所写的那样:
它们不必是秘密的:IV通常只是添加到 密文消息未加密。
总结:您无需影响加密过程本身,而需要检查Electron需要哪些数据。
例如我的解密过程(在节点中,来自PHP的数据):
let crypto = {
key: Buffer.from('secret in hex', 'hex'),
cipher: 'aes-128-cbc',
iv_size: 16
}
let bData = Buffer.from(data.replace(/ /g,'+'), 'base64');
let iv = bData.slice(0, crypto.iv_size);
let text = bData.slice(crypto.iv_size);
var decipher = crypt.createDecipheriv(crypto.cipher, crypto.key, iv);
decipher.setAutoPadding(false);
var decrypted = decipher.update(text,'hex','hex');
decrypted += decipher.final('hex');
对于PHP加密:
$data = mcrypt_encrypt($this->_cipher, $this->_key, $data, $this->_mode, $iv);
// Use base64 encoding to convert to a string
return base64_encode($iv.$data);
//where
array(
'key'=> urldecode('secret in urlencode'),
'cipher' => MCRYPT_RIJNDAEL_128,
'mode' => MCRYPT_MODE_CBC,
),
如您所见,我必须找到在两个平台上实现的加密算法,并提供一种在两个平台上提供相同密钥的方法。