Шифрование с помощью Crypto JS, дешифрование с помощью PyCrypto (настройка Crypto JS на значения по умолчанию PyCrypto) - PullRequest
2 голосов
/ 10 января 2020

Я пытаюсь расшифровать на Crypto JS и зашифровать в PyCrypto.

Я видел этот отличный ответ, который работает как шарм, единственная проблема в том, что он настраивает PyCrypto для работы с Crypto JS, и я предпочитаю определять правила того, как я ожидаю ввод, и вносить как можно меньше корректировок в PyCrypto с его значениями по умолчанию.

Я подумал попросить отправить iv и с Zero Padding.

Я написал следующее в JS (ES6):

  const iv = CryptoJS.enc.Hex.parse("1234567889012345");
  const key = 'aR1h7EefwlPNVkvTHwfs6w=='
  const encrypted = AES.encrypt(
    password,
    key,
    {
      iv,
      padding: CryptoJS.pad.NoPadding
    }
  );

  const payload = {password: encrypted, iv: iv};
  // make HTTPS POST call

Python:

def decrypt_from_cryptoJS(encrypted, iv):
    key = "aR1h7EefwlPNVkvTHwfs6w==".encode()
    aes = AES.new(key.encode(), AES.MODE_CBC, iv)
    encrypted = aes.decrypt(base64.b64decode(encrypted)))

Однако я получаю ValueError: raise TypeError("Object type %s cannot be passed to C code" % type(data))

Если я попытаюсь создать VI с помощью: CryptoJS.lib.WordArray.random(16) и отправить его с помощью метода toString () JS, я получу:

Incorrect IV length (it must be 16 bytes long)

для запуска AES

Как я могу расшифровать в Crypto JS с минимальными настройками кода в PyCrypto? Я не уверен, что я даже иду по правильному пути ..

1 Ответ

1 голос
/ 11 января 2020
  • На стороне Crypto JS ключ и IV должны передаваться как WordArray -объекты [1] . Crypto JS предоставляет кодеры для преобразования строк в WordArray -объекты и наоборот [2] . Если ключ передается как строка, он обрабатывается как фраза-пароль, и из него выводятся фактический ключ и IV (в указанном ответе алгоритм, используемый для этого, реализован на Python -объекте [3] ).

  • Ключ закодирован Base64 и имеет длину 16 байтов после декодирования Base64, поэтому используется AES-128. Для преобразования в WordArray необходимо использовать Base64-кодировщик на стороне Crypto JS. На стороне Python ключ должен быть декодирован Base64 (который все еще должен быть добавлен к опубликованному коду). Примечание. В опубликованном коде ключ обрабатывается как строка Utf8, поэтому длина ключа составляет 24 байта, и используется AES-192. Если это предназначено , кодер Utf8 должен использоваться на стороне Crypto JS вместо кодера Base64. На стороне Python декодирование ключа с помощью Base64 тогда не требуется.

  • IV, используемый для шифрования, также должен использоваться для дешифрования. Как правило, IV генерируется на стороне шифрования в виде случайной последовательности байтов. Поскольку IV не является секретным, он обычно помещается перед зашифрованным текстом, и объединенные данные отправляются получателю, который разделяет обе части. На стороне Crypto JS конкатенация легко выполняется с помощью WordArray#concat. На стороне Python разделение выполняется путем нарезки (что еще необходимо добавить к опубликованному коду).

  • AES / CB C ожидает открытый текст, длина которого кратна целому размеру блока (16 байтов). Если открытый текст имеет другую длину, необходимо использовать отступы. Crypto JS использует CB C -mode и PKCS7-padding по умолчанию, так что ни один из них не должен быть явно указан [4] . PKCS7-заполнение более надежно, чем Zero-padding [5] . Однако, если вместо этого следует использовать нулевое заполнение (что мне не ясно из вопроса), оно должно быть указано явно с помощью padding: CryptoJS.pad.ZeroPadding. PyCrypto не удаляет заполнение автоматически, то есть это должно быть сделано вручную (что все еще необходимо добавить к опубликованному коду). Обратите внимание, что в отличие от PyCrypto, PyCryptodome поддерживает заполнение [6] .

Возможный JavaScript -код:

var password = "The quick brown fox jumps over the lazy dog";
var iv = CryptoJS.lib.WordArray.random(16);                         // Generate a random 16 bytes IV
var key = CryptoJS.enc.Base64.parse('aR1h7EefwlPNVkvTHwfs6w==');    // Interpret key as Base64 encoded

var encrypted = CryptoJS.AES.encrypt(password, key, {iv: iv});      // Use CBC-mode and PKCS7-padding
var joinedData = iv.clone().concat(encrypted.ciphertext);           // Concat IV and Ciphertext    
var joinedDataB64 = CryptoJS.enc.Base64.stringify(joinedData);
console.log(joinedDataB64.replace(/(.{64})/g, "$1\n"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script>

Соответствующий Python -код может быть:

from Crypto.Cipher import AES
import base64

def decrypt_from_cryptoJS(encrypted, iv):
  key = base64.b64decode("aR1h7EefwlPNVkvTHwfs6w==")                # Interpret key as Base64 encoded   
  aes = AES.new(key, AES.MODE_CBC, iv)                              # Use CBC-mode
  encrypted = aes.decrypt(encrypted)                                # Remove Base64 decoding
  return encrypted

def unpadPkcs7(data):
  return data[:-ord(data[-1])]
  #return data[:-data[-1]] #Python 3

joinedDataB64 = "sbYEr73hZVKviuQ2rt5RcJ5ugpn7XBLTtZIKKk5JjTXmGojFkAS+dK0D8NNAET6bC/Ai4sx+El5Bzu4igT1S9g=="
joinedData = base64.b64decode(joinedDataB64)
iv = joinedData[:16]                                                # Determine IV from concatenated data
encrypted = joinedData[16:]                                         # Determine ciphertext from concatenated data

decrypted = unpadPkcs7(decrypt_from_cryptoJS(encrypted, iv))        # Decrypt and remove PKCS7-padding manually
print decrypted
#print(decrypted) #Python 3
...