Do you know RSA and AES encryption well enough?

I bet you never went through AES and RSA like this before

Varsha Das
Javarevisited
10 min readFeb 7, 2024

--

Photo by Towfiqu barbhuiya on Unsplash

I recently switched to a fintech company where I have to heavily use Java cryptography. I have to work on a lot of RSA and AES key encryption techniques, specifically. (I have never worked on anything like this before, so it was really outside of my comfort zone.)

While doing so, I became aware of how much we take this topic for granted and how little effort we put into truly understanding the value behind each line of code. For instance, there is a standard set of lines of code that we write to encrypt a message, but we never really stop to consider what those lines actually mean.
Because I had to use some complex encryption and decryption logic for my workloads, I unintentionally ended up discovering a lot of ‘hows’ and ‘whys’ while working on my project.

For example, why Base64 encoding is being used, what role does padding play in encryption, why RSA is used in digital signatures, how to transmit an AES key and so on.

But is it just limited to someone’s domain use only? These concepts are not only important because one works in fintech or wants to work in fintech, but knowing about Java cryptography can help strengthen the security of various applications across diverse industries. Whether you’re developing software for healthcare, e-commerce, or any sector handling sensitive information, a solid understanding of Java cryptography ensures that your data remains confidential and secure.

Hence, I’ve attempted to break down most of the things along the way and share whatever I have learned so far, thus simplifying some of the most commonly used operations.

What will your key takeaways be?

Gain a comprehensive understanding of RSA and AES to establish a solid groundwork in Java cryptography.

If you’re actively involved in encryption and decryption tasks, consider this article as a valuable reference for the standard code snippets.

If you are generally curious to learn something new, you might find this worth-reading.

Revisiting key concepts before interviews.

Let’s start by setting some context on RSA and AES and then discuss the code snippets.

What is RSA encryption?

Asymmetric algorithm, widely used for secure data transmission, digital signatures, and key exchange. Unlike symmetric-key algorithms, RSA uses a pair of keys: one for encryption (public key) and one for decryption (private key).

Credits : https://sectigostore.com

What is a Symmetric key?

Symmetric -Single Key for Encryption and Decryption

This means that the parties involved in the communication share the same secret key. The main challenge in symmetric key cryptography is securely distributing and managing the secret key among communicating parties. If a third party gains access to the key, they can decrypt the messages.

Algorithms: Common symmetric key algorithms include AES (Advanced Encryption Standard), DES (Data Encryption Standard), and 3DES (Triple DES).

Credits — ssl2buy.com

What is Asymmetric Key Encryption?

Involves a pair of keys — a public key for encryption and a private key for decryption. Information encrypted with the public key can only be decrypted with the corresponding private key.

Addresses the key distribution challenge in symmetric key encryption since the public key can be openly shared.

Algorithms: Common asymmetric key algorithms include RSA (Rivest–Shamir–Adleman), DSA (Digital Signature Algorithm).

Credits — ssl2buy.com

What is AES Encryption?

AES stands for Advanced Encryption Standard. It is a symmetric key algorithm, meaning the same key is used for both encryption and decryption. The security of AES relies on keeping the key secret.

AES supports key sizes of 128, 192, or 256 bits. The larger the key size, the stronger the encryption. For example, AES-128 uses a 128-bit key, AES-192 uses a 192-bit key, and AES-256 uses a 256-bit key.

Credits — wallarm.com

What is the significance of a digital signature and how RSA plays a role in it?

A digital signature is a cryptographic technique used to verify the authenticity and integrity of a message or document. It involves the use of a private key to generate a signature and a corresponding public key to verify that signature. The process typically uses asymmetric key algorithms, like RSA, where one key is used for signing (a private key) and the other for verification (a public key).

The recipient, using the sender’s public key, can verify the signature by applying a corresponding mathematical operation on the received message’s hash. If the generated signature matches the received signature, the message is considered authentic.

Credits — techterms

Now, let’s discuss the Java code snippets to do some of the common operations.

1. How do I generate an RSA key pair?

public class RSAKeyPairGenerator {

public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048); // Adjust key size as needed
return keyPairGenerator.generateKeyPair();
}

public static void main(String[] args) throws NoSuchAlgorithmException {
KeyPair keyPair = generateKeyPair();
System.out.println("RSA Public Key: " + keyPair.getPublic());
System.out.println("RSA Private Key: " + keyPair.getPrivate());
}
}

In RSA, the key size is typically expressed in bits, and common key sizes include 1024 bits, 2048 bits, and 3072 bits.

The security of a cryptographic system depends on the computational effort required to break the encryption. As computational power increases, larger key sizes become necessary to maintain a desired level of security, but also adds up in complexity.

You can also do this online : https://cryptotools.net/rsagen

2. How do I convert a string to a public key and vice versa?

Why is this important?

Public keys, especially in Java, are often represented as objects (e.g., instances of the PublicKey class). When you need to transmit or store a public key, it's common to convert it into a string format for easier handling, transmission, or storage. (SERIALIZATION)

1. Converting the public key to a string makes it easier to include in HTTP requests or responses, where strings are a more natural data format.

2. A string representation of the public key, often encoded in Base64, is more versatile and platform-independent compared to a raw binary format. The Base64 encoding provides a compact and human-readable representation of the public key. This can be helpful for debugging or logging purposes.


public class StringToPublicKeyConverter {

public static PublicKey convertStringToPublicKey(String publicKeyString) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(publicKeyString);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(keySpec);
}

public static String convertPublicKeyToString(PublicKey publicKey) {
return Base64.getEncoder().encodeToString(publicKey.getEncoded());
}

public static void main(String[] args) throws Exception {
KeyPair keyPair = RSAKeyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();

// Convert public key to string
String publicKeyString = convertPublicKeyToString(publicKey);
System.out.println("Public Key String: " + publicKeyString);

// Convert string back to public key
PublicKey convertedPublicKey = convertStringToPublicKey(publicKeyString);
System.out.println("Converted Public Key: " + convertedPublicKey);
}
}

X.509 is a standard that defines the format of public key certificate.

The X509EncodedKeySpec class in Java is part of the java.security.spec package and is used to represent the key specifications of an X.509-encoded public key. This class is typically used when you have an X.509-encoded public key in a byte array, and you want to convert it into a PublicKey object.

3. How do I load a public and private key from a file?

Often times, you may have to load the public and private keys from a secure location and use them in the code.


public class KeyLoader {

public static PublicKey loadPublicKey(String filePath) throws Exception {
byte[] keyBytes = Files.readAllBytes(Paths.get(filePath));
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(keySpec);
}

public static PrivateKey loadPrivateKey(String filePath) throws Exception {
byte[] keyBytes = Files.readAllBytes(Paths.get(filePath));
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
}

public static void main(String[] args) throws Exception {
// Load public key from file
PublicKey publicKey = loadPublicKey("path/to/publicKey.pem");
System.out.println("Loaded Public Key: " + publicKey);

// Load private key from file
PrivateKey privateKey = loadPrivateKey("path/to/privateKey.pem");
System.out.println("Loaded Private Key: " + privateKey);
}
}

The PKCS8EncodedKeySpec class in Java, part of the java.security.spec package, represents the key specifications of a private key encoded in PKCS #8 format. This class is used when you have a private key in a byte array and you want to convert it into a PrivateKey object.

Time for the announcement:

If you’re liking what you’re reading, you’re going to love what I have in store for you on my YouTube channel.

We’re providing a range of exclusive perks, such as virtual video collaborations, member-only polls, premium content only for our members, and so much more.

In the context of this article, our exclusive videos will guide you through all the essential aspects of system design, deep-dive into the components, offer extra insights into math concepts, share valuable tips, and provide actionable strategies that can strengthen your System design skills.

Who am I?

Across 7 years, I have led projects on AWS, Java, Spring Boot, Kafka, ELK stack, Splunk, Apache Mesos, etc, optimizing systems for cost-effectiveness, achieving savings of up to 30% , reduced latency by 50% through performance tuning techniques, and enabled systems to handle a higher volume of transactions.

So, I am quite certain you can rely on my expertise.

In addition to that, we will also have videos dedicated to common interview questions about Java threads and concurrency, detailed plans for Spring Boot projects, and plenty of project ideas. All this special content is just for you!

As you support our channel, join our expanding community and get access to things you won’t find anywhere else.

To become a valued member right now, click this link.

4. How do I do RSA encryption?

public class RSAEncryptionExample {

public static String encrypt(String plainText, Key key) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
}

public static String decrypt(String encryptedText, Key key) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
return new String(decryptedBytes);
}

public static void main(String[] args) throws Exception {
KeyPair keyPair = RSAKeyPairGenerator.generateKeyPair();
String plainText = "Hello, RSA Encryption!";

// Encrypt using the public key
String encryptedText = encrypt(plainText, keyPair.getPublic());
System.out.println("Encrypted Text: " + encryptedText);

// Decrypt using the private key
String decryptedText = decrypt(encryptedText, keyPair.getPrivate());
System.out.println("Decrypted Text: " + decryptedText);
}
}

The encrypted byte array is encoded into a Base64-encoded string using the Base64 class. This step is often done to represent the encrypted binary data in a format that is suitable for text-based transmission or storage.

5. How do I securely transmit an AES key using RSA encryption?

The RSA algorithm is often used for key exchange because it allows a user to securely send a secret key to another party over an insecure channel. The RSA key pair consists of a public key, which can be freely distributed, and a private key, which must be kept secret.

By encrypting the AES key with the recipient’s RSA public key, the confidentiality of the key is maintained during transmission. Even if an attacker intercepts the encrypted key, they will need the private key of the recipient to decrypt it.

In a real-world scenario, you would transmit the encrypted AES key securely to the other party, and for decryption, they would use the corresponding RSA private key.


public class RSAKeyEncryptionExample {

public static byte[] encryptAESKeyWithRSA(PublicKey publicKey, SecretKey aesKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(aesKey.getEncoded());
}

public static SecretKey generateAESKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256, new SecureRandom());
return keyGenerator.generateKey();
}

public static void main(String[] args) {
try {
// Generate RSA key pair
KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();

// Generate AES key
SecretKey aesKey = generateAESKey();

// Encrypt AES key with RSA public key
byte[] encryptedAESKey = encryptAESKeyWithRSA(publicKey, aesKey);

String encryptedAESKeyBase64 = java.util.Base64.getEncoder().encodeToString(encryptedAESKey);

System.out.println("Original AES Key: " + java.util.Base64.getEncoder().encodeToString(aesKey.getEncoded()));
System.out.println("Encrypted AES Key (Base64): " + encryptedAESKeyBase64);

} catch (Exception e) {
e.printStackTrace();
}
}
}

This line :

Cipher cipher = Cipher.getInstance(“RSA/ECB/OAEPWithSHA-256AndMGF1Padding”);

might seem a little new to you.

Let me break it down and talk more about padding schemes here.

Padding is crucial in RSA encryption to ensure the security and reliability of the encryption process. Padding introduces a random component, making it less likely that an attacker can gather information from repeated encryption of the same plaintext.

  1. Algorithm: RSA — Specifies the RSA encryption algorithm.
  2. Mode: ECB (Electronic Codebook) - In the context of RSA, the mode is often set to Electronic Codebook, even though RSA doesn't technically have different modes like block ciphers. It's essentially ignored in the RSA context.
  3. Padding Scheme: OAEPWithSHA-256AndMGF1Padding - This part specifies the padding scheme used with RSA. In this case, it's OAEP (Optimal Asymmetric Encryption Padding) with SHA-256 as the hash function and MGF1 (Mask Generation Function 1) with the same SHA-256 as the mask generation function.

Two commonly used padding schemes for RSA are:

  1. PKCS#1 v1.5 Padding
  2. OAEP (Optimal Asymmetric Encryption Padding): is a more secure padding scheme for RSA. It introduces randomness to the plaintext before encryption, making it less susceptible to certain attacks. It involves a hash function (e.g., SHA-256) and a mask generation function (MGF1).

So, that’s all for today.

Thanks for reading.

If you liked this article, please click the “clap” button 👏 a few times.

It gives me enough motivation to put out more content like this. Please share it with a friend who you think this article might help.

Connect with me — Varsha Das | LinkedIn

If you’re seeking personalized guidance in software engineering, career development, core Java, Systems design, or interview preparation, let’s connect here.

Rest assured, I’m not just committed; I pour my heart and soul into every interaction. I have a genuine passion for decoding complex problems, offering customised solutions, and connecting with individuals from diverse backgrounds.

Follow my Youtube channel — Code With Ease — By Varsha, where we discuss Java & Data Structures & Algorithms and so much more.

Subscribe here to receive alerts whenever I publish an article.

Happy learning and growing together.

--

--

Varsha Das
Javarevisited

"Senior Software Engineer @Fintech | Digital Creator @Youtube | Thrive on daily excellence | ❤️ complexity -> clarity | Devoted to health and continuous growth