0

I am doing encryption in Java and decrypting it with JavaScript using AES-256/CBC, but actually this is the scenario: while encryption of .pdf, .jpg, in other words, other than text files Java produces the encrypted file with roughly the same bytes but in case of JavaScript(CryptoJS) it outputs ~1.5 times of the original file size, which is why I think for the decryption with CryptoJS it does not expect the small encrypted file size from Java. I have given the code from both sides i.e, encryption at Java side, decryption at JavaScript side.

Problem:

I have a requirement of encrypting any file with Java and decrypting the same file with JavaScript. Kindly refer to the code as given below and this example.

Java: Encryption

  1. key generation:

     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
     SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
     KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), hex(salt), iterationCount, keySize);
     SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
    
  2. Encryption:

    params:

    private static final String IV = "F27D5C9927726BCEFE7510B1BDD3D137";
    private static final String SALT = "3FF2EC019C627B945225DEBAD71A01B6985FE84C95A70EB132882F88C0A59A55";
    private static final int KEY_SIZE = 128;
    private static final int ITERATION_COUNT = 10000;
    private static final String PASSWORD = "SET_YOUR_PASSWORD_HERE";
    

    code:

    public String encrypt(String salt, String iv, String passphrase, String plaintext) {
        try {
            SecretKey key = generateKey(salt, passphrase);
            byte[] encrypted = doFinal(Cipher.ENCRYPT_MODE, key, iv, plaintext.getBytes("UTF-8"));
            return base64(encrypted);
        } catch (Exception e) {
            throw fail(e);
        }
    }
    private 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) {
            throw fail(e);
        }
    }
    public static String base64(byte[] bytes) {
        return Base64.getEncoder().encodeToString(bytes);
    }
    public static byte[] base64(String str) {
        return Base64.getDecoder().decode(str);
    }
    protected static byte[] hex(String str) {
        try {
            return decodeHex(str.toCharArray());
        } catch (Exception e) {
            e.printStackTrace();
        }
    
        return new byte[0];
    }
    public static byte[] decodeHex(char[] data) throws Exception {
        int len = data.length;
        if ((len & 1) != 0) {
            throw new Exception("Odd number of characters.");
        } else {
            byte[] out = new byte[len >> 1];
            int i = 0;
    
            for (int j = 0; j < len; ++i) {
                int f = toDigit(data[j], j) << 4;
                ++j;
                f |= toDigit(data[j], j);
                ++j;
                out[i] = (byte)(f & 255);
            }
    
            return out;
        }
    }
    protected static int toDigit(char ch, int index) throws Exception {
        int digit = Character.digit(ch, 16);
        if (digit == -1) {
            throw new Exception("Illegal hexadecimal character " + ch + " at index " + index);
        } else {
            return digit;
        }
    }
    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;
    }
    private IllegalStateException fail(Exception e) {
        return new IllegalStateException(e);
    }
    
  3. Decryption

    params: (same as in above java code)

    code:

    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) });
    
    var plaintext = decrypted.toString(CryptoJS.enc.Utf8);
    
James Z
  • 12,209
  • 10
  • 24
  • 44
Aryesh
  • 386
  • 2
  • 16
  • Welcome to SO! So it seems that your code works. Can you specified which one is your problem? – David García Bodego Jan 11 '20 at 07:53
  • When I decrypt the java encrypted file by CryptoJS, it shows error "malformed UTF-8 data", which as per my Google search means the file does not encrypt well, but Java has encrypted it well as the decoding in java outputs the original file. So I am confused why the error has been occurring in JavaScript(which on its own side is true code). – Aryesh Jan 11 '20 at 08:35
  • So, please, add this comment to your question and it will become clear. Most of the people they are taking a look to the question and if it is not clear, they go for the next one. – David García Bodego Jan 11 '20 at 08:53
  • Line 2 of the JavaScript code looks not correct to me. Why to you encode the ciphertext again? It is already base64 encoded for transmission, therefore you should decode it there and not encode again. – Robert Jan 12 '20 at 16:52

0 Answers0