我正在加密像这样的文本(node.js):
var text = "holds a long string..."
var cipher = crypto.createCipher("aes128", "somepassword")
var crypted = cipher.update(text, 'utf8', 'hex')
crypted += cipher.final('hex');
如果我直接将text
保存到文件中,则为N个字节。如果我保存crypted
,则文件大小约为N * 2个字节。
任何使加密文本的方法都尽可能接近N个字节?
答案 0 :(得分:4)
像AES这样的现代密码适用于二进制数据。加密字符数据时,首先将其转换为二进制表示形式。这基本上是UTF-8编码所做的。加密后,您将获得任意二进制数据,当您尝试对其进行解码时,该数据不一定是有效的UTF-8编码(几乎所有编码都具有特殊结构)。
如果省略output_encoding
和Cipher#update
中的Cipher#final
,则会得到Buffer
,您可以将其连接或写入文件。它以二进制格式管理数据,但在打印时默认为Hex。当您将缓冲区写入文件时,文件大小将接近明文大小,但它永远不会达到它。
AES是块密码,只能加密正好16个字节的单个块。像ECB或CBC这样的操作模式使您可以加密多个块。最后,像默认的PKCS#7填充这样的填充方案使您可以加密任意长度的文本。此填充总是在实际解密之前添加一些字节。确切地说,它增加了1到16个字节。
您可以使用cipher.setAutoPadding(false)
来阻止填充,但是您需要自己填充。你也可以使用流媒体模式,比如CTR(" aes-128-ctr"),但是你需要提供唯一的 IV(nonce)它的12个字节有任何安全性。这个nonce不必是秘密的,但你必须将它传送给解密者。
最后,密文与明文的大小完全相同。总有一些东西会使密文膨胀。
永远不要使用crypto.createCipher
。您需要使用随机密码来获得语义安全性。使用crypto.createCipheriv
新鲜且随机的IV。对于CTR模式,IV必须是唯一的,对于CBC模式,它必须是不可预测的。
始终使用经过身份验证的加密。它使您能够检测错误的密钥和(恶意)篡改密文。 Here's AES-GCM的一个例子。
答案 1 :(得分:3)
问题在于您的.MP3
编码。基本上你建议密码
'hex'
编码text
的二进制表示形式
utf8
编码十六进制编码使用2个字节来表示1个实际字节,因此您获得的文件大小约为纯文本大小的两倍。
解决方案是为您的密文使用更高效的编码,该密文仍然能够保存所有可能的字节值,从而排除了一个简单的字符串。尝试:
hex
这会将密文编码为base64编码的字符串。
我创建了一个online example,结果是:
var crypted = cipher.update(text, 'utf8', 'base64');
crypted += cipher.final('base64');
安全公告:请勿在生产中使用此密钥/ IV生成。我强烈建议使用text: 488890
crypted hex length: 977792, ratio: 2.0000245453987606
crypted base64 length: 651864, ratio: 1.3333551514655648
为每次加密使用不同的IV。但是出于演示目的,这很好。