Как декодировать данные, зашифрованные с помощью AES-256 в режиме CBC и заполнения PKCS7?

#javascript #java #cryptojs

#javascript #java #cryptojs

Вопрос:

Мы используем приведенный ниже Java-код для расшифровки данных, зашифрованных с использованием AES-256 в режиме CBC и заполнения PKCS7.

Java-код:

 import javax.crypto.spec.SecretKeySpec;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import java.security.*;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;


public class AES256 {

    private static byte[] initVector = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

    public String decrypt (String encryptedDataBase64, String keyBase64)
    {
       try {
           Security.setProperty("crypto.policy", "unlimited");
           IvParameterSpec ivSpec = new IvParameterSpec(initVector);  // Get the init vector

           // Get the Base64-encoded key
           byte[] key = Base64.decodeBase64(keyBase64.getBytes("UTF-8"));
           Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");  // AES / CBC / PKCS5 padding
           SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
           cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
           byte[] encryptedData = Base64.decodeBase64(encryptedDataBase64.getBytes("UTF-8"));
           byte[] decryptedData = cipher.doFinal(encryptedData);

           return new String(decryptedData);
       }
       catch (Exception e) {
           logger.error("AES256 Decrypt: Decryption exception: "  e.getMessage());
           return null;
       }
    }
}
  

Теперь нам нужно преобразовать эту логику дешифрования в Javascript, поскольку наше приложение отправляет зашифрованные данные в заголовках при запросе index.html с сервера. Я попытался расшифровать с помощью Crypto.js но я получаю декодированную строку как пустую. Ниже приведен код Javascript, который я пытался использовать.

 var key = CryptoJS.enc.Base64.parse(keyBase64);
var data = CryptoJS.enc.Base64.parse(encryptedDataBase64);
var dec_data = CryptoJS.AES.decrypt(data, key);
  

dec_data отображается как пустой.

введите описание изображения здесь

Я попробовал это после прочтения некоторых вопросов stack over flow. Может кто-нибудь, пожалуйста, сообщить мне, есть ли какая-либо ошибка в коде.

Ответ №1:

К сожалению, вы не предоставили никаких образцов данных для тестирования в вашей среде, поэтому я настраиваю свои собственные значения. Используя эти значения:

 ciphertext = rjygE0TjIqiQ4ETnpszoieRWzaSD 9oINf1c748VcL/3zD5AazSFomx4paeanihz
keyBase64 = MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=
ivBase =  AAAAAAAAAAAAAAAAAAAAAA==
  

Я получаю этот результат дешифрования на Java:

 The quick brown fox jumps over the lazy dog
  

На стороне Javascript я получаю те же результаты с моим кодом:

 decrypted (str): The quick brown fox jumps over the lazy dog
  

Живой тест можно выполнить здесь — Java:https://paiza.io/projects/e/dHG73CRgJojOOfLxtvJjtg и Javascript: https://playcode.io/672463.

Пожалуйста, обратите внимание, что мой код не имеет обработки исключений и предназначен только для образовательных целей. Кроме того, ваш код НЕБЕЗОПАСЕН, поскольку он использует статический (фиксированный) ключ и вектор инициализации.

Код Java (немного изменен, поскольку я использую Java 11, встроенный в кодировщик Base64):

 import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.Security;
import java.util.Base64;

public class Main {

    private static byte[] initVector = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

    public static void main(String[] args) throws UnsupportedEncodingException {
        System.out.println("How to decode data encrypted using AES-256 in CBC mode and PKCS7 padding");
        String plaintext = "The quick brown fox jumps over the lazy dog";
        byte[] key = "12345678901234567890123456789012".getBytes("UTF-8");
        String keyBase64 = Base64.getEncoder().encodeToString(key);
        System.out.println("keyBase64: "   keyBase64);
        String ivBase64 = Base64.getEncoder().encodeToString(initVector);
        System.out.println("initVector: "   ivBase64);
        String ciphertext = "rjygE0TjIqiQ4ETnpszoieRWzaSD 9oINf1c748VcL/3zD5AazSFomx4paeanihz";
        System.out.println("ciphertext: "   ciphertext);
        String decryptedtext = decrypt(ciphertext, Base64.getEncoder().encodeToString(key));
        System.out.println("decryptedtext: "   decryptedtext);
    }

    public static String decrypt (String encryptedDataBase64, String keyBase64)
    {
        try {
            Security.setProperty("crypto.policy", "unlimited");
            IvParameterSpec ivSpec = new IvParameterSpec(initVector);  // Get the init vector
            // Get the Base64-encoded key
            byte[] key = Base64.getDecoder().decode(keyBase64.getBytes("UTF-8"));
            //byte[] key = Base64.decodeBase64(keyBase64.getBytes("UTF-8"));
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");  // AES / CBC / PKCS5 padding
            SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
            byte[] encryptedData = Base64.getDecoder().decode(encryptedDataBase64.getBytes("UTF-8"));
            //byte[] encryptedData = Base64.decodeBase64(encryptedDataBase64.getBytes("UTF-8"));
            byte[] decryptedData = cipher.doFinal(encryptedData);
            return new String(decryptedData);
        }
        catch (Exception e) {
            System.out.println("AES256 Decrypt: Decryption exception: "  e.getMessage());
            //logger.error("AES256 Decrypt: Decryption exception: "  e.getMessage());
            return null;
        }
    }
}
  

Код Javascript:

 let keyBase64 = 'MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=';
let ivBase64 = 'AAAAAAAAAAAAAAAAAAAAAA==';
let iv = CryptoJS.enc.Base64.parse(ivBase64);
let secret_key = CryptoJS.enc.Base64.parse(keyBase64);
ciphertext = 'rjygE0TjIqiQ4ETnpszoieRWzaSD 9oINf1c748VcL/3zD5AazSFomx4paeanihz';
console.log('ciphertext: ', ciphertext);
var decrypted = CryptoJS.AES.decrypt(ciphertext, secret_key,{
  iv: iv,
  padding: CryptoJS.pad.Pkcs7,
  mode: CryptoJS.mode.CBC,
});
console.log('decrypted (str): ', CryptoJS.enc.Utf8.stringify(decrypted).toString());
  

Комментарии:

1. Большое спасибо, Майкл. Могу ли я узнать, что такое ivBase64? Потому что мы не используем это в коде Java. Мы используем initVector = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

2. Код работает с моим ключом и данными. Я просто хочу понять, почему ivBase64 инициализируется ‘ААААААААААААААААААААА==’.

3. Мне было просто лень найти способ использовать initvector с 16 x0. Как вы видите в Java-коде, ваш «обнуленный» iv был просто закодирован как строка Base64. Я использовал эту строку в качестве инициализации на стороне Javascript, поэтому я был уверен, что использую это значение (через Base64-decoding). Будут другие методы для непосредственного создания переменной с «нулевым» значением длиной 16 байт 🙂