1

Hello I'm trying to reproduce hybrid encryption from posted NodeJS code in Java. It reads String Base64 encoded RSA public key, which uses for encrypting symmetric key. Same key with Iv is used for AES-256 data encryption. Then the iv, symmetricKey and encryptedData are POSTED via http to API endpoint.

//nodeJS code
// base64 public key
publicKey: string

const key: string = getRandomHex(64);
const rsa: NodeRSA = new NodeRSA(Buffer.from(publicKey, "utf8"), "pkcs1-public");
const encryptedKey: Buffer = rsa.encrypt(Buffer.from(key, "hex"));
const ivString: string = getRandomHex(32);
const iv: Buffer = Buffer.from(ivString, "hex");
const encryptedData: Buffer = encryptData(iv,Buffer.from(key, "hex"),Buffer.from(data.fileData, "base64"),);
const encryptedMeta: Buffer = encryptData(iv,Buffer.from(key, "hex"),Buffer.from(JSON.stringify(data.fileDescriptor), "utf8"),);

const getRandomHex = (size: number): string => crypto.randomBytes(Math.ceil(size / 2)).toString("hex").slice(0, size);

const encryptData = (iv: Buffer, key: Buffer, input: Buffer): Buffer => {
    const cipher: crypto.Cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
    const concat: Buffer = Buffer.concat([cipher.update(input), cipher.final()]);
    return concat;
};


//my java equivalent

public static IvParameterSpec makeIv(){
        SecureRandom s = new SecureRandom();
        byte[] newSeed =  s.generateSeed(16);
        s.setSeed(newSeed);
        byte[] byteIV = new byte[16];
        s.nextBytes(byteIV);
        IvParameterSpec iv = new IvParameterSpec(byteIV);
        return iv;
}

public static SecretKey makeKey(){
        KeyGenerator keyGen = null;
        SecureRandom sRandom = null;
        try {
            keyGen = KeyGenerator.getInstance("AES"); 
            sRandom = SecureRandom.getInstanceStrong();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } 
        keyGen.init(256, sRandom);
        SecretKey key = keyGen.generateKey();
        return key;
}

public static byte[] encryptData(IvParameterSpec iv, SecretKey key, byte[] input) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key, iv);
            byte[] update = cipher.update(input);
            byte[] doFinal = cipher.doFinal();
            byte[] encryptedData = new byte[update.length + doFinal.length];
            System.arraycopy(update, 0, encryptedData, 0, update.length);
            System.arraycopy(doFinal, 0, encryptedData, update.length, doFinal.length);
            return encryptedData;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
}

public static byte[] getSymmetricalKey(String publicKey, SecretKey key){
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            java.security.interfaces.RSAPublicKey pubKey = PKCS1ToSubjectPublicKeyInfo.decodePKCS1PublicKey(Base64.getDecoder().decode(publicKey.getBytes("UTF-8")));
            cipher.init(Cipher.PUBLIC_KEY, pubKey);
            return cipher.doFinal(key.getEncoded());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
}

public class Main {
    SecretKey secretKey = makeKey();
    byte[] encryptedKey = getSymmetricalKey("RSA PUBLIC KEY", secretKey);
    IvParameterSpec ivParameterSpec = makeIv();
    byte[] encryptedData = encryptData(ivParameterSpec, secretKey, fileDataBase64);
    byte[] encryptedMeta = encryptData(ivParameterSpec, secretKey, data.getJsonFileDescriptor().getBytes("UTF-8"));
}

For reading String public key i'm using this method: Reading a PKCS#1 or SPKI public key in Java without libraries. I'd like to ask, is this good approach ? Am I doing it right ? Because, the other side is not able to decrypt data. Bud when i use node js code, its working well. Thank you.

jakubM
  • 25
  • 4
  • (1) since when does nodejs, or any js, have ': type' in decls and signatures? (2) by default node-rsa uses **OAEP** for encrypt (with default SHA1) but your Java doesn't (3) the js code expects 'fileData' in base64 and decodes, while the Java uses 'fileDataBase64' as-is. With those changes and some scaffolding your code works interchangeably for me, although I would convert the pubkey value to SPKI once in advance so Java can handle it more easily (and node-rsa could use that also) – dave_thompson_085 Sep 03 '19 at 15:31
  • @dave_thompson_085 since typescript and also flow checks. It has been quite a few years. – Sulthan Sep 07 '19 at 05:50

0 Answers0