CryptoJS和Pycrypto一起工作

时间:2012-07-19 18:42:59

标签: javascript python encryption pycrypto cryptojs

我正在使用CryptoJS(v 2.3)加密Web应用程序中的字符串,我需要在Python上在服务器上解密它,所以我使用的是PyCrypto。我觉得我错过了一些东西,因为我无法工作。

这是JS:

Crypto.AES.encrypt('1234567890123456', '1234567890123456',
                   {mode: new Crypto.mode.CBC(Crypto.pad.ZeroPadding)})
// output: "wRbCMWcWbDTmgXKCjQ3Pd//aRasZ4mQr57DgTfIvRYE="

蟒蛇:

from Crypto.Cipher import AES
import base64
decryptor = AES.new('1234567890123456', AES.MODE_CBC)
decryptor.decrypt(base64.b64decode("wRbCMWcWbDTmgXKCjQ3Pd//aRasZ4mQr57DgTfIvRYE="))
# output: '\xd0\xc2\x1ew\xbb\xf1\xf2\x9a\xb9\xb6\xdc\x15l\xe7\xf3\xfa\xed\xe4\xf5j\x826\xde(m\xdf\xdc_\x9e\xd3\xb1'

2 个答案:

答案 0 :(得分:4)

这是一个使用CryptoJS 3.1.2的版本。始终注意以下事项(在两种语言中使用相同的内容):

  • 操作模式(本例中为CBC)
  • 填充(在这种情况下为零填充;更好地使用PKCS#7填充)
  • 键(相同的派生功能或清除键)
  • 编码(密钥,明文,密文等的相同编码)
  • IV(加密期间生成,通过解密)

如果将字符串作为encrypt()参数传递给CryptoJS ciphertext函数,则该字符串用于派生用于加密的实际密钥。如果您希望使用密钥(有效大小为16,24和32字节),则需要将其作为WordArray传递。

CryptoJS加密的结果是OpenSSL格式的密文字符串。要从中获取实际的密文,您需要访问它上面的var key = CryptoJS.enc.Utf8.parse('1234567890123456'); function encrypt(msgString, key) { // msgString is expected to be Utf8 encoded var iv = CryptoJS.lib.WordArray.random(16); var encrypted = CryptoJS.AES.encrypt(msgString, key, { iv: iv }); return iv.concat(encrypted.ciphertext).toString(CryptoJS.enc.Base64); } function decrypt(ciphertextStr, key) { var ciphertext = CryptoJS.enc.Base64.parse(ciphertextStr); // split IV and ciphertext var iv = ciphertext.clone(); iv.sigBytes = 16; iv.clamp(); ciphertext.words.splice(0, 4); // delete 4 words = 16 bytes ciphertext.sigBytes -= 16; // decryption var decrypted = CryptoJS.AES.decrypt({ciphertext: ciphertext}, key, { iv: iv }); return decrypted.toString(CryptoJS.enc.Utf8); } 属性。

对于每个加密,IV必须是随机的,以便它在语义上是安全的。这样攻击者就不能说多次加密的同一个明文在查看密文时是否真的是同一个明文。

以下是我的一个例子。

JavaScript的:

BLOCK_SIZE = 16
key = b"1234567890123456"

def pad(data):
    length = BLOCK_SIZE - (len(data) % BLOCK_SIZE)
    return data + chr(length)*length

def unpad(data):
    return data[:-ord(data[-1])]

def encrypt(message, passphrase):
    IV = Random.new().read(BLOCK_SIZE)
    aes = AES.new(passphrase, AES.MODE_CBC, IV)
    return base64.b64encode(IV + aes.encrypt(pad(message)))

def decrypt(encrypted, passphrase):
    encrypted = base64.b64decode(encrypted)
    IV = encrypted[:BLOCK_SIZE]
    aes = AES.new(passphrase, AES.MODE_CBC, IV)
    return unpad(aes.decrypt(encrypted[BLOCK_SIZE:]))

Python代码:

self.redbar.transform = CGAffineTransformMakeTranslation(30, 30)

其他注意事项:

您似乎想要使用密码作为密钥。密码短语通常是人类可读的,但密钥则不是。您可以使用密码短语从PBKDF2,bcrypt或scrypt等函数派生密钥。

上面的代码并不完全安全,因为它缺乏身份验证。未经验证的密文可能会导致可行的攻击和未被注意的数据操作。通常,加密然后MAC方案采用良好的MAC功能,如HMAC-SHA256。

答案 1 :(得分:0)

注意:salt,iv,padding在js和python中应该相同

生成盐和iv值并将其转换为使用CryptoJS.enc.Utf8.parse()的字节字符串

js文件

var encrypted = CryptoJS.AES.encrypt(JSON.stringify(json_data), CryptoJS.enc.Utf8.parse(data['salt']) , { iv: CryptoJS.enc.Utf8.parse(data['iv']) , mode: CryptoJS.mode.CBC , padding: CryptoJS.pad.Pkcs7});
en_data = encrypted.ciphertext.toString(CryptoJS.enc.Base64)

将此加密的数据发送到python文件

python文件

from Crypto.Util.Padding import pad, unpad

ct = request.POST['encrypted_data']
data = base64.b64decode(ct)
cipher1 = AES.new(salt, AES.MODE_CBC, iv)
pt = unpad(cipher2.decrypt(data), 16)
data = json.loads(pt.decode('utf-8'))
        
pycrypto中的

pad和upad默认使用pkcs#7

盐和iv值应在字节字符串中