首页 > 解决方案 > 等效于 NodeJS 的 Java AES-256 和 RSA 混合加密

问题描述

您好,我正在尝试从 Java 中发布的 NodeJS 代码中重现混合加密。它读取字符串 Base64 编码的 RSA 公钥,用于加密对称密钥。与 Iv 相同的密钥用于 AES-256 数据加密。然后 iv、symmetricKey 和 encryptedData 通过 http 发布到 API 端点。

//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"));
}

为了读取字符串公钥,我使用这种方法: Reading a PKCS#1 or SPKI public key in Java without libraries。我想问一下,这是好方法吗?我做对了吗?因为,对方无法解密数据。当我使用节点 js 代码时,它运行良好。谢谢你。

标签: javaencryptioncryptographyaesrsa

解决方案


推荐阅读