java - जावा का उपयोग करके CryptoJS से एन्क्रिप्टेड AES-256 स्ट्रिंग को डिक्रिप्ट कैसे करें?



encryption cryptography (1)

मेरे पास CryptoJS से पासफ़्रेज़ के साथ एन्क्रिप्टेड AES-256 स्ट्रिंग है। मुझे इसे जावा में डिक्रिप्ट करने की आवश्यकता है, लेकिन यह पता नहीं कर सकता कि यह कैसे करना है। ऐसा लगता है कि आपको डिक्रिप्ट करने के लिए IV, कुंजी और नमक की आवश्यकता है, और CryptoJS मुख्यपृष्ठ के रूप में, एन्क्रिप्ट किए गए डेटा में पहले से ही सभी शामिल हैं, और CryptoJS किसी भी तरह एन्क्रिप्टेड इनपुट से बाहर पार्स कर सकते हैं।

कोई जानता है कि उसे कैसे करना है? मैंने CryptoJS - Java एन्क्रिप्ट / डिक्रिप्ट के बारे में बहुत सारे उदाहरण देखे हैं, लेकिन उनमें से ज्यादातर हार्डकोडेड IV / कुंजी का उपयोग करते हैं, या केवल cryptoJS की तरफ से Java साइड में IV / key भेजते हैं। मेरे पास केवल एक पासफ़्रेज़ है, जैसे यह साइट क्या करती है!


जब कोई संदेश इस तरह से एन्क्रिप्ट किया जाता है:

CryptoJS.AES.encrypt("message", "passphrase")

पासवर्ड-आधारित दृष्टिकोण का उपयोग किया जाता है। इसके लिए CryptoJS एक नया नमक उत्पन्न करता है और कुंजी और IV प्राप्त करने के लिए पासफ़्रेज़ के साथ मिलकर इस नमक का उपयोग करता है (मैंने इस प्रश्न के लिए एक व्युत्पत्ति फ़ंक्शन लिखा है)।
सिफरटेक्स्ट के निर्माण के बाद एक विशेष ओपनएसएसएल फॉर्मेटर का उपयोग किया जाता है, जिसमें इस्तेमाल किए गए नमक सहित सिफरटेक्स को एनकोड किया जाता है:

var wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext);

बाइट सरणी को बाहर निकालने के लिए आपको बेस 64 एनकोडेड स्ट्रिंग को डीकोड करना होगा। तब आप जांच सकते हैं कि क्या शीर्ष लेख मेल खाता है:

byte[] ctBytes = Base64.getDecoder().decode(ciphertext.getBytes("UTF-8"));
System.out.println("Is salted: " + new String(Arrays.copyOf(ctBytes, 8)).equals("Salted__"));

उसके बाद आप इससे उबरने वाला नमक और साइफरटेक्स्ट प्राप्त कर सकते हैं:

byte[] saltBytes = Arrays.copyOfRange(ctBytes, 8, 16);
byte[] ciphertextBytes = Arrays.copyOfRange(ctBytes, 16, ctBytes.length);

कुंजी + IV प्राप्त करें:

byte[] key = new byte[keySize/8];
byte[] iv = new byte[ivSize/8];
EvpKDF(password.getBytes("UTF-8"), keySize, ivSize, saltBytes, key, iv);

और सिफरटेक्स्ट को डिक्रिप्ट करें:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"),
        new IvParameterSpec(iv));
byte[] recoveredPlaintextBytes = cipher.doFinal(ciphertextBytes);
String recoveredPlaintext = new String(recoveredPlaintextBytes);

पूरा पूरा कोड:

public static void main(String[] args) throws UnsupportedEncodingException, GeneralSecurityException {
    String ciphertext = "U2FsdGVkX1+0m/gle/XQX1shjnpveUrl1fO3oOlurPMlTks6+oQlEPfOrucihzEz";
    String plaintext = "This is some example plaintext";
    String password = "This is a very strong password";
    int keySize = 256;
    int ivSize = 128;

    // var wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext);
    byte[] ctBytes = Base64.getDecoder().decode(ciphertext.getBytes("UTF-8"));
    System.out.println("Is salted: " + Arrays.equals(Arrays.copyOf(ctBytes, 8), new byte[]{0x53, 0x61, 0x6c, 0x74, 0x65, 0x64, 0x5f, 0x5f}));
    System.out.println("Is salted: " + new String(Arrays.copyOf(ctBytes, 8)).equals("Salted__"));

    byte[] saltBytes = Arrays.copyOfRange(ctBytes, 8, 16);
    System.out.println("Salt matches: " + Arrays.equals(saltBytes, hexStringToByteArray("b49bf8257bf5d05f")));

    byte[] ciphertextBytes = Arrays.copyOfRange(ctBytes, 16, ctBytes.length);
    System.out.println("CT matches: " + Arrays.equals(ciphertextBytes, hexStringToByteArray("5b218e7a6f794ae5d5f3b7a0e96eacf3254e4b3afa842510f7ceaee722873133")));

    byte[] key = new byte[keySize/8];
    byte[] iv = new byte[ivSize/8];
    EvpKDF(password.getBytes("UTF-8"), keySize, ivSize, saltBytes, key, iv);

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
    byte[] recoveredPlaintextBytes = cipher.doFinal(ciphertextBytes);
    String recoveredPlaintext = new String(recoveredPlaintextBytes);

    System.out.println("Recovered Plaintext: " + recoveredPlaintext);
    System.out.println("Expected Plaintext: " + plaintext);
}

public static byte[] EvpKDF(byte[] password, int keySize, int ivSize, byte[] salt, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException {
    return EvpKDF(password, keySize, ivSize, salt, 1, "MD5", resultKey, resultIv);
}

public static byte[] EvpKDF(byte[] password, int keySize, int ivSize, byte[] salt, int iterations, String hashAlgorithm, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException {
    keySize = keySize / 32;
    ivSize = ivSize / 32;
    int targetKeySize = keySize + ivSize;
    byte[] derivedBytes = new byte[targetKeySize * 4];
    int numberOfDerivedWords = 0;
    byte[] block = null;
    MessageDigest hasher = MessageDigest.getInstance(hashAlgorithm);
    while (numberOfDerivedWords < targetKeySize) {
        if (block != null) {
            hasher.update(block);
        }
        hasher.update(password);
        block = hasher.digest(salt);
        hasher.reset();

        // Iterations
        for (int i = 1; i < iterations; i++) {
            block = hasher.digest(block);
            hasher.reset();
        }

        System.arraycopy(block, 0, derivedBytes, numberOfDerivedWords * 4,
                Math.min(block.length, (targetKeySize - numberOfDerivedWords) * 4));

        numberOfDerivedWords += block.length/4;
    }

    System.arraycopy(derivedBytes, 0, resultKey, 0, keySize * 4);
    System.arraycopy(derivedBytes, keySize * 4, resultIv, 0, ivSize * 4);

    return derivedBytes; // key + iv
}

/**
 * Copied from https://.com/a/140861
 * */
public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

जावास्क्रिप्ट कोड:

var pw = "This is a very strong password";
var pt = "This is some example plaintext";
var encrypted = CryptoJS.AES.encrypt(pt, pw);
encrypted.toString(); // U2FsdGVkX1+0m/gle/XQX1shjnpveUrl1fO3oOlurPMlTks6+oQlEPfOrucihzEz
encrypted.salt.toString(); // b49bf8257bf5d05f
encrypted.ciphertext.toString(); // 5b218e7a6f794ae5d5f3b7a0e96eacf3254e4b3afa842510f7ceaee722873133





cryptojs