2016-04-21 7 views
7

У меня есть пароль, который шифрует с помощью JavaScriptКак расшифровать пароль из JavaScript CryptoJS.AES.encrypt (пароль, парольная фраза) в Python

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

Затем я попытался расшифровать пароль приходит из JavaScript в 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(password, passphrase) является объектом с некоторыми атрибутами (например, sigBytes:16, words: [-44073646, -1300128421, 1939444916, 881316061]). Кажется, создается случайным образом.

С одной веб-страницы, он говорит мне, что JS имеет два способа шифрования пароля (reference link):

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

То, что я видел в JavaScript должен быть вариант а. Однако только вариант b эквивалентен AES.new() в python.

Вопросов:

  1. Как я могу восстановить этот пароль в Python без изменения кода JavaScript?

  2. Если мне нужно IV в Python, как я могу получить его из пароля, который используется в JavaScript?

+0

CryptoJS AES по умолчанию работает в режиме CBC, поэтому никакого режима CBF в python не требуется. AES.encrypt возвращает также объект. с toString() вы получаете кодировку base64, содержащую соль, iv и сообщение. Все они вам нужно разделить конец фида на Python. также помните, что пароль и ключ - это две разные вещи. – SKR

+0

Спасибо, просто измените ключ на sample_passphrase, чтобы он стал более понятным. но это, если я не могу получить toString() вывод? Это становится невозможной работой? @SKR – Bing

+0

, значит, вы имеете в виду, что у вас нет контроля над js? Как js-код продолжается? что происходит с объектом, который был зашифрован? Вы должны каким-то образом получить соль и iv из js. Или вы просто хотите «высмеять» поведение js и создать аналогичное зашифрованное сообщение для внешнего api или что-то еще? – SKR

ответ

10

Вы должны реализовать OpenSSL, EVP_BytesToKey, потому что это то, что использует CryptoJS для получения ключа и IV из предоставленного пароля, но PyCrypto поддерживает только ключ + IV типа шифрования. CryptoJS также генерирует случайную соль, которая также должна быть отправлена ​​на сервер. Если объект зашифрованного текста преобразуется в строку, он автоматически использует OpenSSL-совместимый формат, который включает случайную соль.

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

CryptoJS по умолчанию 256 бит размер ключа для AES, PKCS # 7 и режим CBC. AES имеет 128-битный размер блока, который также является размером IV. Это означает, что мы должны запросить 32 + 16 = 48 байт от EVP_BytesToKey. Я нашел полуфункциональную реализацию here и расширил ее дальше.

Вот полный Python (протестирован с 2.7 и 3.4) код, который совместим с 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.

JavaScript AES-шифрование в браузере без HTTPS является простым обфускацией и не обеспечивает реальной защиты, поскольку ключ должен передаваться вместе с зашифрованным текстом.

+0

Попробовали это, он отлично работает. Большое спасибо. Я не очень разбираюсь в том, как шифровать и расшифровывать работу с этими параметрами, если бы вы могли отметить некоторые ссылочные ссылки, я могу получить эту информацию, которая будет очень оценена. – Bing

+0

Я не уверен, что понимаю, какие ссылки вы ищете. Если вы говорите о том, как я все это знаю, то самым простым способом было бы просто взять незащищенный исходный код и прочитать его. –

+0

Да, я имею в виду, как получить эту информацию. Я проверю код. Благодарю. – Bing