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());