0

I'm trying to find the similar java code for the below Node JS code,

Node JS Code:

     var crypto = require('crypto');

     var mykey = crypto.createCipher('aes-128-ecb', 'XXXXXXXX00000000');
     var mystr = mykey.update('HelloWorld', 'utf8', 'hex')
     mystr += mykey.final('hex');

      console.log(mystr);

Encryption Result: ce25d577457cf8113fa4d9eb16379529

Java Code:

 public static String toHex(String arg) throws UnsupportedEncodingException {
              return String.format("%x", new BigInteger(1, arg.getBytes("UTF-8")));
        }

 public static void main(String args[]) throws Exception{
 
    byte[] key = "XXXXXXXX".getBytes();
    String message = "HelloWorld";
        
    try {
        key = Arrays.copyOf(key, 16); 
        SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);         
        byte encstr[] = cipher.update(message.getBytes());
        String encData = new String(encstr, "UTF-8");
        encData = toHex(encData);
        byte encstr2[] = cipher.doFinal();
        String encData2 = new String(encstr2);
        encData  = encData + toHex(encData2);           
        System.out.println(encData);
    } catch (NoSuchAlgorithmException nsae) {
        throw new Exception("Invalid Java Version");
    } catch (NoSuchPaddingException nse) {
        throw new Exception("Invalid Key");
    }
    
}

Encryption Result: 056efbfbdefbfbd7c7760efbfbdefbfbdefbfbd39262cefbfbdefbfbd5166

  • 1
    You are using the `crypto.createCipher(algorithm, password[, options])` version, hence the key you specify is handled as password and the actual key should be MD5(password) according to the node.js crypt documentation. On Java side you just use the string bytes as key without MD5 (which is insecure as well as using ECB mode). – Robert Aug 05 '20 at 10:46
  • 1
    You shouldn't convert the ciphertext to a Utf8 string. This corrupts the data. Instead, you should hex encode it directly. For this, a `toHex` implementation that directly expects a `byte[]` would be more useful (by the way, the current `toHex` omits leading 0-values). Also, the `update` call isn't necessary, the plaintext can be passed directly to `doFinal`. The encoding of the plaintext should be specified explicitly. – Topaco Aug 05 '20 at 12:05
  • By the way, if you want to derive the key via a password according to `createCipher`, you need a Java implementation of the (relatively insecure) key derivation function `EVP_BytesToKey`. An alternative is `createCipheriv`, see the NodeJS documentation. – Topaco Aug 05 '20 at 12:17
  • In particular all those efbfbd in the Java output are places where parts of your ciphertext that weren't valid UTF8 were discarded and changed to U+FFFD REPLACEMENT CHARACTER. For nodejs createCipher to Java dupe https://stackoverflow.com/questions/48047155/ https://stackoverflow.com/questions/33391533/ and since it is a copy of (pre-1.1.0 unsalted) `openssl enc` also https://stackoverflow.com/questions/8357941/ https://stackoverflow.com/questions/31947256/ – dave_thompson_085 Aug 05 '20 at 12:50

1 Answers1

0

Taking up the comments of @Robert and @Topaco I wrote a simple decryption program that is working for the given password 'XXXXXXXX00000000'.

Please keep in mind that this progrsm is using UNSECURE AES ECB mode and UNSECURE MD5 hash algorithm. The program does NOT provide any proper exception handling.

This is the result:

ciphertext Java:   ce25d577457cf8113fa4d9eb16379529
ciphertext NodeJS: ce25d577457cf8113fa4d9eb16379529

My code:

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MainSo {
    public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        System.out.println("https://stackoverflow.com/questions/63263081/node-js-encryption-code-to-java-encryption-code");

        String plaintext = "HelloWorld";
        String keyString =  "XXXXXXXX00000000"; // 16 chars
        byte[] key = keyString.getBytes(StandardCharsets.UTF_8);
        // md5 hashing is unsecure !!
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] keyMd5 = md.digest(key);
        // aes ecb mode encryption is unsecure
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyMd5, "AES");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
        byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        System.out.println("ciphertext Java:   " + bytesToHex(ciphertext));
        System.out.println("ciphertext NodeJS: " + "ce25d577457cf8113fa4d9eb16379529");
    }
    private static String bytesToHex(byte[] bytes) {
        // service method for displaying a byte array as hex string
        StringBuffer result = new StringBuffer();
        for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
        return result.toString();
    }
}
Michael Fehr
  • 5,827
  • 2
  • 19
  • 40