KeyPair Generation Best Practices in Java: Secure Cryptography Implementation

This comprehensive guide covers secure key pair generation, storage, and management practices in Java for various cryptographic algorithms.

Project Setup and Dependencies

Maven Configuration

<!-- pom.xml -->
<properties>
<bouncycastle.version>1.76</bouncycastle.version>
</properties>
<dependencies>
<!-- Bouncy Castle Provider for additional algorithms -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<!-- Bouncy Castle PKIX for X.509 certificate handling -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.9</version>
</dependency>
</dependencies>

Core KeyPair Generation Service

Secure KeyPair Generator

package com.security.crypto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.KeyGenerator;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.HashMap;
import java.util.Map;
public class SecureKeyPairGenerator {
private static final Logger logger = LoggerFactory.getLogger(SecureKeyPairGenerator.class);
// Secure random instance - reuse for better performance
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
static {
// Initialize security providers
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// Seed the secure random
seedSecureRandom();
}
/**
* Seed the secure random with additional entropy
*/
private static void seedSecureRandom() {
try {
// Add system entropy
byte[] seed = new byte[32];
new SecureRandom().nextBytes(seed); // System random for initial seed
SECURE_RANDOM.setSeed(seed);
// Add thread timing entropy
SECURE_RANDOM.setSeed(System.nanoTime());
SECURE_RANDOM.setSeed(Thread.currentThread().getId());
logger.info("SecureRandom seeded successfully");
} catch (Exception e) {
logger.warn("Failed to seed SecureRandom: {}", e.getMessage());
}
}
/**
* Generate RSA key pair with secure parameters
*/
public KeyPair generateRSAKeyPair(int keySize) throws GeneralSecurityException {
validateRSAKeySize(keySize);
try {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "BC");
// Use secure parameters for RSA key generation
RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(
keySize, 
RSAKeyGenParameterSpec.F4 // 65537 - standard public exponent
);
keyGen.initialize(spec, SECURE_RANDOM);
KeyPair keyPair = keyGen.generateKeyPair();
logger.info("Generated RSA-{} key pair successfully", keySize);
logKeyStrength(keyPair.getPublic());
return keyPair;
} catch (GeneralSecurityException e) {
logger.error("Failed to generate RSA-{} key pair: {}", keySize, e.getMessage());
throw e;
}
}
/**
* Generate Elliptic Curve key pair
*/
public KeyPair generateECKeyPair(String curveName) throws GeneralSecurityException {
validateECCurveName(curveName);
try {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", "BC");
// Use named curve for better interoperability
ECGenParameterSpec ecSpec = new ECGenParameterSpec(curveName);
keyGen.initialize(ecSpec, SECURE_RANDOM);
KeyPair keyPair = keyGen.generateKeyPair();
logger.info("Generated EC key pair with curve {} successfully", curveName);
logKeyStrength(keyPair.getPublic());
return keyPair;
} catch (GeneralSecurityException e) {
logger.error("Failed to generate EC key pair with curve {}: {}", curveName, e.getMessage());
throw e;
}
}
/**
* Generate DSA key pair
*/
public KeyPair generateDSAKeyPair(int keySize) throws GeneralSecurityException {
validateDSAKeySize(keySize);
try {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "BC");
keyGen.initialize(keySize, SECURE_RANDOM);
KeyPair keyPair = keyGen.generateKeyPair();
logger.info("Generated DSA-{} key pair successfully", keySize);
logKeyStrength(keyPair.getPublic());
return keyPair;
} catch (GeneralSecurityException e) {
logger.error("Failed to generate DSA-{} key pair: {}", keySize, e.getMessage());
throw e;
}
}
/**
* Generate EdDSA key pair (Ed25519/Ed448)
*/
public KeyPair generateEdDSAKeyPair(String algorithm) throws GeneralSecurityException {
if (!algorithm.equalsIgnoreCase("Ed25519") && !algorithm.equalsIgnoreCase("Ed448")) {
throw new IllegalArgumentException("Unsupported EdDSA algorithm: " + algorithm);
}
try {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm, "BC");
keyGen.initialize(null, SECURE_RANDOM); // EdDSA doesn't need explicit parameters
KeyPair keyPair = keyGen.generateKeyPair();
logger.info("Generated {} key pair successfully", algorithm);
logKeyStrength(keyPair.getPublic());
return keyPair;
} catch (GeneralSecurityException e) {
logger.error("Failed to generate {} key pair: {}", algorithm, e.getMessage());
throw e;
}
}
/**
* Validate RSA key size
*/
private void validateRSAKeySize(int keySize) {
if (keySize < 2048) {
throw new IllegalArgumentException(
"RSA key size must be at least 2048 bits for security. Provided: " + keySize);
}
// Check if key size is a power of two for optimal performance
if ((keySize & (keySize - 1)) != 0) {
logger.warn("RSA key size {} is not a power of two, which may impact performance", keySize);
}
// NIST recommendations
if (keySize < 3072) {
logger.warn("RSA key size {} is below NIST recommended 3072 bits for new systems", keySize);
}
}
/**
* Validate EC curve name
*/
private void validateECCurveName(String curveName) {
Map<String, Integer> standardCurves = new HashMap<>();
standardCurves.put("secp256r1", 256);  // NIST P-256
standardCurves.put("secp384r1", 384);  // NIST P-384
standardCurves.put("secp521r1", 521);  // NIST P-521
standardCurves.put("brainpoolP256r1", 256);
standardCurves.put("brainpoolP384r1", 384);
standardCurves.put("brainpoolP512r1", 512);
if (!standardCurves.containsKey(curveName)) {
throw new IllegalArgumentException(
"Unsupported EC curve: " + curveName + ". Supported: " + standardCurves.keySet());
}
logger.debug("Using EC curve: {} ({} bits security)", curveName, standardCurves.get(curveName));
}
/**
* Validate DSA key size
*/
private void validateDSAKeySize(int keySize) {
if (keySize < 2048) {
throw new IllegalArgumentException(
"DSA key size must be at least 2048 bits for security. Provided: " + keySize);
}
// DSA key sizes should be multiples of 64
if (keySize % 64 != 0) {
throw new IllegalArgumentException("DSA key size must be a multiple of 64. Provided: " + keySize);
}
}
/**
* Log key strength information
*/
private void logKeyStrength(PublicKey publicKey) {
String algorithm = publicKey.getAlgorithm();
int keySize = getKeySize(publicKey);
String strength;
if (keySize >= 3072 || (algorithm.equals("EC") && keySize >= 256)) {
strength = "STRONG";
} else if (keySize >= 2048) {
strength = "ADEQUATE";
} else {
strength = "WEAK";
}
logger.info("Key strength: {} - {}-bit {}", strength, keySize, algorithm);
}
/**
* Estimate key size from public key
*/
private int getKeySize(PublicKey publicKey) {
String algorithm = publicKey.getAlgorithm();
if (algorithm.equals("RSA") || algorithm.equals("DSA")) {
// For RSA and DSA, key size is explicit in the encoding
return publicKey.getEncoded().length * 8; // Rough estimate
} else if (algorithm.equals("EC")) {
// For EC, we need to parse the curve parameters
java.security.interfaces.ECPublicKey ecKey = (java.security.interfaces.ECPublicKey) publicKey;
return ecKey.getParams().getCurve().getField().getFieldSize();
} else if (algorithm.equals("Ed25519")) {
return 255;
} else if (algorithm.equals("Ed448")) {
return 448;
}
return -1; // Unknown
}
/**
* Get secure random instance
*/
public SecureRandom getSecureRandom() {
return SECURE_RANDOM;
}
}

Key Storage and Management

Secure Key Storage Service

package com.security.crypto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.file.*;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class SecureKeyStorage {
private static final Logger logger = LoggerFactory.getLogger(SecureKeyStorage.class);
// Encryption parameters
private static final String KEY_ENCRYPTION_ALGORITHM = "AES/GCM/NoPadding";
private static final int GCM_TAG_LENGTH = 128; // bits
private static final int GCM_IV_LENGTH = 12;   // bytes
private static final int SALT_LENGTH = 32;     // bytes
private static final int ITERATION_COUNT = 210000; // OWASP recommended
/**
* Store key pair securely to files
*/
public void storeKeyPair(KeyPair keyPair, String basePath, char[] password) 
throws GeneralSecurityException, IOException {
validateStoragePath(basePath);
// Create directory if it doesn't exist
Path directory = Paths.get(basePath).getParent();
if (directory != null) {
Files.createDirectories(directory);
}
// Store private key encrypted
String privateKeyPath = basePath + ".private";
storePrivateKey(keyPair.getPrivate(), privateKeyPath, password);
// Store public key in plain text (it's public)
String publicKeyPath = basePath + ".public";
storePublicKey(keyPair.getPublic(), publicKeyPath);
logger.info("Key pair stored successfully: {}", basePath);
}
/**
* Store encrypted private key
*/
private void storePrivateKey(PrivateKey privateKey, String filePath, char[] password) 
throws GeneralSecurityException, IOException {
// Encrypt private key
byte[] encryptedKey = encryptKey(privateKey.getEncoded(), password);
// Write to file with secure permissions
Path path = Paths.get(filePath);
Files.write(path, encryptedKey, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
// Set secure file permissions (Unix-like systems)
try {
path.toFile().setReadable(false, false); // No global read
path.toFile().setReadable(true, true);   // Owner read only
path.toFile().setWritable(true, true);   // Owner write only
} catch (SecurityException e) {
logger.warn("Could not set secure file permissions: {}", e.getMessage());
}
logger.debug("Private key stored encrypted: {}", filePath);
}
/**
* Store public key
*/
private void storePublicKey(PublicKey publicKey, String filePath) throws IOException {
// Public key doesn't need encryption
byte[] publicKeyBytes = publicKey.getEncoded();
// Write to file
Files.write(Paths.get(filePath), publicKeyBytes, 
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
logger.debug("Public key stored: {}", filePath);
}
/**
* Load key pair from storage
*/
public KeyPair loadKeyPair(String basePath, char[] password, String keyAlgorithm) 
throws GeneralSecurityException, IOException {
validateStoragePath(basePath);
// Load private key
String privateKeyPath = basePath + ".private";
PrivateKey privateKey = loadPrivateKey(privateKeyPath, password, keyAlgorithm);
// Load public key
String publicKeyPath = basePath + ".public";
PublicKey publicKey = loadPublicKey(publicKeyPath, keyAlgorithm);
KeyPair keyPair = new KeyPair(publicKey, privateKey);
logger.info("Key pair loaded successfully: {}", basePath);
return keyPair;
}
/**
* Load and decrypt private key
*/
private PrivateKey loadPrivateKey(String filePath, char[] password, String keyAlgorithm) 
throws GeneralSecurityException, IOException {
// Read encrypted key
byte[] encryptedKey = Files.readAllBytes(Paths.get(filePath));
// Decrypt private key
byte[] privateKeyBytes = decryptKey(encryptedKey, password);
// Reconstruct private key
KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm, "BC");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
return keyFactory.generatePrivate(keySpec);
}
/**
* Load public key
*/
private PublicKey loadPublicKey(String filePath, String keyAlgorithm) 
throws GeneralSecurityException, IOException {
byte[] publicKeyBytes = Files.readAllBytes(Paths.get(filePath));
KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm, "BC");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
return keyFactory.generatePublic(keySpec);
}
/**
* Encrypt key using password-based encryption
*/
private byte[] encryptKey(byte[] keyData, char[] password) throws GeneralSecurityException {
// Generate salt
byte[] salt = new byte[SALT_LENGTH];
new SecureRandom().nextBytes(salt);
// Generate IV for GCM
byte[] iv = new byte[GCM_IV_LENGTH];
new SecureRandom().nextBytes(iv);
// Derive encryption key from password
SecretKey secretKey = deriveKey(password, salt);
// Initialize cipher
Cipher cipher = Cipher.getInstance(KEY_ENCRYPTION_ALGORITHM, "BC");
GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmSpec);
// Encrypt key data
byte[] encryptedKey = cipher.doFinal(keyData);
// Combine salt + iv + encrypted data
byte[] result = new byte[salt.length + iv.length + encryptedKey.length];
System.arraycopy(salt, 0, result, 0, salt.length);
System.arraycopy(iv, 0, result, salt.length, iv.length);
System.arraycopy(encryptedKey, 0, result, salt.length + iv.length, encryptedKey.length);
// Clear sensitive data from memory
Arrays.fill(salt, (byte) 0);
Arrays.fill(iv, (byte) 0);
return result;
}
/**
* Decrypt key using password-based encryption
*/
private byte[] decryptKey(byte[] encryptedData, char[] password) throws GeneralSecurityException {
// Extract components
byte[] salt = new byte[SALT_LENGTH];
byte[] iv = new byte[GCM_IV_LENGTH];
byte[] encryptedKey = new byte[encryptedData.length - SALT_LENGTH - GCM_IV_LENGTH];
System.arraycopy(encryptedData, 0, salt, 0, SALT_LENGTH);
System.arraycopy(encryptedData, SALT_LENGTH, iv, 0, GCM_IV_LENGTH);
System.arraycopy(encryptedData, SALT_LENGTH + GCM_IV_LENGTH, encryptedKey, 0, encryptedKey.length);
// Derive decryption key
SecretKey secretKey = deriveKey(password, salt);
// Initialize cipher
Cipher cipher = Cipher.getInstance(KEY_ENCRYPTION_ALGORITHM, "BC");
GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmSpec);
// Decrypt key data
byte[] decryptedKey = cipher.doFinal(encryptedKey);
// Clear sensitive data from memory
Arrays.fill(salt, (byte) 0);
Arrays.fill(iv, (byte) 0);
return decryptedKey;
}
/**
* Derive encryption key from password using PBKDF2
*/
private SecretKey deriveKey(char[] password, byte[] salt) throws GeneralSecurityException {
PBEKeySpec keySpec = new PBEKeySpec(password, salt, ITERATION_COUNT, 256);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256", "BC");
byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
// Clear sensitive data
keySpec.clearPassword();
Arrays.fill(keyBytes, (byte) 0);
return secretKey;
}
/**
* Validate storage path
*/
private void validateStoragePath(String basePath) {
if (basePath == null || basePath.trim().isEmpty()) {
throw new IllegalArgumentException("Storage path cannot be null or empty");
}
// Check for path traversal attempts
if (basePath.contains("..") || basePath.contains("~")) {
throw new IllegalArgumentException("Invalid storage path: " + basePath);
}
}
/**
* Export public key to PEM format
*/
public String exportPublicKeyToPEM(PublicKey publicKey) {
byte[] encoded = publicKey.getEncoded();
String base64 = Base64.getEncoder().encodeToString(encoded);
StringBuilder pem = new StringBuilder();
pem.append("-----BEGIN PUBLIC KEY-----\n");
// Split into 64-character lines
for (int i = 0; i < base64.length(); i += 64) {
int end = Math.min(i + 64, base64.length());
pem.append(base64, i, end).append("\n");
}
pem.append("-----END PUBLIC KEY-----\n");
return pem.toString();
}
/**
* Import public key from PEM format
*/
public PublicKey importPublicKeyFromPEM(String pem, String algorithm) 
throws GeneralSecurityException {
// Remove PEM headers and whitespace
String base64 = pem.replaceAll("-----BEGIN PUBLIC KEY-----", "")
.replaceAll("-----END PUBLIC KEY-----", "")
.replaceAll("\\s", "");
byte[] encoded = Base64.getDecoder().decode(base64);
KeyFactory keyFactory = KeyFactory.getInstance(algorithm, "BC");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
return keyFactory.generatePublic(keySpec);
}
}

Key Rotation and Lifecycle Management

Key Rotation Service

package com.security.crypto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.KeyPair;
import java.security.PublicKey;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class KeyRotationService {
private static final Logger logger = LoggerFactory.getLogger(KeyRotationService.class);
private final SecureKeyPairGenerator keyGenerator;
private final SecureKeyStorage keyStorage;
private final ScheduledExecutorService scheduler;
// Key rotation policies
private final Map<String, RotationPolicy> rotationPolicies;
private final Map<String, KeyVersion> activeKeys;
public KeyRotationService() {
this.keyGenerator = new SecureKeyPairGenerator();
this.keyStorage = new SecureKeyStorage();
this.scheduler = Executors.newScheduledThreadPool(2);
this.rotationPolicies = new ConcurrentHashMap<>();
this.activeKeys = new ConcurrentHashMap<>();
// Start background rotation tasks
startRotationMonitor();
}
/**
* Key rotation policy
*/
public static class RotationPolicy {
private final String keyId;
private final int maxLifetimeDays;
private final int warningPeriodDays;
private final String algorithm;
private final int keySize;
private final String curveName;
public RotationPolicy(String keyId, int maxLifetimeDays, int warningPeriodDays, 
String algorithm, int keySize, String curveName) {
this.keyId = keyId;
this.maxLifetimeDays = maxLifetimeDays;
this.warningPeriodDays = warningPeriodDays;
this.algorithm = algorithm;
this.keySize = keySize;
this.curveName = curveName;
}
// Getters
public String getKeyId() { return keyId; }
public int getMaxLifetimeDays() { return maxLifetimeDays; }
public int getWarningPeriodDays() { return warningPeriodDays; }
public String getAlgorithm() { return algorithm; }
public int getKeySize() { return keySize; }
public String getCurveName() { return curveName; }
}
/**
* Key version information
*/
public static class KeyVersion {
private final String keyId;
private final String version;
private final LocalDateTime creationTime;
private final LocalDateTime expirationTime;
private final KeyPair keyPair;
private boolean active;
public KeyVersion(String keyId, String version, LocalDateTime creationTime, 
LocalDateTime expirationTime, KeyPair keyPair) {
this.keyId = keyId;
this.version = version;
this.creationTime = creationTime;
this.expirationTime = expirationTime;
this.keyPair = keyPair;
this.active = true;
}
// Getters
public String getKeyId() { return keyId; }
public String getVersion() { return version; }
public LocalDateTime getCreationTime() { return creationTime; }
public LocalDateTime getExpirationTime() { return expirationTime; }
public KeyPair getKeyPair() { return keyPair; }
public boolean isActive() { return active; }
public boolean isExpired() { 
return LocalDateTime.now().isAfter(expirationTime); 
}
public boolean isExpiringSoon() {
return LocalDateTime.now().isAfter(expirationTime.minusDays(7));
}
public void deactivate() { this.active = false; }
}
/**
* Register a key rotation policy
*/
public void registerRotationPolicy(RotationPolicy policy) {
rotationPolicies.put(policy.getKeyId(), policy);
logger.info("Registered rotation policy for key: {}", policy.getKeyId());
}
/**
* Generate initial key pair with rotation policy
*/
public KeyVersion generateInitialKey(String keyId, char[] storagePassword) 
throws GeneralSecurityException {
RotationPolicy policy = rotationPolicies.get(keyId);
if (policy == null) {
throw new IllegalArgumentException("No rotation policy found for key: " + keyId);
}
// Generate key pair
KeyPair keyPair = generateKeyPair(policy);
// Create key version
String version = generateVersionId();
LocalDateTime now = LocalDateTime.now();
LocalDateTime expiration = now.plusDays(policy.getMaxLifetimeDays());
KeyVersion keyVersion = new KeyVersion(keyId, version, now, expiration, keyPair);
// Store key
String storagePath = buildStoragePath(keyId, version);
keyStorage.storeKeyPair(keyPair, storagePath, storagePassword);
// Set as active
activeKeys.put(keyId, keyVersion);
logger.info("Generated initial key version {} for key: {}", version, keyId);
return keyVersion;
}
/**
* Rotate key to new version
*/
public KeyVersion rotateKey(String keyId, char[] storagePassword) 
throws GeneralSecurityException {
RotationPolicy policy = rotationPolicies.get(keyId);
if (policy == null) {
throw new IllegalArgumentException("No rotation policy found for key: " + keyId);
}
// Generate new key pair
KeyPair newKeyPair = generateKeyPair(policy);
// Create new version
String newVersion = generateVersionId();
LocalDateTime now = LocalDateTime.now();
LocalDateTime expiration = now.plusDays(policy.getMaxLifetimeDays());
KeyVersion newKeyVersion = new KeyVersion(keyId, newVersion, now, expiration, newKeyPair);
// Store new key
String storagePath = buildStoragePath(keyId, newVersion);
keyStorage.storeKeyPair(newKeyPair, storagePath, storagePassword);
// Deactivate old key
KeyVersion oldKeyVersion = activeKeys.get(keyId);
if (oldKeyVersion != null) {
oldKeyVersion.deactivate();
logger.info("Deactivated old key version {} for key: {}", 
oldKeyVersion.getVersion(), keyId);
}
// Activate new key
activeKeys.put(keyId, newKeyVersion);
logger.info("Rotated key {} to new version: {}", keyId, newVersion);
return newKeyVersion;
}
/**
* Get active key for a key ID
*/
public KeyVersion getActiveKey(String keyId) {
KeyVersion keyVersion = activeKeys.get(keyId);
if (keyVersion == null || !keyVersion.isActive()) {
throw new IllegalArgumentException("No active key found for: " + keyId);
}
return keyVersion;
}
/**
* Check if key needs rotation
*/
public boolean needsRotation(String keyId) {
KeyVersion keyVersion = activeKeys.get(keyId);
if (keyVersion == null) return true;
return keyVersion.isExpiringSoon() || keyVersion.isExpired();
}
/**
* Generate key pair based on policy
*/
private KeyPair generateKeyPair(RotationPolicy policy) throws GeneralSecurityException {
switch (policy.getAlgorithm().toUpperCase()) {
case "RSA":
return keyGenerator.generateRSAKeyPair(policy.getKeySize());
case "EC":
return keyGenerator.generateECKeyPair(policy.getCurveName());
case "DSA":
return keyGenerator.generateDSAKeyPair(policy.getKeySize());
case "ED25519":
case "ED448":
return keyGenerator.generateEdDSAKeyPair(policy.getAlgorithm());
default:
throw new IllegalArgumentException("Unsupported algorithm: " + policy.getAlgorithm());
}
}
/**
* Generate version ID based on timestamp
*/
private String generateVersionId() {
return DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss").format(LocalDateTime.now());
}
/**
* Build storage path for key version
*/
private String buildStoragePath(String keyId, String version) {
return String.format("keys/%s/%s", keyId, version);
}
/**
* Start background rotation monitoring
*/
private void startRotationMonitor() {
// Check for expiring keys every hour
scheduler.scheduleAtFixedRate(() -> {
try {
monitorKeyExpiration();
} catch (Exception e) {
logger.error("Error in key rotation monitor", e);
}
}, 1, 1, TimeUnit.HOURS);
logger.info("Key rotation monitor started");
}
/**
* Monitor key expiration and send alerts
*/
private void monitorKeyExpiration() {
for (Map.Entry<String, KeyVersion> entry : activeKeys.entrySet()) {
String keyId = entry.getKey();
KeyVersion keyVersion = entry.getValue();
if (keyVersion.isExpired()) {
logger.error("KEY EXPIRED: Key {} version {} has expired!", 
keyId, keyVersion.getVersion());
sendExpirationAlert(keyId, keyVersion, "EXPIRED");
} else if (keyVersion.isExpiringSoon()) {
logger.warn("KEY EXPIRING: Key {} version {} expires in less than 7 days", 
keyId, keyVersion.getVersion());
sendExpirationAlert(keyId, keyVersion, "EXPIRING_SOON");
}
}
}
/**
* Send expiration alert
*/
private void sendExpirationAlert(String keyId, KeyVersion keyVersion, String severity) {
// In a real implementation, this would send email, Slack message, etc.
String message = String.format(
"Key Rotation Alert [%s] - Key: %s, Version: %s, Expires: %s",
severity, keyId, keyVersion.getVersion(), 
keyVersion.getExpirationTime().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
);
logger.warn("KEY ROTATION ALERT: {}", message);
// Example: Integrate with monitoring system
// monitoringService.alert("KeyRotation", severity, message);
}
/**
* Shutdown the rotation service
*/
public void shutdown() {
scheduler.shutdown();
try {
if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
scheduler.shutdownNow();
}
} catch (InterruptedException e) {
scheduler.shutdownNow();
Thread.currentThread().interrupt();
}
logger.info("Key rotation service shutdown complete");
}
}

Key Validation and Testing

Key Validation Service

```java
package com.security.crypto;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.; import java.security.interfaces.;
import java.util.ArrayList;
import java.util.List;

public class KeyValidationService {
private static final Logger logger = LoggerFactory.getLogger(KeyValidationService.class);

/**
* Validate key pair for correctness and security
*/
public ValidationResult validateKeyPair(KeyPair keyPair) {
List<String> errors = new ArrayList<>();
List<String> warnings = new ArrayList<>();
try {
// Basic validation
validateNotNull(keyPair, errors);
validateKeyComponents(keyPair, errors);
// Algorithm-specific validation
String algorithm = keyPair.getPublic().getAlgorithm();
switch (algorithm.toUpperCase()) {
case "RSA":
validateRSAKeyPair((RSAPublicKey) keyPair.getPublic(), 
(RSAPrivateKey) keyPair.getPrivate(), errors, warnings);
break;
case "EC":
validateECKeyPair((ECPublicKey) keyPair.getPublic(), 
(ECPrivateKey) keyPair.getPrivate(), errors, warnings);
break;
case "DSA":
validateDSAKeyPair((DSAPublicKey) keyPair.getPublic(), 
(DSAPrivateKey) keyPair.getPrivate(), errors, warnings);
break;
default:
warnings.add("Unsupported algorithm for detailed validation: " + algorithm);
}
// Perform cryptographic test
if (errors.isEmpty()) {
testKeyPairFunctionality(keyPair, errors);
}
} catch (Exception e) {
errors.add("Validation failed with exception: " + e.getMessage());
}
return new ValidationResult(errors, warnings);
}
/**
* Validate RSA key pair
*/
private void validateRSAKeyPair(RSAPublicKey publicKey, RSAPrivateKey privateKey, 
List<String> errors, List<String> warnings) {
// Check key sizes
int keySize = publicKey.getModulus().bitLength();
if (keySize < 2048) {
errors.add("RSA key size too small: " + keySize + " bits (minimum 2048)");
} else if (keySize < 3072) {
warnings.add("RSA key size " + keySize + " bits is below NIST recommended 3072 bits");
}
// Check public exponent
if (!publicKey.getPublicExponent().equals(RSAPublicKeySpec.F4)) {
warnings.add("RSA public exponent is not 65537 (F4)");
}
// Check modulus properties
if (!publicKey.getModulus().isProbablePrime(100)) {
errors.add("RSA modulus is not prime");
}
// Verify public/private key relationship
try {
if (!publicKey.getModulus().equals(privateKey.getModulus())) {
errors.add("RSA public and private key moduli do not match");
}
} catch (Exception e) {
errors.add("Failed to verify RSA key relationship: " + e.getMessage());
}
}
/**
* Validate EC key pair
*/
private void validateECKeyPair(ECPublicKey publicKey, ECPrivateKey privateKey, 
List<String> errors, List<String> warnings) {
// Check curve strength
int fieldSize = publicKey.getParams().getCurve().getField().getFieldSize();
if (fieldSize < 256) {
errors.add("EC key curve too weak: " + fieldSize + " bits (minimum 256)");
}
// Verify public key is on curve
try {
if (!isPointOnCurve(publicKey)) {
errors.add("EC public key point is not on the curve");
}
} catch (Exception e) {
errors.add("Failed to validate EC point: " + e.getMessage());
}
// Check private key range
if (privateKey.getS().signum() <= 0) {
errors.add("EC private key is not positive");
}
}
/**
* Validate DSA key pair
*/
private void validateDSAKeyPair(DSAPublicKey publicKey, DSAPrivateKey privateKey, 
List<String> errors, List<String> warnings) {
int keySize = publicKey.getParams().getP().bitLength();
if (keySize < 2048) {
errors.add("DSA key size too small: " + keySize + " bits (minimum 2048)");
}
// Verify parameter consistency
if (!publicKey.getParams().equals(privateKey.getParams())) {
errors.add("DSA public and private key parameters do not match");
}
}
/**
* Basic validation checks
*/
private void validateNotNull(KeyPair keyPair, List<String> errors) {
if (keyPair == null) {
errors.add("Key pair is null");
return;
}
if (keyPair.getPublic() == null) {
errors.add("Public key is null");
}
if (keyPair.getPrivate() == null) {
errors.add("Private key is null");
}

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper