RSA Asymmetric Encryption Implementation
The following example demonstrates a complete RSA encryption utility for generating key pairs, encrypting data with public keys, and decryptign with private keys. This implementation uses Java's built-in cryptographic providers with Base64 encoding for key and data portability.
import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class RSAKeyManager {
private static final String ALGORITHM = "RSA";
private static final int KEY_SIZE = 2048;
public static void createKeyPair(String seed) throws GeneralSecurityException {
KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM);
SecureRandom random = new SecureRandom(seed.getBytes(StandardCharsets.UTF_8));
generator.initialize(KEY_SIZE, random);
KeyPair keyPair = generator.generateKeyPair();
String encodedPublic = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
String encodedPrivate = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
System.out.println("Public Key: " + encodedPublic);
System.out.println("Private Key: " + encodedPrivate);
}
public static String encryptWithPublicKey(String plaintext, String publicKeyString) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
PublicKey pubKey = loadPublicKey(publicKeyString);
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] encrypted = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encrypted);
}
public static String decryptWithPrivateKey(String ciphertext, String privateKeyString) throws Exception {
byte[] decoded = Base64.getDecoder().decode(ciphertext);
Cipher cipher = Cipher.getInstance(ALGORITHM);
PrivateKey privKey = loadPrivateKey(privateKeyString);
cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] decrypted = cipher.doFinal(decoded);
return new String(decrypted, StandardCharsets.UTF_8);
}
private static PublicKey loadPublicKey(String keyString) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(keyString);
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory factory = KeyFactory.getInstance(ALGORITHM);
return factory.generatePublic(spec);
}
private static PrivateKey loadPrivateKey(String keyString) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(keyString);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory factory = KeyFactory.getInstance(ALGORITHM);
return factory.generatePrivate(spec);
}
public static void main(String[] args) throws Exception {
String pubKey = "";
String privKey = "";
// createKeyPair("your-secret-seed");
String message = "RSA Encryption Demo";
String encrypted = encryptWithPublicKey(message, pubKey);
System.out.println("Encrypted: " + encrypted);
String decrypted = decryptWithPrivateKey(encrypted, privKey);
System.out.println("Decrypted: " + decrypted);
}
}
JWT Token Generation with RSA256
This implementation uses the Auth0 JWT library to create and verify tokens using RSA signatures. The private key signs the token while the public key validates it, enabling secure stateless authentication.
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Date;
public class JWTTokenService {
private static final long TOKEN_LIFESPAN_MS = 30 * 60 * 1000;
private static final String CLAIM_KEY = "userData";
public static String issueToken(String payload, PrivateKey signingKey) {
Algorithm algorithm = Algorithm.RSA256(null, (RSAPrivateKey) signingKey);
Date expiration = new Date(System.currentTimeMillis() + TOKEN_LIFESPAN_MS);
return JWT.create()
.withClaim(CLAIM_KEY, payload)
.withExpiresAt(expiration)
.sign(algorithm);
}
public static boolean verifyToken(String token, PublicKey verificationKey) {
try {
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) verificationKey, null);
JWTVerifier verifier = JWT.require(algorithm).build();
verifier.verify(token);
return true;
} catch (JWTVerificationException e) {
System.err.println("Token validation failed: " + e.getMessage());
return false;
}
}
public static String retrievePayload(String token, PublicKey verificationKey) {
if (!verifyToken(token, verificationKey)) {
return null;
}
try {
DecodedJWT decoded = JWT.decode(token);
return decoded.getClaim(CLAIM_KEY).asString();
} catch (Exception e) {
System.err.println("Payload extraction failed: " + e.getMessage());
return null;
}
}
public static void main(String[] args) throws Exception {
String publicKey = "";
String privateKey = "";
// String jwt = issueToken("user123", RSAKeyManager.loadPrivateKey(privateKey));
String jwt = "";
System.out.println("Generated JWT: " + jwt);
String extractedData = retrievePayload(jwt, RSAKeyManager.loadPublicKey(publicKey));
System.out.println("Extracted payload: " + extractedData);
}
}
Dependencies
Add the Auth0 JWT library to your project:
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
AES Symmetric Encryption
For scenarios requiring fast symmetric encryption, this AES implementation uses CBC mode with PKCS5 padding and a fixed initialization vector for demonstration puropses.
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class AESCipherService {
private static final String SECRET = "your-16-byte-key!";
private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
private static final String INITIALIZATION_VECTOR = "16-byte-vector--";
public static String encryptData(String input) {
try {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
SecretKeySpec keySpec = new SecretKeySpec(SECRET.getBytes(StandardCharsets.UTF_8), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(INITIALIZATION_VECTOR.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] encrypted = cipher.doFinal(input.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encrypted);
} catch (Exception e) {
throw new RuntimeException("Encryption failed", e);
}
}
public static String decryptData(String encryptedData) {
try {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
SecretKeySpec keySpec = new SecretKeySpec(SECRET.getBytes(StandardCharsets.UTF_8), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(INITIALIZATION_VECTOR.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] decoded = Base64.getDecoder().decode(encryptedData);
return new String(cipher.doFinal(decoded), StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException("Decryption failed", e);
}
}
public static void main(String[] args) {
String original = "Sensitive Data";
String encrypted = encryptData(original);
System.out.println("Encrypted: " + encrypted);
String decrypted = decryptData(encrypted);
System.out.println("Decrypted: " + decrypted);
}
}