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.