I'm writing this question + answer because I struggled a lot (maybe because of a lack of experience), got lost in many different ways of encrypting/decrypting things with node or python.
我之所以写这个问题+答案,是因为我经历了很多困难(也许是因为缺乏经验),在使用node或python进行加密/解密的许多不同方式中迷失了方向。
I thought maybe my case could help people in the future.
我想也许我的案子将来会对人们有所帮助。
What I needed to do:
我需要做的是:
- Get data from a form, encrypt them using Crypto (node-js)
- 从表单中获取数据,使用Crypto (node-js)对其进行加密
- Pass the encrypted data in Python and decrypt it using PyCrypto.
- 在Python中传递加密数据并使用PyCrypto对其进行解密。
I chose to use the AES encryption.
我选择使用AES加密。
Here is how I started (I'm not gonna go through everything I tried):
我是这样开始的(我不会把我尝试过的每件事都讲一遍):
-
I followed the example at the end of this page
我以这一页末尾的例子为例
Which gave in my case:
对我来说
(this might be a very bad mix between javascript and coffeescript)
(这可能是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') [...]
This worked pretty fine to encode my string.
这对我的字符串进行了很好的编码。
-
Then I wrote my python script to decrypt this string, using the readme on PyCrypto's github's page:
然后,我用PyCrypto的github的页面上的readme写了我的python脚本对这个字符串进行解密:
from Crypto.Cipher import AES [...] my_string = data_coming_from_rabbitmq obj = AES.new('mykeywhatever', AES.MODE_CBC) obj.decrypt(ciphertext) [...]
This obviously didn't work: in the readme there is an IV but since I didn't gave one in the node script, why would I give one in the python one?
这显然不起作用:在自述文件中有一个IV,但是由于我没有在节点脚本中给出一个,为什么我要在python脚本中给出一个呢?
After more googling, I learnt that node's Crypto uses OpenSSL, while PyCrypto apparently doesn't. So I looked into that and found those pages:
经过更多的搜索之后,我了解到node的加密使用的是OpenSSL,而PyCrypto显然没有。所以我查了一下,发现了那些页:
- How can I decrypt something with PyCrypto that was encrypted using OpenSSL?
- 如何用PyCrypto解密使用OpenSSL加密的东西?
- Is AES the same in libraries PyCrypto & Node.JS Crypto
- 在库PyCrypto和Node中,AES是相同的。JS加密
- and a lot more...
- 和更多的……
So things got complicated, no one is doing the same thing to decrypt data, I got lost, and asked for help.
所以事情变得很复杂,没有人做同样的事情来解密数据,我迷路了,请求帮助。
The answer is what my coworker and I came up with (well, mostly my corworker).
答案是我和我的同事想出的(嗯,大部分是我的同事)。
2 个解决方案
#1
13
So we started from the "How can i decrypt... OpenSSL" 's answer.
所以我们从“我如何解密……”OpenSSL”的回答。
-
We needed to modify the encryption script which gave:
我们需要修改加密脚本,它给出:
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 needs to be 16bytes long, key is 32bytes. And we changed
createCipher
tocreateCipheriv
.iv需要16字节长,密钥是32字节。我们把createCipher改为createCipheriv。
-
Back to the python decryption script:
回到python解密脚本:
Process was simply reading PyCrypto's documentation, and compare with the code we started from.
进程只是读取PyCrypto的文档,并与我们开始的代码进行比较。
Then we decided to just stick to the API, and start from scratch. And it gave:
然后我们决定继续使用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)
And it was as simple as that... Hope it'll help some of you!
就这么简单……希望它能帮助你们中的一些人!
Update:
As Perseids wrote in the comments of his answer, the IV has to be random and different for every message
正如Perseids在他回答的评论中所写的,每条信息都必须是随机的和不同的
#2
8
The system you are building is probably insecure
Except for storage you basically never want to just encrypt your data, but also authenticate it. Authentication in this context means that a valid message can only be generated by someone who knows the key. A widely used authentication scheme is HMAC.
除了存储之外,您基本上不希望只对数据进行加密,还要对其进行身份验证。在此上下文中的身份验证意味着有效的消息只能由知道密钥的人生成。一个广泛使用的认证方案是HMAC。
If you do not authenticate your messages anyone can feed data into your service. An attacker might not be able to fully control the outcome after decryption but he/she might still be very dangerous. For example, if you use CBC (which you do) and the most common paddings schemes (AES is a block cipher and can only encrypt 128bit Blocks of data) and an attacker can differentiate between a padding error and any other error then all your messages can be decrypted by an attacker. This is called a padding oracle attack and is far too common.
如果不对消息进行身份验证,任何人都可以向您的服务提供数据。攻击者可能无法在解密后完全控制结果,但是他/她可能仍然非常危险。例如,如果您使用CBC(你)和最常见的填充方案(AES是一个块密码,只有128位的数据块加密),攻击者可以区分填充错误和任何其他错误,那么你所有的消息可以由攻击者进行解密。这被称为填充oracle攻击,这种攻击太常见了。
To protect from this class of attacks you can use an authenticated encryption scheme, for example the GCM blockcipher mode.
为了防止此类攻击,您可以使用经过身份验证的加密方案,例如GCM块密码模式。
Also you have to protect against replay attacks. Consider a banking application and the data you are transmitting is a bank transfer order. Barring any TAN an attacker might record a previous transaction and replay this transaction to your service again and again thus transferring a multiple of the money the customer originally wanted to.
此外,你还必须防止重播攻击。考虑一个银行应用程序,您正在传输的数据是一个银行转账订单。除非使用任何TAN,攻击者可能会记录以前的事务,并将该事务反复地重放到您的服务中,从而将客户最初想要的钱转换成倍数。
Is the form you are getting the data from transmitted over HTTPS? If not: Can the key be eavesdropped by an attacker? How does a user know he got the form from you and not anybody else (SSL/TLS is as much about authentication as it is about confidentiality).
您正在从HTTPS传输的数据中获取数据的表单吗?如果没有:密钥可以被攻击者偷听吗?用户如何知道他是从您而不是其他人那里得到的表单(SSL/TLS不仅涉及机密性,还涉及身份验证)。
Probably I have forgotten some other attack vectors simple CBC-encryption offers.
我可能忘记了一些其他的攻击矢量简单的cbc加密提供。
Alternatives
Probably the easiest way to protect against these attacks is to transmit the form data over HTTPS. SSL/TLS was designed to prevent all of the above attacks and the client and server side implementations had a long time to mature.
防止这些攻击的最简单方法可能是通过HTTPS传输表单数据。SSL/TLS旨在防止上述所有攻击,客户机和服务器端实现需要很长时间才能成熟。
#1
13
So we started from the "How can i decrypt... OpenSSL" 's answer.
所以我们从“我如何解密……”OpenSSL”的回答。
-
We needed to modify the encryption script which gave:
我们需要修改加密脚本,它给出:
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 needs to be 16bytes long, key is 32bytes. And we changed
createCipher
tocreateCipheriv
.iv需要16字节长,密钥是32字节。我们把createCipher改为createCipheriv。
-
Back to the python decryption script:
回到python解密脚本:
Process was simply reading PyCrypto's documentation, and compare with the code we started from.
进程只是读取PyCrypto的文档,并与我们开始的代码进行比较。
Then we decided to just stick to the API, and start from scratch. And it gave:
然后我们决定继续使用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)
And it was as simple as that... Hope it'll help some of you!
就这么简单……希望它能帮助你们中的一些人!
Update:
As Perseids wrote in the comments of his answer, the IV has to be random and different for every message
正如Perseids在他回答的评论中所写的,每条信息都必须是随机的和不同的
#2
8
The system you are building is probably insecure
Except for storage you basically never want to just encrypt your data, but also authenticate it. Authentication in this context means that a valid message can only be generated by someone who knows the key. A widely used authentication scheme is HMAC.
除了存储之外,您基本上不希望只对数据进行加密,还要对其进行身份验证。在此上下文中的身份验证意味着有效的消息只能由知道密钥的人生成。一个广泛使用的认证方案是HMAC。
If you do not authenticate your messages anyone can feed data into your service. An attacker might not be able to fully control the outcome after decryption but he/she might still be very dangerous. For example, if you use CBC (which you do) and the most common paddings schemes (AES is a block cipher and can only encrypt 128bit Blocks of data) and an attacker can differentiate between a padding error and any other error then all your messages can be decrypted by an attacker. This is called a padding oracle attack and is far too common.
如果不对消息进行身份验证,任何人都可以向您的服务提供数据。攻击者可能无法在解密后完全控制结果,但是他/她可能仍然非常危险。例如,如果您使用CBC(你)和最常见的填充方案(AES是一个块密码,只有128位的数据块加密),攻击者可以区分填充错误和任何其他错误,那么你所有的消息可以由攻击者进行解密。这被称为填充oracle攻击,这种攻击太常见了。
To protect from this class of attacks you can use an authenticated encryption scheme, for example the GCM blockcipher mode.
为了防止此类攻击,您可以使用经过身份验证的加密方案,例如GCM块密码模式。
Also you have to protect against replay attacks. Consider a banking application and the data you are transmitting is a bank transfer order. Barring any TAN an attacker might record a previous transaction and replay this transaction to your service again and again thus transferring a multiple of the money the customer originally wanted to.
此外,你还必须防止重播攻击。考虑一个银行应用程序,您正在传输的数据是一个银行转账订单。除非使用任何TAN,攻击者可能会记录以前的事务,并将该事务反复地重放到您的服务中,从而将客户最初想要的钱转换成倍数。
Is the form you are getting the data from transmitted over HTTPS? If not: Can the key be eavesdropped by an attacker? How does a user know he got the form from you and not anybody else (SSL/TLS is as much about authentication as it is about confidentiality).
您正在从HTTPS传输的数据中获取数据的表单吗?如果没有:密钥可以被攻击者偷听吗?用户如何知道他是从您而不是其他人那里得到的表单(SSL/TLS不仅涉及机密性,还涉及身份验证)。
Probably I have forgotten some other attack vectors simple CBC-encryption offers.
我可能忘记了一些其他的攻击矢量简单的cbc加密提供。
Alternatives
Probably the easiest way to protect against these attacks is to transmit the form data over HTTPS. SSL/TLS was designed to prevent all of the above attacks and the client and server side implementations had a long time to mature.
防止这些攻击的最简单方法可能是通过HTTPS传输表单数据。SSL/TLS旨在防止上述所有攻击,客户机和服务器端实现需要很长时间才能成熟。