Шифрование в Javascript и дешифрование в Java для Zip-файла - PullRequest
1 голос
/ 02 июня 2019

Я хочу зашифровать локальный zip-файл в javascript, а затем расшифровать его в java.

Я использовал код по этой ссылке https://www.devglan.com/corejava/aes-encryption-javascript-and-decryption-in-java

зашифровать в JavaScript

var AesUtil = function (keySize, iterationCount) {
    this.keySize = keySize / 32;
    this.iterationCount = iterationCount;
};

AesUtil.prototype.generateKey = function (salt, passPhrase) {
    var key = CryptoJS.PBKDF2(
        passPhrase,
        CryptoJS.enc.Hex.parse(salt),
        {keySize: this.keySize, iterations: this.iterationCount});
    return key;
};

AesUtil.prototype.encrypt = function (salt, iv, passPhrase, plainText) {
    var key = this.generateKey(salt, passPhrase);
    var encrypted = CryptoJS.AES.encrypt(
        plainText,
        key,
        {iv: CryptoJS.enc.Hex.parse(iv)});
    return encrypted.ciphertext.toString(CryptoJS.enc.Base64);
};

AesUtil.prototype.decrypt = function (salt, iv, passPhrase, cipherText) {
    var key = this.generateKey(salt, passPhrase);
    var cipherParams = CryptoJS.lib.CipherParams.create({
        ciphertext: CryptoJS.enc.Base64.parse(cipherText)
    });
    var decrypted = CryptoJS.AES.decrypt(
        cipherParams,
        key,
        {iv: CryptoJS.enc.Hex.parse(iv)});
    return decrypted.toString(CryptoJS.enc.Utf8);


};

var CryptoJS = require('crypto-js'),
    fs = require('fs');

var data = fs.readFileSync("C:\\<my_path>\\scripts.zip");

var passPhrase = "123456789123456789";
var iv = "a145525c53eafb0258999612b13d9d3e"; //CryptoJS.lib.WordArray.random(128 / 8).toString(CryptoJS.enc.Hex);
var salt = "ca70e17a698096cfb42047926713dd62";// CryptoJS.lib.WordArray.random(128 / 8).toString(CryptoJS.enc.Hex);

var aesUtil = new AesUtil(128, 1000);
var ciphertext = aesUtil.encrypt(salt, iv, passPhrase, data.toString());

fs.writeFileSync('C:/Output.encrypted', ciphertext);

и расшифровка в Java такая: AesUtil.java

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

public class AesUtil {
    private final int keySize;
    private final int iterationCount;
    private final Cipher cipher;

    public AesUtil(int keySize, int iterationCount) {
        this.keySize = keySize;
        this.iterationCount = iterationCount;
        try {
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        }
        catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw fail(e);
        }
    }

    public String decrypt(String salt, String iv, String passphrase, String ciphertext) {
        try {
            SecretKey key = generateKey(salt, passphrase);
            byte[] decrypted = doFinal(Cipher.DECRYPT_MODE, key, iv, base64(ciphertext));
            return new String(decrypted, "UTF-8");
        }
        catch (UnsupportedEncodingException e) {
            return null;
        }catch (Exception e){
            return null;
        }
    }

    public byte[] doFinal(int encryptMode, SecretKey key, String iv, byte[] bytes) {
        try {
            cipher.init(encryptMode, key, new IvParameterSpec(hex(iv)));
            return cipher.doFinal(bytes);
        }
        catch (InvalidKeyException
                | InvalidAlgorithmParameterException
                | IllegalBlockSizeException
                | BadPaddingException e) {
            return null;
        }
    }

    public SecretKey generateKey(String salt, String passphrase) {
        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), hex(salt), iterationCount, keySize);
            SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
            return key;
        }
        catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            return null;
        }
    }

    public static byte[] base64(String str) {
        return Base64.decodeBase64(str);
    }

    public static byte[] hex(String str) {
        try {
            return Hex.decodeHex(str.toCharArray());
        }
        catch (DecoderException e) {
            throw new IllegalStateException(e);
        }
    }

    private IllegalStateException fail(Exception e) {
        return null;
    }

}

Основной метод:

private static void mainScan(String[] args) {
        try {
            String keyString = "123456789123456789";


            int keySize = 128;
            int iterationCount = 1000;
            String iv = "a145525c53eafb0258999612b13d9d3e";
            String salt = "ca70e17a698096cfb42047926713dd62";
            AesUtil aesUtil = new AesUtil(keySize, iterationCount);


            String encryptedPath = "C:/Output.encrypted";
            String decryptedPath = "C:/Output.zip";


            String fileString = new String(Files.readAllBytes(Paths.get(encryptedPath)));
            String decryptedText = aesUtil.decrypt(salt, iv, keyString, fileString);

            FileUtils.writeStringToFile(new File(decryptedPath), decryptedText);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Но, тем не менее, после расшифровки я получил zip-файл, который больше по размеру от исходного zip и не является действительным zip-файлом.

  • Примечание: этот код работал, когда текст был только String и не получал строку из / в файл

1 Ответ

2 голосов
/ 02 июня 2019

Обработка двоичного содержимого, такого как Zip-файлы, как если бы они были строками, обычно является большой ошибкой в ​​большинстве языков. На стороне Javascript CryptoJS ожидает, что произвольные байтовые последовательности будут предоставлены как CryptoJS.lib.WordArray аргументы.

Итак, вместо

var ciphertext = aesUtil.encrypt(salt, iv, passPhrase, data.toString());

у вас должно быть

var ciphertext = aesUtil.encrypt(salt, iv, passPhrase, CryptoJS.lib.WordArray.create(data));

На стороне Java измените функцию decrypt, чтобы она возвращала byte[].

public byte[] decrypt(String salt, String iv, String passphrase, String ciphertext) {
    SecretKey key = generateKey(salt, passphrase);
    byte[] decrypted = doFinal(Cipher.DECRYPT_MODE, key, iv, base64(ciphertext));
    return decrypted;
}

А в main измените код так, чтобы он выглядел как

String fileString = new String(Files.readAllBytes(Paths.get(encryptedPath)));
byte [] decryptedText = aesUtil.decrypt(salt, iv, keyString, fileString);
Files.write(Paths.get(decryptedPath), decryptedText);
...