19

我写这个问题+答案是因为我很挣扎(可能是因为缺乏经验),迷失在使用节点或 python 加密/解密事物的许多不同方式中。

我想也许我的案子可以在未来帮助人们。

我需要做的:

  • 从表单中获取数据,使用 Crypto (node-js) 对其进行加密
  • 在 Python 中传递加密数据并使用 PyCrypto 对其进行解密。

我选择使用 AES 加密。

这是我开始的方式(我不会经历我尝试过的所有事情):

  • 我按照本页末尾的示例进行操作

    就我而言,这给出了:

    (这可能是 javascript 和 coffeescript 之间的一个非常糟糕的组合)

    crypto = require "crypto"
    [...]
    key = "mykeywhatever"
    cipher = crypto.createCipher('aes192', key)
    cipher.update('string i want to encode', 'binary', 'hex')
    encoded_string = cipher.final('hex')
    [...]
    

    这对我的字符串进行编码非常有效。

  • 然后我编写了我的 python 脚本来解密这个字符串,使用PyCrypto 的 github 页面上的自述文件:

    from Crypto.Cipher import AES
    [...]
    my_string = data_coming_from_rabbitmq
    obj = AES.new('mykeywhatever', AES.MODE_CBC)
    obj.decrypt(ciphertext)
    [...]
    

    这显然不起作用:在自述文件中有一个 IV,但由于我没有在节点脚本中给出一个,为什么我要在 python 中给出一个呢?

经过更多的谷歌搜索,我了解到节点的 Crypto 使用 OpenSSL,而 PyCrypto 显然没有。所以我调查了一下,发现了这些页面:

所以事情变得复杂了,没有人做同样的事情来解密数据,我迷路了,寻求帮助。

答案是我和我的同事想出的(嗯,主要是我的同事)。

4

2 回答 2

15

所以我们从“我如何解密... OpenSSL”的答案开始。

  • 我们需要修改给出的加密脚本:

    crypto = require "crypto"
    [...]
    var iv = new Buffer('asdfasdfasdfasdf')
    var key = new Buffer('asdfasdfasdfasdfasdfasdfasdfasdf')
    var cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
    cipher.update(new Buffer("mystring"));
    var enc = cipher.final('base64');
    [...]
    

    iv需要 16bytes 长,key是 32bytes。我们createCipher改为createCipheriv.

  • 回到python解密脚本:

    过程只是简单地阅读 PyCrypto 的文档,并与我们从.

    然后我们决定只使用 API,从头开始。它给了:

    from base64 import b64decode
    from Crypto.Cipher import AES
    [...]
    iv = 'asdfasdfasdfasdf'
    key = 'asdfasdfasdfasdfasdfasdfasdfasdf'
    encoded = b64decode('my_encrypted_string')
    
    dec = AES.new(key=key, mode=AES.MODE_CBC, IV=iv)
    value = dec.decrypt(encoded)
    

就这么简单……希望对你们中的一些人有所帮助!

更新:

正如 Perseids 在他的回答评论中所写,IV 必须是随机的,并且对于每条消息都不同

于 2013-08-14T16:04:34.410 回答
8

您正在构建的系统可能不安全

除了存储之外,您基本上不想只加密您的数据,还要对其进行身份验证。在这种情况下,身份验证意味着只有知道密钥的人才能生成有效消息。一种广泛使用的身份验证方案是HMAC

如果您不对您的消息进行身份验证,任何人都可以将数据输入您的服务。攻击者可能无法完全控制解密后的结果,但他/她可能仍然非常危险。例如,如果您使用 CBC(您这样做)和最常见的填充方案(AES 是一种分组密码,只能加密 128 位数据块)并且攻击者可以区分填充错误和任何其他错误,那么您的所有消息可以被攻击者解密。这被称为填充预言攻击,并且常见了。

为了防止此类攻击,您可以使用经过身份验证的加密方案,例如GCM块密码模式。

您还必须防止重放攻击。考虑一个银行应用程序,您传输的数据是银行转帐单。除非有任何 TAN,否则攻击者可能会记录先前的交易并将此交易一次又一次地重播到您的服务,从而转移客户最初想要的资金的倍数。

您获取数据的表单是通过 HTTPS 传输的吗?如果不是:密钥可以被攻击者窃听吗?用户如何知道他从您那里获得了表单,而不是其他任何人(SSL/TLS 既关乎身份验证,也关乎机密性)。

可能我忘记了其他一些简单的 CBC 加密提供的攻击向量。

备择方案

防御这些攻击的最简单方法可能是通过 HTTPS 传输表单数据。SSL/TLS 旨在防止上述所有攻击,客户端和服务器端的实现需要很长时间才能成熟。

于 2013-08-14T19:14:50.173 回答