因此,我一直在编写一个简单的命令行程序,用于使用Node的内置crypto
模块对文件进行加密和解密:
if( deciphered_object.multibase_digest != null ){
ciphered_object.multibase_digest = deciphered_object.multibase_digest;
try{
iv_buffer = Crypto.randomBytes(32);
try{
cipher = Crypto.createCipheriv( 'aes-256-ofb', secret_keyobject, iv_buffer );
if( cipher != null && typeof(cipher) === 'object' ){
encrypted_buffer = cipher.update( deciphered_object.deciphered_data_buffer );
encrypted_buffer += cipher.final();
if( encrypted_buffer != null && Buffer.isBuffer(encrypted_buffer) === true ){
try{
ciphered_object.ciphered_data_buffer = Buffer.alloc( (1 + iv_buffer.length + encrypted_buffer.length) );
buffer_offset = ciphered_object.ciphered_data_buffer.writeUInt8( iv_buffer.length, 0 );
buffer_offset += iv_buffer.copy( ciphered_object.ciphered_data_buffer, buffer_offset );
buffer_offset += encrypted_buffer.copy( ciphered_object.ciphered_data_buffer, buffer_offset );
if( buffer_offset === ciphered_object.ciphered_data_buffer.length ){
_return = [0, ciphered_object];
} else{
_return = [-256, 'Error: "buffer_offset" is not equal to "ciphered_object.ciphered_data_buffer.length"'];
}
} catch(error){
_return = [-128, Utility.format('Buffer.alloc threw: %s', error)];
}
} else{
_return = [-64, 'Error: "ciphered_buffer" is either null or not a buffer.'];
}
} else{
_return = [-32, 'Error: "cipher" is either null or not an object.'];
}
} catch(error){
_return = [-16, Utility.format('Crypto.createCipheriv threw: %s', error)];
}
} catch(error){
_return = [-8, Utility.format('Crypto.randomBytes threw: %s', error)];
}
} else{
_return = [-4, 'Error: "deciphered_object.multibase_digest" is either null or undefined.'];
}
但是,正如我通过蛮力测试发现的那样,显然createCipheriv只接受正好16个字节的键和IV长度;相对于IV的32个字节和Scrypt派生的密钥的4096个字节,我最初计划使用:
password = function_return[1];
function_return = SaltFile.LoadSaltFile();
if( function_return[0] === 0 ){
try{
scrypt_buffer = Crypto.scryptSync( password, function_return[1], 4096 );
secret_keyobject = Crypto.createSecretKey( scrypt_buffer );
if( secret_keyobject != null && typeof(secret_keyobject) === 'object' ){
_return = [0, secret_keyobject];
} else{
_return = [-32, 'Error: "secret_keyobject" is either null or not an object.'];
}
} catch(error){
_return = [-16,Utility.format('Crypto.scryptSync threw: %s', error)];
}
} else{
_return = [function_return[0], 'SaltFile.LoadSaltFile: '+function_return[1]];
}
最糟糕的是,createCipheriv的文档中没有提到这些大小限制:https://nodejs.org/api/crypto.html#crypto_crypto_createcipheriv_algorithm_key_iv_options
所以,我真正想知道的是为什么:为什么要使用这些任意限制?为什么要使用一个密码套件来强制使用任何旧计算机都可以在短短几分钟内强行使用的荒谬的弱密钥?为什么在文档中没有提到这些警告?
这个16字节的密钥限制对我来说似乎很荒唐,这使得整个crypto
模块都无法使用。可以通过使用其他算法或其他方法来规避吗?这些限制没有任何意义。...
编辑:
AES密钥为16、24和32字节,分别为128、192和256位。 iv始终为16个字节。这就是AES规范。 (@jww)
为什么RSA密钥通常为4096位(512字节),而AES却限制为32字节?为什么256位的熵足以满足AES的要求,但不能满足RSA的要求?是什么让AES密钥比RSA密钥更不容易受到暴力攻击?
如果要32字节的iv,则需要切换到Rijndael。 (@jww)
但是我认为AES是Rijndael。
基础对称密码学的复习可以帮助您确定为什么这个问题没有多大意义。 (@约书亚公园卢克)
真的,没有帮助;问这个问题之前我应该读什么“基本对称密码学”?显然,我不是专家,也没有声称自己是专家,但是,在我已经读过有关对称密码学的知识中,对于AES来说128位密钥足够安全是没有道理的,但是不是RSA。如果您希望我使用RTFM,那很好,但是在问这个问题之前,我应该在哪儿读过这本手册?我希望有人能解释为什么16位字节的安全密钥是安全的,尽管这没有什么直观的意义。
答案 0 :(得分:3)
为什么会有一个加密套件强制使用可笑的弱密钥,而任何旧计算机都可以在短短几分钟内强行使用它?
您严重低估了2 ^ 128的大小。如果您每秒可以尝试一万亿个密钥,那么您将需要10年至18年的时间才能尝试所有密钥,无论是给予还是接受。宇宙小于14e9岁。您看到了问题。
假定AES密钥(或更常见的是对称密码的所有密钥)是完全随机选择的。只要随机性的来源足够不可预测,一个键就和另一个键一样好。因此,没有针对密钥的“聪明”攻击。它要么是对键空间的详尽搜索,要么是攻击算法本身(即独立于任何键)。RSA是一个完全不同的故事,即非对称密码学。不能完全随机选择密钥。这是a series of computations that start out with two numbers that have specific properties的结果。该计算至少在原则上是可逆的。对于RSA来说,这是一个众所周知的分解问题(考虑到所有找到它的主要因素)。选择的数字必须足够大,以使在任何合理的时间内都无法进行分解。
总而言之,AES和RSA的密钥大小根本无法比较,因为AES和RSA是非常不同的加密算法,并且对各个密钥的攻击类型也有很大差异。