java - 等效于 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 代码时,它运行良好。谢谢你。
解决方案
推荐阅读
- python - 在 python 3.6 上安装 python PIL
- kotlin - 在 TornadoFX 中将“FXTask”消息绑定到“标签”而无需组件耦合
- quickbooks-online - Zapier 中 QB 在线销售收据上有多个行项目
- firebase - 如何根据添加时间在 Firestore 中检索有限的文档(对于聊天应用程序)?
- java - 使用 XML 配置和注释初始化 java bean 类时出现空指针异常
- javascript - 无法编译意外令牌 57:1 Return(
- c# - 在 C# 控制台应用程序中显示 SQL 数据库中的值
- c++ - 如何编写一个类似于内核list_head的c++风格的双链表实现
- javascript - React Native - 用于 TextInput 的未定义函数 onPress
- python - 如何计算具有循环值的列中的循环数?