如何使用加密加密文本而不增加太多大小?

时间:2016-01-19 08:46:11

标签: node.js encryption cryptography

我正在加密像这样的文本(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个字节?

2 个答案:

答案 0 :(得分:4)

像AES这样的现代密码适用于二进制数据。加密字符数据时,首先将其转换为二进制表示形式。这基本上是UTF-8编码所做的。加密后,您将获得任意二进制数据,当您尝试对其进行解码时,该数据不一定是有效的UTF-8编码(几乎所有编码都具有特殊结构)。

如果省略output_encodingCipher#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编码。基本上你建议密码

  1. 使用'hex'编码
  2. 获取字符串text的二进制表示形式
  3. 加密
  4. 使用utf8编码
  5. 将二进制编码的字节转换为字符串

    十六进制编码使用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。但是出于演示目的,这很好。