Part 13 of 16

Security: TLS 1.3, ChaCha20-Poly1305, and Curve25519 (JEP 329, 332, 324)

Security Improvements Across Java 9–11

JEPReleaseFeature
JEP 287Java 9SHA-3 hash algorithms
JEP 273Java 9DRBG-based SecureRandom
JEP 288Java 9Disable SHA-1 certificates
JEP 324Java 11Key Agreement with Curve25519 and Curve448
JEP 329Java 11ChaCha20 and Poly1305 cryptographic algorithms
JEP 332Java 11Transport Layer Security (TLS) 1.3
JEP 181Java 11Nest-Based Access Control

TLS 1.3 (JEP 332)

TLS 1.3 is the current version of the Transport Layer Security protocol, finalised in RFC 8446 (August 2018). Java 11 delivers a complete implementation in JSSE (Java Secure Socket Extension).

What changed vs TLS 1.2

AspectTLS 1.2TLS 1.3
Handshake round trips2 RTT1 RTT (0-RTT for resumed sessions)
Cipher suitesMany (including weak ones)5 strong suites only
Key exchangeRSA key exchange (vulnerable)Only forward-secret ECDHE/DHE
Signature algorithmsMD5, SHA-1SHA-256 minimum
Session resumptionTicket-basedPSK (pre-shared key) based
Forward secrecyOptionalMandatory

TLS 1.3 eliminates several known-weak options that TLS 1.2 still supported (RC4, DES, 3DES, MD5, SHA-1 signatures, RSA key exchange without PFS).

TLS 1.3 in Java 11 — what is supported

  • All five TLS 1.3 cipher suites:
    • TLS_AES_128_GCM_SHA256
    • TLS_AES_256_GCM_SHA384
    • TLS_CHACHA20_POLY1305_SHA256
    • TLS_AES_128_CCM_SHA256
    • TLS_AES_128_CCM_8_SHA256
  • 1-RTT handshake
  • Session resumption (PSK)
  • 0-RTT is supported but disabled by default (replay attack risk)

Enabling and configuring TLS 1.3

By default, Java 11 negotiates TLS 1.3 when both client and server support it. No code changes are needed for most HTTPS clients and servers — the upgrade is automatic.

To force TLS 1.3 explicitly:

SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
sslContext.init(null, null, null);

SSLServerSocketFactory factory = sslContext.getServerSocketFactory();
SSLServerSocket server = (SSLServerSocket) factory.createServerSocket(8443);

// Restrict to TLS 1.3 and specify cipher suites
server.setEnabledProtocols(new String[]{"TLSv1.3"});
server.setEnabledCipherSuites(new String[]{
    "TLS_AES_256_GCM_SHA384",
    "TLS_CHACHA20_POLY1305_SHA256"
});

Using TLS 1.3 with HttpClient

var sslParams = new SSLParameters();
sslParams.setProtocols(new String[]{"TLSv1.3"});
sslParams.setCipherSuites(new String[]{
    "TLS_AES_256_GCM_SHA384",
    "TLS_CHACHA20_POLY1305_SHA256"
});

var client = HttpClient.newBuilder()
    .sslParameters(sslParams)
    .build();

Disabling TLS 1.0 and 1.1 system-wide

Edit $JAVA_HOME/conf/security/java.security:

# Disable TLS 1.0 and 1.1 (already partially restricted in Java 11)
jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, \
  DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL

Or set via system property at startup:

java -Djdk.tls.disabledAlgorithms="SSLv3,TLSv1,TLSv1.1,RC4,DES" -jar myapp.jar

ChaCha20 and Poly1305 (JEP 329)

ChaCha20-Poly1305 is a modern AEAD (Authenticated Encryption with Associated Data) cipher suite added to Java 11.

ChaCha20 vs AES-GCM

AspectAES-GCMChaCha20-Poly1305
TypeBlock cipher (with GCM mode)Stream cipher
Hardware accelerationAES-NI (Intel/AMD x64, ARM AES)None required
Software speedSlow without AES-NIConstant high speed
Nonce reuse riskCritical vulnerabilityLess catastrophic
TLS 1.3 suiteTLS_AES_128_GCM_SHA256TLS_CHACHA20_POLY1305_SHA256

When to prefer ChaCha20-Poly1305: on mobile devices, IoT hardware, or ARM servers without hardware AES acceleration. Without AES-NI, AES-GCM is 3–5× slower; ChaCha20 runs at the same speed regardless.

Using ChaCha20-Poly1305 in Java

// Stream cipher — encrypt
Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305");
byte[] nonce = new byte[12];
new SecureRandom().nextBytes(nonce);
IvParameterSpec ivSpec = new IvParameterSpec(nonce);

SecretKey key = new SecretKeySpec(keyBytes, "ChaCha20");
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] ciphertext = cipher.doFinal(plaintext);

// Decrypt
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
byte[] decrypted = cipher.doFinal(ciphertext);

Note: ChaCha20-Poly1305 is the AEAD variant (includes authentication tag). The raw ChaCha20 stream cipher is also available separately.


Curve25519 and Curve448 Key Agreement (JEP 324)

Java 11 adds Curve25519 and Curve448 for elliptic-curve Diffie-Hellman key agreement. These modern curves are used in TLS 1.3 and replace the older NIST curves (P-256, P-384) in contexts where their design assumptions are questioned.

Curve25519 characteristics

  • Designed by Daniel Bernstein (djb) in 2005
  • Fixed-time scalar multiplication — resistant to timing side-channel attacks
  • 128-bit security level
  • Used in TLS 1.3, SSH, WireGuard, Signal Protocol

Key agreement example

import java.security.*;
import java.security.spec.*;
import javax.crypto.*;

// Generate Curve25519 key pairs
KeyPairGenerator kpg = KeyPairGenerator.getInstance("X25519");
KeyPair aliceKP = kpg.generateKeyPair();
KeyPair bobKP   = kpg.generateKeyPair();

// Alice computes shared secret using her private key + Bob's public key
KeyAgreement aliceKA = KeyAgreement.getInstance("X25519");
aliceKA.init(aliceKP.getPrivate());
aliceKA.doPhase(bobKP.getPublic(), true);
byte[] aliceSecret = aliceKA.generateSecret();

// Bob computes shared secret using his private key + Alice's public key
KeyAgreement bobKA = KeyAgreement.getInstance("X25519");
bobKA.init(bobKP.getPrivate());
bobKA.doPhase(aliceKP.getPublic(), true);
byte[] bobSecret = bobKA.generateSecret();

// aliceSecret and bobSecret are equal
assert Arrays.equals(aliceSecret, bobSecret);

SHA-3 Hash Algorithms (JEP 287, Java 9)

Java 9 added SHA-3 (Secure Hash Algorithm 3) — the Keccak-based hash family standardised in FIPS 202. SHA-3 is the backup to SHA-2, designed to be structurally different so that a break in SHA-2 does not affect SHA-3.

// SHA-3 variants: SHA3-224, SHA3-256, SHA3-384, SHA3-512
MessageDigest md = MessageDigest.getInstance("SHA3-256");
byte[] hash = md.digest("Hello, Java 11".getBytes(StandardCharsets.UTF_8));

// Hex string
String hexHash = HexFormat.of().formatHex(hash);   // Java 17+
// For Java 11: use String.format or a loop
StringBuilder sb = new StringBuilder();
for (byte b : hash) sb.append(String.format("%02x", b));
System.out.println(sb);

// HMAC with SHA-3
Mac mac = Mac.getInstance("HmacSHA3-256");
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "HmacSHA3-256");
mac.init(secretKey);
byte[] hmac = mac.doFinal(data);

SHA-3 vs SHA-2 — when to use SHA-3

Use SHA-3 when:

  • Your security policy requires it (FIPS 202 compliance)
  • You want independence from SHA-2’s Merkle-Damgård construction
  • Integrating with systems that specify SHA-3

SHA-2 (SHA-256, SHA-512) is still the practical default — it is widely supported and has no known weaknesses.


DRBG-Based SecureRandom (JEP 273, Java 9)

Java 9 added DRBG (Deterministic Random Bit Generator) implementations to SecureRandom, as specified in NIST SP 800-90Ar1.

// Request a DRBG instance by name and strength
SecureRandom drbg = SecureRandom.getInstance("DRBG",
    DrbgParameters.instantiation(
        256,                              // security strength in bits
        DrbgParameters.Capability.PR_AND_RESEED,  // prediction resistance + reseeding
        "my-personalization".getBytes()  // optional personalisation string
    ));

byte[] randomBytes = new byte[32];
drbg.nextBytes(randomBytes,
    DrbgParameters.nextBytes(256, true, "additional-input".getBytes()));

DRBG instances are FIPS-compliant — use them when targeting FIPS 140-2/140-3 environments.


Nest-Based Access Control (JEP 181)

Nest-based access control is a JVM-level change (not a developer-facing API) that affects reflection behaviour and bytecode generation.

The pre-Java 11 problem

In Java 8, when a nested class accessed a private member of its enclosing class (or vice versa), the compiler silently generated package-private bridge methods:

class Outer {
    private int secret = 42;

    class Inner {
        void read() {
            System.out.println(secret);  // compiler generates a bridge method: access$000(Outer)
        }
    }
}

These synthetic bridge methods were visible in reflection, could be invoked by bytecode manipulation libraries, and added unnecessary overhead.

Java 11 fix

JEP 181 introduces nestmates — logically related classes that share a nest and can access each other’s private members without bridge methods. The JVM enforces nest membership via two new class file attributes:

  • NestHost — in a nested class, names the host (outer) class
  • NestMembers — in the host class, lists all nested class members
// Java 11 — no bridge methods generated; access is direct at JVM level
class Outer {
    private int secret = 42;

    class Inner {
        void read() {
            System.out.println(secret);  // direct JVM-level access; no bridge method
        }
    }
}

Impact on reflection

// Java 11 reflection API additions
Class<?> hostClass = Inner.class.getNestHost();       // returns Outer.class
Class<?>[] members  = Outer.class.getNestMembers();   // returns [Outer.class, Inner.class]

boolean areNestmates = Outer.class.isNestmateOf(Inner.class);  // true

This matters for libraries that do bytecode manipulation (ASM, Byte Buddy, cglib): they must be updated to emit correct NestHost/NestMembers attributes when generating or transforming nested classes.


SHA-1 Certificate Restriction (JEP 288, Java 9)

Java 9 tightened certificate validation by blocking TLS connections that present SHA-1-signed certificates. SHA-1 has been cryptographically broken since 2017 (SHAttered attack).

If your application connects to a server with a SHA-1 certificate and gets:

javax.net.ssl.SSLHandshakeException: PKIX path building failed

Check the server certificate:

openssl s_client -connect myserver.com:443 </dev/null 2>/dev/null | \
  openssl x509 -text -noout | grep "Signature Algorithm"
# If it shows "sha1WithRSAEncryption" — the server cert uses SHA-1

Fix: replace the server certificate with a SHA-256 (or better) signed certificate. As a temporary workaround (not recommended for production), you can re-enable SHA-1 in java.security:

# Remove sha1dsa and sha1withrsa from the disabled list — NOT recommended
jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, DSA keySize < 1024

What’s Next

Next: Removed and Deprecated APIs: Java EE, JavaFX, Nashorn (JEP 320, 335, 336)