我不是这方面的专家,所以我需要听从专家的意见。下面的示例是加密和解密消息(长度未知)的合理安全方法,以便在可能不安全的网络(即电子邮件、HTTP请求或其他方式)上传输。我所说的"相当安全"是指,可以防止一个偶然的或半确定的第三方读取消息。
使用随机AES密钥加密消息,并通过公钥加密来保护AES密钥。
public static String encrypt(String data, PublicKey publicKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
// Create AES secret key
Cipher aes = Cipher.getInstance("AES");
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(256);
SecretKey key = kgen.generateKey();
SecretKeySpec aeskeySpec = new SecretKeySpec(key.getEncoded(), "AES");
// Encrypt data with AES Secret key
aes.init(Cipher.ENCRYPT_MODE, aeskeySpec);
byte[] dataEncoded = aes.doFinal(data.getBytes());
// Encrypt the secret AES key with the public key
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] aesKeyEncoded = rsa.doFinal(key.getEncoded());
// Output both secret AES key and data
return
Base64.getEncoder().encodeToString(aesKeyEncoded) + "~" +
Base64.getEncoder().encodeToString(dataEncoded);
}
解密AES密钥,然后解密消息:
public static String decrypt(String data, PrivateKey privateKey) throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException {
String[] parts = data.split("~");
// Decrypt AES secret key
byte[] encodedSecretKey = Base64.getDecoder().decode(parts[0]);
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decodedSecretKey = rsa.doFinal(encodedSecretKey);
SecretKeySpec key = new SecretKeySpec(decodedSecretKey, "AES");
// Decrypt message
Cipher aes = Cipher.getInstance("AES");
aes.init(Cipher.DECRYPT_MODE, key);
byte[] decodedData = aes.doFinal(Base64.getDecoder().decode(parts[1]));
return new String(decodedData);
}
使用上述方法:
public static void main(String args[]) throws NoSuchAlgorithmException, BadPaddingException, NoSuchPaddingException, IllegalBlockSizeException, InvalidKeyException {
// Generate public/private key
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048, new SecureRandom());
KeyPair kp = generator.generateKeyPair();
System.out.println(" Public key = " + Base64.getEncoder().encodeToString(kp.getPublic().getEncoded()));
System.out.println("Private key = " + Base64.getEncoder().encodeToString(kp.getPrivate().getEncoded()));
String mytext = "test message with some test data.";
String e = encrypt(mytext, kp.getPublic());
String d = decrypt(e, kp.getPrivate());
System.out.println(" text = " + mytext);
System.out.println("Decoded text = " + d);
}
只要您可以信任RSA公钥,总体思路就没问题。如果您只是将公钥发送给另一方,那么它就不是。
您还需要通过添加完整性和真实性来保护您的密文。您可以通过切换到AES/GCM模式(仅在Java 8中可用,或者使用Bouncy Castle)轻松地做到这一点。当前您正在使用不安全的AES/ECB加密模式。
您应该尝试使用带有OAEP填充的RSA,而不是pkcs# 1 v1.5填充。一般来说,您不应该依赖默认的字符编码(getBytes()
)或密码模式。
所以最后:不,那不安全。如果您想避免许多陷阱,请尝试使用TLS。