CODE WITH SIBIN

Solving Real Problems with Real Code


How to Implement AES & RSA Dual-Layer Security in Java

Concept

This security approach combines AES (symmetric encryption) and RSA (asymmetric encryption) to leverage the strengths of both algorithms:

  1. AES (Advanced Encryption Standard):
    • Fast symmetric encryption for bulk data
    • Uses the same key for encryption and decryption
    • Strong (especially with 256-bit keys)
    • Problem: Secure key exchange is challenging
  2. RSA (Rivest-Shamir-Adleman):
    • Asymmetric encryption for secure key exchange
    • Uses public/private key pairs
    • Slow for large data but perfect for encrypting small items like keys
    • Solves the key exchange problem

How the Double Layer Works

Encryption Process:

  1. Generate a random AES key (session key)
  2. Encrypt your data with AES (fast, efficient encryption)
  3. Encrypt the AES key with RSA using the recipient's public key
  4. Send both the RSA-encrypted AES key and AES-encrypted data

Decryption Process:

  1. Decrypt the AES key using your RSA private key
  2. Decrypt the data using the retrieved AES key

Why This Combination is Powerful

AspectAES AloneRSA AloneAES+RSA Combo
Speed for large dataFastVery SlowFast
Key exchangeProblemSolutionSolved
SecurityStrongStrongVery Strong
Practical useLimitedLimitedIdeal

Typical Use Cases

  • Secure file transfer systems
  • Encrypted messaging applications
  • Secure data storage solutions
  • Hybrid cryptosystems (like SSL/TLS)

Security Advantages

  1. Perfect forward secrecy - Each session uses a new AES key
  2. Efficient encryption - Only the small key uses slow RSA
  3. Secure key distribution - No need to pre-share AES keys
  4. Defense in depth - Even if one layer is compromised, the other provides protection

This combination is similar to what's used in SSL/TLS protocols, where symmetric encryption handles the bulk data encryption while asymmetric encryption manages the secure key exchange.

Implementation

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.util.Base64;

public class DoubleLayerSecurity {

    // AES Configuration
    private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";
    private static final int AES_KEY_SIZE = 256; // 128, 192, or 256
    private static final int IV_SIZE = 16; // 16 bytes for AES

    // RSA Configuration
    private static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
    private static final int RSA_KEY_SIZE = 2048; // 1024, 2048, or 4096

    /**
     * Generate AES Secret Key
     */
    public static SecretKey generateAesKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(AES_KEY_SIZE);
        return keyGenerator.generateKey();
    }

    /**
     * Generate RSA Key Pair
     */
    public static KeyPair generateRsaKeyPair() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(RSA_KEY_SIZE);
        return keyPairGenerator.generateKeyPair();
    }

    /**
     * Encrypt data with AES
     */
    public static String encryptAes(String plainText, SecretKey secretKey) throws Exception {
        byte[] iv = new byte[IV_SIZE];
        new SecureRandom().nextBytes(iv);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);

        byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        
        // Combine IV + encrypted data
        byte[] combined = new byte[iv.length + encrypted.length];
        System.arraycopy(iv, 0, combined, 0, iv.length);
        System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);

        return Base64.getEncoder().encodeToString(combined);
    }

    /**
     * Decrypt data with AES
     */
    public static String decryptAes(String encryptedText, SecretKey secretKey) throws Exception {
        byte[] combined = Base64.getDecoder().decode(encryptedText);
        
        // Extract IV
        byte[] iv = new byte[IV_SIZE];
        System.arraycopy(combined, 0, iv, 0, iv.length);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
        
        // Extract encrypted data
        byte[] encrypted = new byte[combined.length - IV_SIZE];
        System.arraycopy(combined, IV_SIZE, encrypted, 0, encrypted.length);

        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);

        byte[] decrypted = cipher.doFinal(encrypted);
        return new String(decrypted, StandardCharsets.UTF_8);
    }

    /**
     * Encrypt AES key with RSA public key
     */
    public static String encryptRsa(byte[] data, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encrypted = cipher.doFinal(data);
        return Base64.getEncoder().encodeToString(encrypted);
    }

    /**
     * Decrypt AES key with RSA private key
     */
    public static byte[] decryptRsa(String encryptedData, PrivateKey privateKey) throws Exception {
        byte[] data = Base64.getDecoder().decode(encryptedData);
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * Full encryption process:
     * 1. Generate random AES key
     * 2. Encrypt data with AES
     * 3. Encrypt AES key with RSA public key
     * Returns: encrypted AES key (RSA) + encrypted data (AES)
     */
    public static String[] fullEncrypt(String plainText, PublicKey publicKey) throws Exception {
        // Generate AES key
        SecretKey aesKey = generateAesKey();
        
        // Encrypt data with AES
        String encryptedData = encryptAes(plainText, aesKey);
        
        // Encrypt AES key with RSA
        String encryptedAesKey = encryptRsa(aesKey.getEncoded(), publicKey);
        
        return new String[]{encryptedAesKey, encryptedData};
    }

    /**
     * Full decryption process:
     * 1. Decrypt AES key with RSA private key
     * 2. Decrypt data with AES key
     */
    public static String fullDecrypt(String encryptedAesKey, String encryptedData, PrivateKey privateKey) throws Exception {
        // Decrypt AES key
        byte[] decryptedAesKey = decryptRsa(encryptedAesKey, privateKey);
        SecretKey aesKey = new SecretKeySpec(decryptedAesKey, 0, decryptedAesKey.length, "AES");
        
        // Decrypt data
        return decryptAes(encryptedData, aesKey);
    }

    public static void main(String[] args) throws Exception {
        // Generate RSA key pair
        KeyPair keyPair = generateRsaKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();

        // Original message
        String originalMessage = "This is a secret message that needs double layer security!";
        System.out.println("Original: " + originalMessage);

        // Encrypt
        String[] encrypted = fullEncrypt(originalMessage, publicKey);
        System.out.println("Encrypted AES Key (RSA): " + encrypted[0]);
        System.out.println("Encrypted Data (AES): " + encrypted[1]);

        // Decrypt
        String decryptedMessage = fullDecrypt(encrypted[0], encrypted[1], privateKey);
        System.out.println("Decrypted: " + decryptedMessage);
    }
}

Explanation

  1. AES Encryption:
    • Used for encrypting the actual data (symmetric encryption)
    • Fast and efficient for large amounts of data
    • Uses CBC mode with PKCS5Padding
    • Includes a random IV for each encryption
  2. RSA Encryption:
    • Used for encrypting the AES key (asymmetric encryption)
    • Secure key exchange
    • Slower but good for small amounts of data (like keys)
  3. Double Layer Security Flow:
    • Generate a random AES key for each session/message
    • Encrypt the data with AES
    • Encrypt the AES key with RSA using the recipient's public key
    • Send both the encrypted AES key and encrypted data
    • Recipient uses their private key to decrypt the AES key
    • Recipient uses the AES key to decrypt the data

Security Considerations

  1. Always use strong key sizes (256-bit for AES, 2048-bit or higher for RSA)
  2. Never reuse IVs for AES in CBC mode
  3. Store private keys securely
  4. Consider adding HMAC for message authentication
  5. In production, use established protocols like TLS instead of rolling your own

This implementation provides a good balance between security and performance by combining the strengths of both symmetric and asymmetric encryption.

Leave a Reply

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