Created
September 15, 2023 06:24
-
-
Save hardyscc/935bf1ab300b45a7c66ef1db1e739d7d to your computer and use it in GitHub Desktop.
RSA & AES encryption
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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