Что такое обратная операция Javascript CryptoJS.enc.base64.stringify (data) в Python3 / Django? - PullRequest
2 голосов
/ 12 октября 2019

Я пытаюсь зашифровать в Javascript и расшифровать те же данные в Python / Django.

Отказ от ответственности: не код уровня производства, но для изучения концепции

Я генерирую ключ через Diffie Hellman (Ajax используя jQuery), который я передаю нижеприведенной функции шифрования,Обычно ввод - это идентификатор и пароль в формате JSON.

Так происходит шифрование. {Где-то нашел код.}

function toWordArray(str){
    return CryptoJS.enc.Utf8.parse(str);
}

function toString(words){
    return CryptoJS.enc.Utf8.stringify(words);
}

function toBase64String(words){
    return CryptoJS.enc.Base64.stringify(words);
}

function encrypt(input, key){
    console.log("Input: " + input);  
    var PROTOCOL_AES256 = 2;
    var secret_key = CryptoJS.SHA256(key);
    var header = toWordArray("AMAZON" + String.fromCharCode(PROTOCOL_AES256));
    var iv = CryptoJS.lib.WordArray.random(16);
    var body = CryptoJS.AES.encrypt(input, secret_key, {iv: iv});

    // construct the packet
    // HEADER + IV + BODY
    header.concat(iv);
    header.concat(body.ciphertext);

    console.log("Bytes before Base64 encoding: " + header); //Line 1
    // encode in base64
    return toBase64String(header);
}

Вывод, который я получаю, выглядит следующим образом:

final key: 47 signin:119:33
Input: {"name":"Buzz","password":"lightyear"} signin:55:25
Bytes before Base64 encoding: 414d415a4f4e02e8ec9b8a949eb754e305acfbe5207f1ebe75272c18146bca57ce399928c0ffd7e506d90e11b011da42b1bd8d2393ec59cc926cef33c2121da3f48dfd59925138 signin:67:25
Payload: QU1BWk9OAujsm4qUnrdU4wWs++Ugfx6+dScsGBRrylfOOZkowP/X5QbZDhGwEdpCsb2NI5PsWcySbO8zwhIdo/SN/VmSUTg= signin:137:37
XHRGEThttp://127.0.0.1:8000/Shenzen/actsignin/?encrypted_string=QU1BWk9OAujsm4qUnrdU4wWs%2B%2BUgfx6%2BdScsGBRrylfOOZkowP%2FX5QbZDhGwEdpCsb2NI5PsWcySbO8zwhIdo%2FSN%2FVmSUTg%3D
[HTTP/1.1 500 Internal Server Error 24ms]

AES failed.

Теперь я декодирую его в python следующим образом:

encrypted_string = request.GET['encrypted_string']

print("Encrypted string decoded: ",base64.b64decode(encrypted_string)) #Line 2
print("----")
sha256_key = SHA256.new(data=bytes(key))
cipher = AES.new(sha256_key.digest(),AES.MODE_CBC)
print(cipher.decrypt(base64.b64decode(encrypted_string)))
[12/Oct/2019 18:39:41] "GET /Shenzen/dh/?step=calcval&level1=37 HTTP/1.1" 200 16
Encrypted string decoded:  b"AMAZON\x02\xcb0\xb5~ \xbf<\x96\x16\x0eJY@\x88\xfe\x94\xc28\xf2j\x19n\x8f\x8d\xdb\xb6yc\x89-L\x93\xa3\x9f\xc3i\xd5\xf4e4'|\xa1\x1f\x9d\xb9k\x95O\xb9<\xc3\xa0\xd7\xa6B^\x85+SSToe"
----
Internal Server Error: /Shenzen/actsignin/
Traceback (most recent call last):
  File "/home/tarunmaganti/Documents/AbhiramSlavery/ProjectLogin/hell/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/home/tarunmaganti/Documents/AbhiramSlavery/ProjectLogin/hell/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/tarunmaganti/Documents/AbhiramSlavery/ProjectLogin/hell/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/tarunmaganti/Documents/AbhiramSlavery/ProjectLogin/UrbanHell/Shenzen/views.py", line 67, in actsignin
    print(cipher.decrypt(base64.b64decode(encrypted_string)))
  File "/home/tarunmaganti/Documents/AbhiramSlavery/ProjectLogin/hell/lib/python3.6/site-packages/Crypto/Cipher/_mode_cbc.py", line 246, in decrypt
    raise ValueError("Data must be padded to %d byte boundary in CBC mode" % self.block_size)
ValueError: Data must be padded to 16 byte boundary in CBC mode
[12/Oct/2019 18:39:44] "GET /Shenzen/actsignin/?encrypted_string=QU1BWk9OAsswtX4gvzyWFg5KWUCI%2FpTCOPJqGW6Pjdu2eWOJLUyTo5%2FDadX0ZTQnfKEfnblrlU%2B5PMOg16ZCXoUrU1NUb2U%3D HTTP/1.1" 500 17651put

Я ожидаю, что выходные данные строки 1 и строки 2 будут равны, но вот что я получаю:

Javascript Bytes before Base64 encoding: 414d415a4f4e02e8ec9b8a949eb754e305acfbe5207f1ebe75272c18146bca57ce399928c0ffd7e506d90e11b011da42b1bd8d2393ec59cc926cef33c2121da3f48dfd59925138 signin:67:25

Python Encrypted string decoded: b"AMAZON\x02\xcb0\xb5~ \xbf<\x96\x16\x0eJY@\x88\xfe\x94\xc28\xf2j\x19n\x8f\x8d\xdb\xb6yc\x89-L\x93\xa3\x9f\xc3i\xd5\xf4e4'|\xa1\x1f\x9d\xb9k\x95O\xb9<\xc3\xa0\xd7\xa6B^\x85+SSToe"

Можете ли вы объяснить, что происходит? Как получить ту же строку, что и JavaScript? или Как преобразовать строку в Python в расшифрованные (?) данные.

1 Ответ

0 голосов
/ 13 октября 2019
  • В JavaScript-коде заголовок (в виде шестнадцатеричной строки: 414d415a4f4e02), случайно сгенерированный IV и зашифрованный текст объединяются и кодируются в Base64. В Python-коде объединенные данные декодируются в Base64. Однако разбиение на заголовок, IV и зашифрованный текст не выполняется. Поэтому зашифрованный текст и IV отсутствуют для расшифровки. Вместо зашифрованного текста сцепленные данные используются для расшифровки, что неверно. И экземпляр AES создается без IV, что также неверно.

  • На стороне JavaScript объединенные данные до кодировки Base64 приведены вшестнадцатеричное представление:

    414d415a4f4e02e8ec9b8a949eb754e305acfbe5207f1ebe75272c18146bca57ce399928c0ffd7e506d90e11b011da42b1bd8d2393ec59cc926cef33c2121da3f48dfd59925138 
    

    На стороне Python объединенные данные после декодирования Base64 представлены в шестнадцатеричном представлении:

    414d415a4f4e02cb30b57e20bf3c96160e4a594088fe94c238f26a196e8f8ddbb67963892d4c93a39fc369d5f46534277ca11f9db96b954fb93cc3a0d7a6425e852b5353546f65
    

    данные, очевидно, различаются, начиная с IV (т.е. начиная с 8-го байта включительно). JavaScript-код генерирует случайный IV с каждым прогоном, так что зашифрованный текст также отличается для каждого прогона. Скорее всего, оба данных получены из различных прогонов, потому что начало одинаковое, а отклонение начинается с части, которая генерируется случайным образом в каждом прогоне. В противном случае данные должны были бы быть изменены в другом месте (и, вероятно, не по опубликованному коду) таким характерным способом.

  • Также может быть проблема с заполнением. CryptoJS по умолчанию использует заполнение PKCS7. Напротив, PyCrypto / PyCryptodome не использует заполнение по умолчанию (т.е. пользователь должен заполнять вручную), поэтому заполнение на стороне Python не может быть удалено автоматически во время расшифровки.

...