Java Cryptography Architecture (JCA) / Java Secure Socket Extension (JSSE)

Java Security

Java Cryptography Architecture (JCA)

JCA is a component of Java SE which provides a variety of cryptographic services. JCA uses a provider-based (i.e. plugins) architecture. The used security provider can be configured in the java.security file, located in $JAVA_HOME/conf/security/java.security.

Computing a Hash

import java.security.MessageDigest;

MessageDigest md = MessageDigest.getInstance("SHA3-256");
byte[] hash = md.digest("Hello World!".getBytes());

// which is equivalent to:

md.update((byte) 'H');
md.update("ello World!".getBytes());

Random Number Generation

import java.security.SecureRandom;

SecureRandom sr = SecureRandom.getInstanceStrong(); // or just new SecureRandom();
byte[] randomBytes = new byte[16];
sr.nextBytes(randomBytes);

By default, it uses the random source provided by the operating system. If the operating system does not provide a secure random source, it uses SHA1PRNG or DRGB, which is a cryptographically secure pseudo-random number generator (CSPRNG).

Secret Key Generation

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // 128, 192 or 256
SecretKey key = keyGen.generateKey();

Secret Key Cryptography

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

byte[] keyBytes = "0123456789abcdef".getBytes(); // very much secure, nobody can guess this key
SecretKey key = new SecretKeySpec(keyBytes, "AES");

Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
// cipher.update("Hello World!".getBytes());
byte[] encrypted = cipher.doFinal("Hello World!".getBytes());

It's important to call 'doFinal' to finsh the encryption, even if no new data is appended (to ensure data is padded correctly). Also, don't use ECB mode and don't use secret key cryptography without integrity protection.

Algorithms

  • Insecure Hashing Algorithms include: MD5, SHA-1, SHA-256, SHA-384, SHA-512
  • Secure Hashing Algorithms include: SHA3-256, SHA3-384, SHA3-512

Public Key Cryptography

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.ECGenParameterSpec;

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();

Signature signature = Signature.getInstance("SHA512withRSA");
signature.initSign(privateKey);
signature.initVerify(publicKey);

signature.update("Hello World!".getBytes());
byte[] signatureBytes = signature.sign();

signature.update("Hello World!".getBytes());
boolean valid = signature.verify(signatureBytes);

Java Secure Socket Extension (JSSE)

Provides support for the SSL/TLS protocol, cryptographic algorithms provided by the JCA.

SSL Socket

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

SSLServerSocketFactory sslServerSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(8000);
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();

To manage the key pairs, Java uses keystores and truststores. Keystores contain both public and private keys, truststores only contain public keys/certificates. They can be created using the keytool command line tool.

keytool -genkeypair -alias mykey -keyalg RSA -keysize 2048 -keystore keystore.jks -storepass mypass

# Export the certificate
keytool -export -alias mykey -keystore keystore.jks -storepass mypass -file mykey.cer
keytool -printcert -file mykey.cer

# Run a java program with the certificate
java -Djavax.net.ssl.keyStore=keystore.jks -Djavax.net.ssl.keyStorePassword=mypass MyServer

# And on client side (only using a trust store)
java -Djavax.net.ssl.trustStore=truststore.jks -Djavax.net.ssl.trustStorePassword=mypass MyClient

To dynamically load the keystore on server side, use the following code:

KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream("keystore.p12"), "mypass".toCharArray());

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX");
keyManagerFactory.init(keyStore, "mypass".toCharArray());