Шифровщики Spring 4 против CryptoJs

Я обрабатываю шифрование с использованием класса Spring 4 Encryptors следующим образом:

String salt = KeyGenerators.string().generateKey();
TextEncryptor textEncryptor = Encryptors.text("MY_SECRET_KEY", salt);
textEncryptor.encrypt(json);

В клиентском javascript я пытаюсь расшифровать с помощью CryptoJS

var uncrypted = CryptoJS.AES.decrypt(serverEncrypted, "MY_SECRET_KEY");
$("#encrypted-data").val(uncrypted);

Я предполагаю, что мне нужно вернуть часть шестнадцатеричной кодировки, но я не понимаю, что нужно сделать.

Пробовал синтаксический анализ перед расшифровкой, но ничего хорошего из этого не вышло.

CryptoJS.enc.Hex.parse(serverEncrypted)

В документации Spring говорится, что текстовый метод будет шифровать шестнадцатеричное значение в «стандартном» методе шифрования, который представляет собой 256-битный AES с использованием PKCS # 5 PBKDF2.

[Ход поиска]

Вот как Spring создает свой ключ:

PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 1024, 256);
SecretKey secretKey = newSecretKey("PBKDF2WithHmacSHA1", keySpec);
SecretKeySpec secretKey = new SecretKeySpec(secretKey.getEncoded(), "AES");

И шифрование:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));

iv — это защищенный случайный массив размером 8 байт, который добавляется к зашифрованным данным.


person P. Lalonde    schedule 28.04.2015    source источник
comment
обратите внимание, что все строки JS имеют юникод...   -  person dandavis    schedule 28.04.2015
comment
Итак, что это значит?   -  person P. Lalonde    schedule 28.04.2015
comment
это означает, что результат шифрования строки, отличной от Юникода, будет отличаться от результата кодирования той же строки в формате, отличном от Юникода. я заметил, что это большая проблема совместимости при использовании бэкэнда, отличного от js, и внешнего интерфейса js. возможно, ваша строка Java уже является Unicode, и в этом случае я потратил ваше серое вещество впустую...   -  person dandavis    schedule 28.04.2015
comment
Должен ли я использовать другой метод кодирования?   -  person P. Lalonde    schedule 28.04.2015
comment
вам нужно поиграть с несколькими, пока не найдете тот, который дает одинаковый результат на каждом конце. Я нашел совпадение для php + js один раз для AES, но я не искал java. я уверен, что что-то там может это сделать, и если вы можете принудительно использовать юникод или преобразовать в массив кодов символов, тот, который у вас есть, может работать.   -  person dandavis    schedule 28.04.2015
comment
Эта документация совершенно бесполезна в этот случай. Если вы можете ответить на следующие вопросы, то это легко реализовать в CryptoJS: 1. Сколько итераций используется для получения ключа с помощью PBKDF2 с использованием предоставленного пароля и соли? 2. В документации написано, что генерируется дополнительный случайный IV. Куда это идет? Он добавлен/добавлен к зашифрованному тексту или вам нужно как-то запросить его? 3. Какой режим работы? Я подозреваю, что это общий анализ крови из-за капельницы.   -  person Artjom B.    schedule 28.04.2015
comment
Итак, я думаю, мне не следует использовать реализацию Spring?   -  person P. Lalonde    schedule 28.04.2015
comment
@P.Lalonde P.Lalonde Я не вижу причин, по которым ты должен это делать. Java предоставляет реализацию PBKDF2 и реализацию AES (Cipher). Вы даже можете использовать PBE, который сочетает в себе оба.   -  person Artjom B.    schedule 28.04.2015
comment
Я обновил свое описание, основываясь на своих исследованиях, я должен иметь возможность использовать Spring, так как мой механизм шифрования использует UTF-8, и, похоже, он выполняет все предлагаемые вещи, которые я нахожу в Google. Мне просто нужно выяснить, как отменить процесс с помощью CryptoJS.   -  person P. Lalonde    schedule 29.04.2015


Ответы (1)


После некоторых исследований я нашел решение, как объединить Spring 4 Encryptors и CryptoJS. Spring использует в своих шифраторах 256-битный AES с использованием PKCS #5 PBKDF2, как указано в документации — Документы Spring Crypto с размером IV, равным 16 байтам. Эта информация имеет решающее значение при создании кода в CryptoJS. Еще одна вещь, которую следует помнить, это использование одной и той же соли и iv на протяжении всего процесса шифрования/дешифрования одного сообщения. Вооружившись этой информацией, мы можем начать кодирование (в этом примере я шифрую сообщение в CryptoJS и расшифровываю его в Spring): CryptoJS

const keySize = 256;
const ivSize = 128;
const iterations = 1024;

function encrypt(msg, pass) {
    const salt = CryptoJS.lib.WordArray.random(128 / 8);

    const key = CryptoJS.PBKDF2(pass, salt, {
        keySize: keySize / 32,
        iterations: iterations
    });

    const iv = CryptoJS.lib.WordArray.random(ivSize / 8);

    const encrypted = CryptoJS.AES.encrypt(msg, key, {
        iv: iv,
        padding: CryptoJS.pad.Pkcs7,
        mode: CryptoJS.mode.CBC

    });

    // salt, iv will be hex 32 in length
    // append them to the ciphertext for use  in decryption
    return salt.toString() + iv.toString() + encrypted.ciphertext.toString();
}

Как видите, результатом всего шифрования является конкатенация salt + iv + encryptedMessage. Что также важно, в коде Spring я обнаружил, что ключ создается с длиной 256 и за 1024 итерации:

PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), Hex.decode(salt), 1024, 256);

Теперь этот подготовленный результат мы можем взять в наш код Spring и расшифровать:

private static String decrypt(String encryptedData, String keyStr) {
        final String salt = encryptedData.substring(0, 32);
        final String encryptedPart = encryptedData.substring(32);
        final TextEncryptor textEncryptor = Encryptors.text(keyStr, salt);
        return textEncryptor.decrypt(encryptedPart);
}

Шифровальщик Spring AES сам вырежет часть с помощью IV и будет использовать ее для процесса расшифровки. Конечно, все должно быть в шестнадцатеричном кодировании, но именно так работает Spring TextEncryptpors.

Обратная процедура (зашифровать в Spring и расшифровать в CryptoJS) будет практически такой же. В CryptoJS нам нужно извлечь salt и iv:

const keySize = 256;

function decrypt (encryptedMessage, pass) {
  var salt = CryptoJS.enc.Hex.parse(encryptedMessage.substr(0, 32));
  var iv = CryptoJS.enc.Hex.parse(encryptedMessage.substr(32, 32))
  var encrypted = encryptedMessage.substring(64);

  var key = CryptoJS.PBKDF2(pass, salt, {
      keySize: keySize / 32,
      iterations: iterations
    });

  var decrypted = CryptoJS.AES.decrypt(encrypted, key, { 
    iv: iv, 
    padding: CryptoJS.pad.Pkcs7,
    mode: CryptoJS.mode.CBC

  })
  return decrypted;
}

Надеюсь кому-нибудь поможет :)

Ваше здоровье!

person Kamil Czyznielewski    schedule 13.04.2017