Can Your Java Cryptography Architecture Survive a Quantum Attack?

cover
27 Jun 2024

It's the 2030s, and what experts were saying along the way has come true! Yes, from the 2019 Google article to reality, a quantum computer is ready to take on any and all encryptions. Will your Java Cryptography Architecture(JCA) survive on that doomsday?


Source

You have six years to figure that out. So first, you need to understand JCA and how to survive until the 2030s.

Quantum computing can do more than break encryptions. However, anyone who knows cryptography encryption knows it has been around too long to be discounted.

But are encryptions invincible?

Not really!

So,what can you do anyway?

There are specific aspects of a JCA that you can optimize for better web app protection. What they are and the best practices you can follow are included in this article!

First, let me introduce the survivor - JCA!

Java Cryptographic Architecture(JCA)- The Survivor!

JCA is a framework for developers working with cryptography in the Java programming language. It is part of the Java security API introduced with JDK 1.1. However, if you are well-versed in Java, this is familiar!

Java Cryptographic Architecture is structured with general-purpose classes and interfaces at its center. It is one of the Java frameworks for web app security, including Java Authentication and Authorization Service (JAAS) and Java Cryptography Extensions (JCE).

Here, the real heroes for you are “Providers.” These providers offer actual functionality behind all the architecture interfaces. For example, if you want to encrypt or decrypt the data, you will use the “Cipher” class. However, implementing the encryption algorithm is not possible without a provider.

The best part is that you get to implement your providers, too! However, this is also where it gets tricky.

Implementing the encryption correctly becomes crucial, or you may expose a vulnerability to attackers. So, if you are new to this, use the default provider, which comes with built-in Java.

Java packages with cryptography API:

  • java. security
  • java.security.cert
  • java.security.spec
  • java.security.interfaces
  • javax.crypto
  • javax.crypto.spec
  • javax.crypto.interfaces

The core classes and interfaces for JCA are:

  • Provider
  • SecureRandom
  • Cipher
  • MessageDigest
  • Signature
  • Mac
  • AlgorithmParameters
  • AlgorithmParameterGenerator
  • KeyFactory
  • SecretKeyFactory
  • KeyPairGenerator
  • KeyGenerator
  • KeyAgreement
  • KeyStore
  • CertificateFactory
  • CertPathBuilder
  • CertPathValidator
  • CertStore

You know the components of JCA listed above, and here is a brief introduction to each of them.

Key Components of JCA

Think of it as a grand Hollywood story like Avengers, but for JCA, there are several vital components. When these components assemble, they form an architecture that offers robust cryptography.

Captain “Provider”

Mr. Dependable, our captain, “Provider (java.security.Provider),” is a class central to the Java cryptography API.

Source

The best part about any Java cryptography API is the default provider, which does not require developers to add their own provider.

But like every superhero, this one, too, has its kryptonite! Yes, the issue with the default provider is compatibility with the encryption algorithms.

It may only support some of the algorithms you want to use for encryptions. So, the best practice is to use your provider. \

Here is an example,

import org. bouncy castle.jce.provider.BouncyCastleProvider;\
import java.security.Security;\
public class ProviderExample {
public static void main(String[] args) {Security.addProvider(new BouncyCastleProvider());\}}

Cipher Man

With a web of encryptions, the cipher class is your cryptographic algorithm. Yes, “Cipher (javax.crypto.Cipher)” is the class that allows you to encrypt and decrypt data. The cipher class is used by first creating an instance.

Source

You can create the cipher instance by calling the getInstance() method with a parameter. This parameter defines the encryption algorithm you want to use to encrypt the data.

Here is how you can create a cipher: Cipher cipher = Cipher.getInstance("AES");

However, before you use a cipher instance, you will have to initialize it through the following command for encryptions,

Key key = ... // get / create symmetric encryption key
cipher.init(Cipher.ENCRYPT_MODE, key);

Similarly, you can use the following command for decryptions,

Key key = ... // get / create symmetric encryption key
cipher.init(Cipher.DECRYPT_MODE, key);

Another critical element of a cipher is the mode. Yes, cipher modes define how an encryption algorithm should encrypt the data. You can consider cipher modes as an add-on appended to the encryption algorithm's name.

If you initiate a cipher, its mode becomes essential. However, it is crucial to note that the default provider does not support all cipher modes and algorithms.

Data Encryptions and Decryptions in JCA

Now that your Cipher(AKA Iron) man is initiated, it’s time to execute the mission- Encryption!

Call Cipher update() or doFinal()methods to start the encryption process. You can use update() method to encrypt or decrypt huge pieces of data. This is especially useful for social media and eCommerce web application security.

Next, you can use a method to encrypt or decrypt a small part of that massive data. This is important, especially when you are looking to encrypt specific data. If you want to decrypt the data, you can use the cipher text used in encryption and pass it on to the doUpdate() method.

Now you have the captain and Ironman ready, it’s time to get the keys!

Keys to the Mission!

As you know, encryption and decryption are not possible without security keys. Two main types of security keys are used: public and private.

The type of encryption is determined by which key you use for encryption or decryption. If you use the same key for encryption and decryption, it's symmetric.

Similarly, it's asymmetric encryption if you use different keys for encryption and decryption. Now, if you are the receiver of the encrypted data, having a decryption key with you is crucial.

In any scenario, you and the data's encryption must have the same security key or exchange keys to access information. This means keys are crucial to encryptions and decryptions. So, how can you generate keys?

You can use the KeyGenerator class to generate security keys in Java. First, create a KeyGenerator instance calling the static method getInstance(), passing it as a parameter in the name of the encryption algorithm.

KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");

Like the encryption process, once the instance is ready, initiate key generation using the following command.

SecureRandom secureRandom = new SecureRandom();

int keyBitSize = 256;

keyGenerator.init(keyBitSize, secureRandom);

Lastly, call the KeyGenerator generateKey()method to generate keys.

SecretKey secretKey = keyGenerator.generateKey();

When you pass the Secretkey to Cipher.init(), you will be able to encrypt the data. However, you will need a key pair if you use an asymmetric encryption type. In the earlier section, I showed how you can create a security key that you can use for both encryption and decryption. However, for asymmetric encryption, you need one private and one public key.

Java Keypair Forever!

Forget Wakanda; you need a moonlight with one public and a private key! To generate a key pair for asymmetric encryption, use KeyPairGenerator (java.security.KeyPairGenerator).\

Source

SecureRandom secureRandom = new SecureRandom();

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");\
KeyPair keyPair = keyPairGenerator.generateKeyPair();

Keystore And Keytool

In Java, a keystore is a database that stores keys after you generate them. This database is defined by the KeyStore (java.security.KeyStore) class. At the same time, a Keytool is basically a command-line tool that you can use with the KeyStore files. It can generate key pairs into the KeyStore file and export and import certificates.

MessageDigest(Hash)

When you send data to the receiver, they should be able to determine whether information is tampered with. This is possible through a MessageDIgest or hash value. Attach a hash value to the file and encrypt both of them.

When the receiver ties and decrypts the file, a hash value is calculated and matched with the encrypted one. If it matches without a single change in the data byte, your information is not tampered with.

How to use this MessageDigest

It’s simple: Just use the MessageDigest (java.security.MessageDigest) to calculate message digests. Call the MessageDigest.getInstance() method to create the instance and initiate the hash algorithm. Be mindful of mentioning the algorithm you want to use for hashing while creating the instance.

Here is an example of creating the hash value,

MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");

Signing The Data

You can use the Signature (java.security.Signature)  class to sign data digitally. The hash value is crucial for digital signature. Every digital signature is created by first calculating the MessageDigest or hash value. Once calculated, it is encrypted with the device's private key and other files.

An encrypted hash value is your digital signature. Simply call the Signature.getInstance(...)  to create a Signature instance and complete the signing process.

To verify the signature, you can call initVerify(...)  method, where a public key is used for verification of the digitally signed data.

Signature signature = Signature.getInstance("SHA256WithDSA");

signature.initVerify(keyPair.getPublic());

The above code will initialize the verification, and to execute it, you have to call the update() method. Finish the call to vetify(), which will provide a response that is true or false based on the verification status.

So, all your Avengers are here, and SHIELD(Digital Signature) is ready to defend. But what if you meet an adversary like Thanos(Log4J)? Well, here are some practices to follow for the right endgame!

Best Practices for Java Cryptography Architecture

When you think of best practices or even search for them online, you will mostly find instructions on how to create secure Java code. But you need JCA best practices. Trust me, when I was searching for them, I, too, got the same results.

So, here is what I could get from peers, experts in the JCA plus some research on Reddit.

Master Key Security

Security keys, whether public or private, need to be secure while stored in the KeyStore. One way to ensure security is using HSM(Hardware Security Module). Storing your keys in HSM is the best option for key security management.

Make Sure You Get the Provider Right!

By now, you know that not all the default providers support all the algorithms. So, you need to use your provider for better compatibility and effective encryption. If Java Cryptography Architecture does not support the algorithm you aim to use for encryptions, your web apps can be at risk.

Choose Secure Algorithms

When you select cryptographic algorithms for your Java application, choose a secure one. You need to choose a widely compatible, well-tested algorithm that maintains industry standards. There are many options, such as AES, RSA, and SHA-256.

Use Secure Random Number Generation

You can use the SecureRandom class to generate high-quality random numbers. You can use random numbers to create keys, initiate vectors, and other cryptography elements.

Here is a simple example of how you can use SecureRandom in Java cryptography:\

Import java.security.SecureRandom;

public class RandomNumberExample {\
public static void main(String[] args) {
SecureRandom random = new SecureRandom();
byte[] randomBytes = new byte[16];
random.nextBytes(randomBytes);\
System.out.println("Random number: " + byteArrayToHexString(randomBytes));}
private static String byteArrayToHexString(byte[] array) {
StringBuilder sb = new StringBuilder();
for (byte b : array) {sb.append(String.format("%02X", b));}return sb.toString();}}

The End!

Yes, it’s the end of this superhero tale! JCA is truly your security superhero if you can get its components right. Getting the right algorithm and compatible provider, as well as managing the security keys is crucial to ensuring JCA security. And before you think this will not last against an AI-powered quantum computer—“you never know!”

However, what you can ensure by using the above practices is security from most of the cyber threats in the current era. So, leverage these best practices and get your JCA ready for the infinity war.