Exchanging Encrypted Files between Java and JavaScript

In this post we a going to encrypt a message in Java and decrypt later with JavaScript.

Let's start with the Java (encryption) part:

import static org.assertj.core.api.Assertions.assertThat;

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

import org.assertj.core.api.Assertions;
import org.junit.Test;

public class AppveyorEncryptionTest {

  private char[] password = "0123456789abcdef0123456789abcdef".toCharArray();
  private byte[] salt = "0123456789".getBytes();
  private int iterationCount = 5;

  public static byte[] encrypt(String toEncrypt, String key) throws Exception {
    // create a binary key from the argument key (seed)
    SecureRandom sr = new SecureRandom(key.getBytes());
    KeyGenerator kg = KeyGenerator.getInstance("Rijndael");
    kg.init(sr);
    SecretKey sk = kg.generateKey();

    // create an instance of cipher
    Cipher cipher = Cipher.getInstance("Rijndael");

    // initialize the cipher with the key
    cipher.init(Cipher.ENCRYPT_MODE, sk);

    // enctypt!
    byte[] encrypted = cipher.doFinal(toEncrypt.getBytes());

    return encrypted;
  }

  public static String decrypt(byte[] toDecrypt, String key) throws Exception {
    // create a binary key from the argument key (seed)
    SecureRandom sr = new SecureRandom(key.getBytes());
    KeyGenerator kg = KeyGenerator.getInstance("Rijndael");
    kg.init(sr);
    SecretKey sk = kg.generateKey();

    // do the decryption with that key
    Cipher cipher = Cipher.getInstance("Rijndael");
    cipher.init(Cipher.DECRYPT_MODE, sk);
    byte[] decrypted = cipher.doFinal(toDecrypt);

    return new String(decrypted);
  }

  @Test
  public void testRijndael() throws Exception {
    byte[] encrypted = encrypt("Hello World!", "myKey");

    assertThat(decrypt(encrypted, "myKey")).isEqualTo("Hello World!");
  }

}
    import java.nio.file.*;

    import javax.crypto.Cipher;
    import javax.crypto.spec.SecretKeySpec;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;

    public class AesEncryption {

      private String key = "shared_secret";

      public byte[] encrypt(byte[] input) throws Exception {
          byte[] keyBytes = key.getBytes();
          byte[] md5Digest = MessageDigest.getInstance("MD5").digest(keyBytes);

          byte[] result = null;
          Cipher aesCipher = Cipher.getInstance("AES");
          aesCipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(md5Digest, "AES"));
          result = new byte[aesCipher.getOutputSize(input.length)];
          int ctLength = aesCipher.update(input, 0, input.length, result, 0);
          aesCipher.doFinal(result, ctLength);
          return result;
      }

      public static void main(String[] args) throws Exception {
        String message = "hello world";

        byte[] input = message.getBytes("UTF-8");

        byte[] encrypted = new AesEncryption().encrypt(input);

        Files.write(Paths.get("/tmp/message.enc"), encrypted, StandardOpenOption.CREATE);
      }
    }

Let's compile and run the small AesEncryption program:

$ java -c AesEncryption.java
$ java AesEncryption

This will save the encrypted message in /tmp/message.enc.

To decrypt this message we are going to use this JavaScript program:

    const crypto = require('crypto');
    const fs = require('fs');

    let key = 'shared_secret'

    let encryptedInput = fs.readFileSync('message.enc');

    let decipher = crypto.createDecipher('aes-128-ecb', key);

    let output = Buffer.concat([decipher.update(encryptedInput) , decipher.final()]);

    fs.writeFileSync('message', output);

That's it. We exchanged a secret message between Java and JavaScript.

Just in case you also want to do the encryption within a Node.js app - this is how you could do the encryption:

    const forge = require('node-forge');

    function encryptAes256Cbc(data, key, iv) {
      let cipher = forge.cipher.createCipher('AES-CBC', forge.util.hexToBytes(key));
      cipher.start({iv: forge.util.hexToBytes(iv)});
      cipher.update(forge.util.createBuffer(data));
      cipher.finish();
      let bytes = cipher.output.getBytes();
      return forge.util.encode64(bytes);
//      return forge.util.encode64(bytes, 64); // use new lines
    }

Have fun creating your secret messages…