Skip to content

Instantly share code, notes, and snippets.

@hardyscc
Created September 15, 2023 06:24
Show Gist options
  • Save hardyscc/935bf1ab300b45a7c66ef1db1e739d7d to your computer and use it in GitHub Desktop.
Save hardyscc/935bf1ab300b45a7c66ef1db1e739d7d to your computer and use it in GitHub Desktop.
RSA & AES encryption
package com.example.cipher;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.util.Base64;
import javax.annotation.PostConstruct;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class CipherHelper {
@Value("${cipher.keystore.path}")
private String keystorePath;
@Value("${cipher.keystore.password:changeit}")
private String keystorePassword;
@Value("${cipher.key.alias:mykey}")
private String keyAlias;
@Value("${cipher.key.algorithm:RSA}")
private String keyAlgorithm;
private PublicKey publicKey;
private PrivateKey privateKey;
@PostConstruct
public void loadKeys() throws Exception {
KeyStore keystore = KeyStore.getInstance("JKS");
Path keystoreFile = Paths.get(keystorePath);
if (Files.exists(keystoreFile)) {
keystore.load(Files.newInputStream(keystoreFile), keystorePassword.toCharArray());
Certificate cert = keystore.getCertificate(keyAlias);
publicKey = cert.getPublicKey();
Key key = keystore.getKey(keyAlias, keystorePassword.toCharArray());
if (key instanceof PrivateKey) {
privateKey = (PrivateKey) key;
}
}
}
// Encrypt data using AES with a randomly generated key
private byte[] encryptWithAES(String data, SecretKey secretKey)
throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec(new byte[16]);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
return cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
}
// Decrypt data using AES with the provided key
private String decryptWithAES(byte[] encryptedData, SecretKey secretKey)
throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec(new byte[16]);
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
byte[] decryptedData = cipher.doFinal(encryptedData);
return new String(decryptedData, StandardCharsets.UTF_8);
}
// Encrypt AES key using RSA public key
private byte[] encryptAESKeyWithRSA(SecretKey secretKey, PublicKey publicKey)
throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(secretKey.getEncoded());
}
// Decrypt AES key using RSA private key
private SecretKey decryptAESKeyWithRSA(byte[] encryptedKey, PrivateKey privateKey)
throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedKey = cipher.doFinal(encryptedKey);
return new SecretKeySpec(decryptedKey, "AES");
}
// Encrypt data using hybrid RSA-AES encryption
public String encrypt(String data) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
// Generate AES key
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
SecretKey secretKey = keyGenerator.generateKey();
// Encrypt data with AES
byte[] encryptedData = encryptWithAES(data, secretKey);
// Encrypt AES key with RSA
byte[] encryptedKey = encryptAESKeyWithRSA(secretKey, publicKey);
// Combine encrypted key and data
byte[] encryptedKeyAndData = new byte[encryptedKey.length + encryptedData.length];
System.arraycopy(encryptedKey, 0, encryptedKeyAndData, 0, encryptedKey.length);
System.arraycopy(encryptedData, 0, encryptedKeyAndData, encryptedKey.length, encryptedData.length);
// Encode the result as Base64 string
return Base64.getEncoder().encodeToString(encryptedKeyAndData);
}
// Decrypt data using hybrid RSA-AES decryption
public String decrypt(String encryptedData)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
// Decode Base64 string
byte[] encryptedKeyAndData = Base64.getDecoder().decode(encryptedData);
// Split encrypted key and data
int keySize = 256; // RSA 2048-bit key size gives 256 bytes
byte[] encryptedKey = new byte[keySize];
byte[] encryptedDataBytes = new byte[encryptedKeyAndData.length - keySize];
System.arraycopy(encryptedKeyAndData, 0, encryptedKey, 0, keySize);
System.arraycopy(encryptedKeyAndData, keySize, encryptedDataBytes, 0, encryptedDataBytes.length);
// Decrypt AES key with RSA
SecretKey secretKey = decryptAESKeyWithRSA(encryptedKey, privateKey);
// Decrypt data with AES
return decryptWithAES(encryptedDataBytes, secretKey);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment