如何在Python中解密来自JavaScript CryptoJS.AES.encrypt(密码,密码)的密码 [英] How to decrypt password from JavaScript CryptoJS.AES.encrypt(password, passphrase) in Python

查看:418
本文介绍了如何在Python中解密来自JavaScript CryptoJS.AES.encrypt(密码,密码)的密码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个通过JavaScript加密的密码

I have a password which is encrypt from JavaScript via

  var password = 'sample'
  var passphrase ='sample_passphrase'
  CryptoJS.AES.encrypt(password, passphrase)

然后我尝试解密密码来自Python中的JavaScript:

Then I tried to decrypt the password comes from JavaScript in Python:

  from Crypto.Cipher import AES
  import base64

  PADDING = '\0'

  pad_it = lambda s: s+(16 - len(s)%16)*PADDING
  key = 'sample_passphrase'
  iv='11.0.0.101'        #------> here is my question, how can I get this iv to restore password, what should I put here?
  key=pad_it(key)        #------> should I add padding to keys and iv?
  iv=pad_it(iv)          ##
  source = 'sample'
  generator = AES.new(key, AES.MODE_CFB,iv)
  crypt = generator.encrypt(pad_it(source))
  cryptedStr = base64.b64encode(crypt)
  print cryptedStr
  generator = AES.new(key, AES.MODE_CBC,iv)
  recovery = generator.decrypt(crypt)
  print recovery.rstrip(PADDING)

我从浏览器控制台检查了JS,它在中显示IV。CryptoJS.AES.encrypt(密码,密码)是一个具有某些属性的对象(如 sigBytes:16,单词:[ - 44073646, -1300128421,1939444916,881316061] )。它似乎是随机生成的。

I checked JS from browser console, it shows IV in CryptoJS.AES.encrypt(password, passphrase) is a object with some attributes( like sigBytes:16, words: [-44073646, -1300128421, 1939444916, 881316061]). It seems generated randomly.

从一个网页上,它告诉我JS有两种方法来加密密码
参考链接):

From one web page, it tells me that JS has two way to encrypt password (reference link ):



  • 一个。 crypto.createCipher(算法,密码)

  • b。 crypto.createCipheriv(算法,密钥,iv)

  • a. crypto.createCipher(algorithm, password)
  • b. crypto.createCipheriv(algorithm, key, iv)

我在JavaScript中看到的应该是选项a。但是,只有选项b相当于python中的AES.new()。

What I saw in JavaScript should be option a. However, only option b is equivalent to AES.new() in python.

问题


  1. 如何在不更改JavaScript代码的情况下在Python中恢复此密码?

  1. How can I restore this password in Python without changing JavaScript code?

如果我需要Python中的IV,我如何从JavaScript中使用的密码中获取它?

If I need IV in Python, how can I get it from the password that is used in JavaScript?


推荐答案

您必须实现OpenSSL的 EVP_BytesToKey ,因为这就是CryptoJS用来派生的密码和IV来自提供的密码,但pyCrypto仅支持密钥+ IV类型加密。 CryptoJS还生成一个随机盐,也必须发送到服务器。如果将密文对象转换为字符串,则它会自动使用包含随机盐的OpenSSL兼容格式。

You will have to implement OpenSSL's EVP_BytesToKey, because that is what CryptoJS uses to derive the key and IV from the provided password, but pyCrypto only supports the key+IV type encryption. CryptoJS also generates a random salt which also must be send to the server. If the ciphertext object is converted to a string, then it uses automatically an OpenSSL-compatible format which includes the random salt.

var data = "Some semi-long text for testing";
var password = "some password";
var ctObj = CryptoJS.AES.encrypt(data, password);
var ctStr = ctObj.toString();

out.innerHTML = ctStr;

<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
<div id="out"></div>

可能的输出:


U2FsdGVkX1 + ATH716DgsfPGjzmvhr + 7 + pzYfUzR + 25u0D7Z5Lw04IJ + LmvPXJMpz

U2FsdGVkX1+ATH716DgsfPGjzmvhr+7+pzYfUzR+25u0D7Z5Lw04IJ+LmvPXJMpz

对于AES,PKCS#7 paddin,CryptoJS默认为256位密钥大小g和CBC模式。 AES具有128位块大小,也是IV大小。这意味着我们必须从EVP_BytesToKey请求32 + 16 = 48字节。我在这里找到了一个半功能实现,并进一步扩展了它。

CryptoJS defaults to 256 bit key size for AES, PKCS#7 padding and CBC mode. AES has a 128 bit block size which is also the IV size. This means that we have to request 32+16 = 48 byte from EVP_BytesToKey. I've found a semi-functional implementation here and extended it further.

以下是完整的Python(经过2.7和3.4测试)代码,与CryptoJS兼容:

Here is the full Python (tested with 2.7 and 3.4) code, which is compatible with CryptoJS:

from Crypto import Random
from Crypto.Cipher import AES
import base64
from hashlib import md5

BLOCK_SIZE = 16

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

def unpad(data):
    return data[:-(data[-1] if type(data[-1]) == int else ord(data[-1]))]

def bytes_to_key(data, salt, output=48):
    # extended from https://gist.github.com/gsakkis/4546068
    assert len(salt) == 8, len(salt)
    data += salt
    key = md5(data).digest()
    final_key = key
    while len(final_key) < output:
        key = md5(key + data).digest()
        final_key += key
    return final_key[:output]

def encrypt(message, passphrase):
    salt = Random.new().read(8)
    key_iv = bytes_to_key(passphrase, salt, 32+16)
    key = key_iv[:32]
    iv = key_iv[32:]
    aes = AES.new(key, AES.MODE_CBC, iv)
    return base64.b64encode(b"Salted__" + salt + aes.encrypt(pad(message)))

def decrypt(encrypted, passphrase):
    encrypted = base64.b64decode(encrypted)
    assert encrypted[0:8] == b"Salted__"
    salt = encrypted[8:16]
    key_iv = bytes_to_key(passphrase, salt, 32+16)
    key = key_iv[:32]
    iv = key_iv[32:]
    aes = AES.new(key, AES.MODE_CBC, iv)
    return unpad(aes.decrypt(encrypted[16:]))


password = "some password".encode()
ct_b64 = "U2FsdGVkX1+ATH716DgsfPGjzmvhr+7+pzYfUzR+25u0D7Z5Lw04IJ+LmvPXJMpz"

pt = decrypt(ct_b64, password)
print("pt", pt)

print("pt", decrypt(encrypt(pt, password), password))






类似的代码可以在我的答案中找到 Java PHP

没有HTTPS的浏览器中的JavaScript AES加密是简单的混淆,并没有提供任何真正的安全性,因为密钥必须与密文一起传输。

JavaScript AES encryption in the browser without HTTPS is simple obfuscation and does not provide any real security, because the key must be transmitted alongside the ciphertext.

这篇关于如何在Python中解密来自JavaScript CryptoJS.AES.encrypt(密码,密码)的密码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆