Postkvantna enkripcija u Javi: šta donosi JDK 27 i kako je koristiti već danas
Java 27 je izašla 16. septembra 2026. i sa njom je postkvantna kriptografija prvi put stigla tamo gde je zaista potrebna — u TLS rukovanje, i to bez ijedne izmene u vašem kodu. U ovom tekstu prolazimo kroz ceo put: šta je JDK dobio kada, kako se hibridna razmena ključeva podešava, koliko košta u bajtovima, kako ML-KEM i ML-DSA koristiti direktno, i šta uraditi ako ste zaglavljeni na Javi 8.
Zašto sada: rok je već postavljen
O motivu smo pisali detaljno: Evropska komisija i države članice usvojile su mapu puta po kojoj kritična infrastruktura mora biti na postkvantnim algoritmima do kraja 2030, a sve ostalo do 2035. Pokretač nije kvantni računar koji postoji danas, nego napad „harvest now, decrypt later” — snimi sada, dešifruj kasnije.
Za Java tim to znači vrlo konkretnu stvar: saobraćaj koji vaša aplikacija danas šalje preko TLS-a neko može da arhivira i otvori za deset godina. Ako podaci u toj sesiji imaju rok poverljivosti duži od toga, zaštita mora da se ugradi sada, a ne kada hardver stigne.
Put JDK-a do kvantne otpornosti
Oracle ovo ne radi od juče. Gradnja je tekla u slojevima, izdanje po izdanje, i tek u JDK 27 se slojevi spajaju u nešto što radi samo od sebe.
| Izdanje | Šta je doneto | JEP |
|---|---|---|
| JDK 21 (LTS, 2023) | Generički KEM API — apstrakcija za enkapsulaciju ključeva, bez ijednog postkvantnog algoritma | JEP 452 |
| JDK 24 (mart 2025) | ML-KEM (FIPS 203) i ML-DSA (FIPS 204) kao ugrađeni algoritmi; KDF API | JEP 496, 497, 510 |
| JDK 25 (LTS, sept. 2025) | Nasleđuje ML-KEM i ML-DSA — prvi LTS sa postkvantnim algoritmima | — |
| JDK 26 (mart 2026) | Potpisivanje JAR-ova pomoću ML-DSA; HPKE (RFC 9180); PEM API | JEP 524 |
| JDK 27 (16. 9. 2026) | Hibridna postkvantna razmena ključeva za TLS 1.3; PEM API (treći pregled) | JEP 527, 538 |
Obratite pažnju na logiku: prvo API (21), pa algoritmi (24), pa alati (26), pa protokol (27). Svaki korak je bio upotrebljiv sam za sebe — ali tek JEP 527 daje ono što većina timova zapravo želi: zaštitu koja se uključuje bez pisanja koda.
Java 27 nije LTS izdanje, što je za produkciju bitno. Oracle je zato najavio i backport hibridnog TLS-a na LTS linije: JDK 25 sa oktobarskim kvartalnim zakrpama 2026, JDK 21 i 17 u prvoj polovini 2027, a JDK 11 i 8 u drugoj polovini 2027. Ako danas držite produkciju na JDK 21, ne morate da skačete na 27 — ali morate da planirate nadogradnju zakrpa.
JEP 527: šta se tačno promenilo u TLS-u
Suština JEP-a 527 je da SunJSSE provajder dobija tri nove „imenovane grupe” (named groups) za razmenu ključeva u TLS 1.3:
- X25519MLKEM768 — X25519 ECDHE + ML-KEM-768 (nova podrazumevana vrednost)
- SecP256r1MLKEM768 — secp256r1 ECDHE + ML-KEM-768
- SecP384r1MLKEM1024 — secp384r1 ECDHE + ML-KEM-1024
Ključna reč je hibridna. Ne zamenjuje se eliptička kriva postkvantnim algoritmom — obe se izvode u istom rukovanju, a njihove tajne se nadovezuju jedna na drugu pre ulaska u HKDF. Konstrukciju je definisao IETF u RFC 9954 (opšti okvir) i RFC 10024 (baš ove tri šeme), a garancija koju daje je elegantna: veza ostaje bezbedna sve dok je bar jedan od dva algoritma neprobijen.
To je osiguranje u oba smera. Ako se sutra pojavi kvantni računar, štiti vas ML-KEM. Ako se u rešetkastoj matematici nađe rupa — a ML-KEM je mnogo mlađi od X25519 — štiti vas klasična kriva.
U JDK 27 podrazumevani redosled preferencija izgleda ovako:
X25519MLKEM768, x25519, secp256r1, secp384r1,
secp521r1, x448, ffdhe2048, ffdhe3072, ffdhe4096
Klijent pritom šalje dva udela ključa — jedan hibridni i jedan klasični — pa rukovanje sa starijim serverom prolazi iz prve, bez dodatne runde.
javax.net.ssl, ne morate da uradite ništa. HttpClient, SSLSocket, Tomcat, Netty preko JSSE-a, JDBC drajveri nad TLS-om — svi automatski dobijaju hibridnu razmenu. Jedini izuzetak su aplikacije koje su eksplicitno postavile listu imenovanih grupa; njih treba ručno dopuniti.
Cena: rukovanje postaje 38 puta veće
Ovo je deo koji vas može iznenaditi u produkciji. Klasičan x25519 udeo ključa je 32 bajta. Hibridni X25519MLKEM768 udeo je 1216 bajtova — 1184 za ML-KEM-768 enkapsulacioni ključ plus 32 za X25519.
Posledica: ClientHello više ne staje u jedan mrežni paket. Većina mreže to podnese bez problema, ali deo starijih firewall i DPI uređaja, kao i pojedini load balancer-i, tiho odbacuju prevelik ClientHello. Rezultat je veza koja „ne radi ni zbog čega” — i to je danas najčešći praktičan problem sa hibridnim TLS-om, a ne performanse. Same lattice operacije su brze; ML-KEM je po procesorskom vremenu uporediv sa ECDHE, ponekad i brži.
Kako podesiti ili isključiti
Dva su načina. Sistemsko svojstvo, globalno za JVM:
# samo klasični algoritmi — privremeno gašenje hibrida
java -Djdk.tls.namedGroups=x25519,secp256r1 -jar app.jar
# eksplicitan redosled sa hibridima
java -Djdk.tls.namedGroups=X25519MLKEM768,SecP256r1MLKEM768,x25519,secp256r1 -jar app.jar
Ili programski, po konekciji:
SSLParameters params = socket.getSSLParameters();
params.setNamedGroups(new String[] {
"X25519MLKEM768",
"SecP256r1MLKEM768",
"x25519",
"secp256r1"
});
socket.setSSLParameters(params);
Dijagnostika
Od JDK-a 26 postoji brz način da vidite šta je zaista uključeno:
java -XshowSettings:security:tls -version
A kada rukovanje pukne, klasika i dalje radi najbolje:
java -Djavax.net.debug=ssl,handshake -jar app.jar
U ispisu tražite named groups i key_share — tu se vidi da li je hibridna grupa ponuđena i da li ju je server prihvatio.
Sloj niže: ML-KEM direktno
TLS pokriva podatke u prenosu. Za sve ostalo — enkripciju u mirovanju, sopstvene protokole, razmenu ključeva između mikroservisa, šifrovanje poruka u redu — algoritam koristite sami, preko KEM API-ja iz JDK-a 21.
Prvo, generisanje para ključeva. Dva ekvivalentna oblika:
import java.security.*;
import java.security.spec.NamedParameterSpec;
// oblik 1: porodica + parametarski skup
KeyPairGenerator g = KeyPairGenerator.getInstance("ML-KEM");
g.initialize(NamedParameterSpec.ML_KEM_768);
KeyPair kp = g.generateKeyPair();
// oblik 2: direktno po imenu skupa
KeyPairGenerator g2 = KeyPairGenerator.getInstance("ML-KEM-768");
KeyPair kp2 = g2.generateKeyPair();
Bez initialize, podrazumevani skup je ML-KEM-768 — i to je pravi izbor za skoro sve. ML-KEM-512 štedi malo prostora po ceni sigurnosne margine, a ML-KEM-1024 je za podatke sa vrlo dugim rokom poverljivosti.
Sada razmena. Pošiljalac ima samo javni ključ primaoca i iz njega izvodi dve stvari odjednom — tajni ključ i šifrat koji taj ključ prenosi:
import javax.crypto.KEM;
import javax.crypto.SecretKey;
// --- strana koja šalje ---
KEM kem = KEM.getInstance("ML-KEM");
KEM.Encapsulator enc = kem.newEncapsulator(kp.getPublic());
KEM.Encapsulated result = enc.encapsulate();
byte[] sifrat = result.encapsulation(); // 1088 B za ML-KEM-768 — ide preko mreže
SecretKey kljucPosiljaoca = result.key(); // ostaje kod pošiljaoca
// --- strana koja prima ---
KEM.Decapsulator dec = kem.newDecapsulator(kp.getPrivate());
SecretKey kljucPrimaoca = dec.decapsulate(sifrat);
// kljucPosiljaoca i kljucPrimaoca su isti bajtovi
Ovo je mentalno drugačije od Diffie–Hellmana i vredi se zadržati na tome. Kod DH-a obe strane doprinose i zajednički izvode tajnu. Kod KEM-a pošiljalac sam proizvede tajnu i zapakuje je tako da je samo vlasnik privatnog ključa može otvoriti. Praktična posledica: razmena je asimetrična i staje u jednu poruku.
Dobijeni SecretKey se ne koristi direktno za šifrovanje. Provucite ga kroz KDF (HKDF je u JDK-u od 24, JEP 510) da biste izveli zasebne ključeve za AES-GCM i za autentikaciju.
Serijalizacija ključeva ide uobičajenim putem, preko KeyFactory:
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
KeyFactory f = KeyFactory.getInstance("ML-KEM");
X509EncodedKeySpec javni = f.getKeySpec(kp.getPublic(), X509EncodedKeySpec.class);
PKCS8EncodedKeySpec privatni = f.getKeySpec(kp.getPrivate(), PKCS8EncodedKeySpec.class);
PublicKey vracenJavni = f.generatePublic(javni);
Potpisi: ML-DSA
ML-KEM rešava poverljivost. Za integritet i autentičnost tu je ML-DSA, koji se u JDK-u koristi kroz standardni Signature API:
KeyPairGenerator g = KeyPairGenerator.getInstance("ML-DSA");
g.initialize(NamedParameterSpec.ML_DSA_65); // podrazumevano i bez ove linije
KeyPair kp = g.generateKeyPair();
byte[] poruka = "ugovor".getBytes(StandardCharsets.UTF_8);
Signature potpisivac = Signature.getInstance("ML-DSA");
potpisivac.initSign(kp.getPrivate());
potpisivac.update(poruka);
byte[] potpis = potpisivac.sign(); // 3309 B za ML-DSA-65
Signature proveravac = Signature.getInstance("ML-DSA");
proveravac.initVerify(kp.getPublic());
proveravac.update(poruka);
boolean ispravno = proveravac.verify(potpis);
Alati prate. keytool generiše ML-DSA par:
keytool -keystore ks -storepass changeit -genkeypair -alias mldsa \
-keyalg ML-DSA -groupname ML-DSA-65 -dname CN=ML-DSA
A od JDK-a 26 i jarsigner ume da potpiše JAR postkvantnim potpisom, uz identifikator algoritma ML-DSA-65. To je nenametljiv, ali važan detalj: lanac isporuke softvera je upravo mesto gde potpis mora da izdrži decenije, jer se artefakt potpisuje jednom a verifikuje godinama.
Ono što ovde boli je veličina. ML-DSA-65 potpis je 3309 bajtova naspram 256 za RSA-2048 — trinaest puta više. Ako potpise stavljate u JWT tokene, u HTTP zaglavlja ili u bazu po redu tabele, to više nije zanemarljiva stavka. Proverite limite na zaglavljima (mnogi reverse proxy-ji podrazumevano seku na 8 KB) pre nego što nešto pređe na ML-DSA.
Šta još ne radi
Da ne bi bilo iznenađenja, evo granica onoga što je isporučeno.
Autentikacija u TLS-u i dalje je klasična. JEP 527 pokriva samo razmenu ključeva. Sertifikati kojima se server predstavlja i dalje su RSA ili ECDSA. To za „harvest now, decrypt later” nije problem — potpis se proverava u trenutku rukovanja, pa retroaktivno probijanje ne pomaže napadaču — ali znači da PKI migracija tek predstoji. Postkvantni sertifikati javnih CA tela još nisu praktično dostupni; ne kupujte ih za produkciju u 2026.
Čist ML-KEM, bez hibrida, nije podržan. To je izričit ne-cilj JEP-a 527. IETF nacrt draft-ietf-tls-mlkem koji definiše samostalne grupe mlkem512, mlkem768 i mlkem1024 (kodne tačke 0x0200–0x0202) trenutno je u redu za objavu kao RFC. Podrška u JDK-u ostaje za kasnije — i to je razumna odluka, jer je hibrid danas jedino što regulatori i NIST preporučuju.
SLH-DSA i HQC nisu u JDK-u. Ako vam treba potpis zasnovan isključivo na heš funkcijama (FIPS 205) ili rezervni KEM nezavisan od rešetki, morate van standardne biblioteke.
HPKE iz JDK-a 26 je za sada klasičan. Podržava X25519, AES-GCM i KDF-ove nad SHA-256; postkvantne varijante čekaju da odgovarajući IETF nacrti postanu RFC.
Ako ste na starijoj Javi: Bouncy Castle
Realnost je da ogroman broj poslovnih sistema u Srbiji stoji na JDK 8, 11 ili 17. Backport hibridnog TLS-a tamo stiže tek 2027, a KEM API postoji tek od 21. Rešenje je Bouncy Castle, koji od verzije 1.79 nosi pune implementacije ML-KEM, ML-DSA i SLH-DSA i registruje se kao običan JCE provajder:
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jcajce.spec.MLKEMParameterSpec;
Security.addProvider(new BouncyCastleProvider());
KeyPairGenerator g = KeyPairGenerator.getInstance("ML-KEM", "BC");
g.initialize(MLKEMParameterSpec.ml_kem_768);
KeyPair kp = g.generateKeyPair();
Za ML-DSA je isto, uz MLDSAParameterSpec.ml_dsa_65. Dve napomene: na JDK-u starijem od 21 nemate javax.crypto.KEM, pa se koristi niži BC API; i ako vam treba FIPS 140-3 validacija, to je zaseban proizvod (bc-fips), ne standardni bcprov.
Plan za Java tim — šest koraka
- Popišite gde se kriptografija zaista koristi. Pretražite kod za
RSA,ECDSA,DH,SSLContext,KeyStore,Signature.getInstance. Naći ćete više mesta nego što očekujete, a najčešće u bibliotekama koje niste vi pisali. - Pronađite ko je „zakucao” imenovane grupe. Svaki poziv
setNamedGroupsili postavljenojdk.tls.namedGroupstiho blokira hibrid. To je jedini kod koji mora da se menja. - Testirajte mrežnu putanju, ne samo aplikaciju. Podignite JDK 27 u test okruženju i propustite saobraćaj kroz iste firewall-e, proxy-je i load balancer-e kao u produkciji. Veliki
ClientHelloje problem infrastrukture, a ne koda — i neće se pokazati na lokalnoj mašini. - Rangirajte podatke po roku poverljivosti. Sesija koja prenosi medicinske ili ugovorne podatke ima prioritet nad onom koja vuče sličice proizvoda.
- Uvedite kriptografsku agilnost. Ime algoritma neka bude konfiguracija, ne literal u kodu. Sledeća smena dolazi brže nego prethodna.
- Uskladite se sa LTS rasporedom. Ako ste na JDK 21, ciljajte zakrpe iz 2027. Ako ste na 25, oktobarske zakrpe 2026. Ako ste na 8 — nadogradnja Jave vam je ionako veći projekat od postkvantne kriptografije.
Zaključak
Java je sa JDK-om 27 stigla do tačke u kojoj postkvantna zaštita prestaje da bude tema za istraživanje i postaje podrazumevano ponašanje. Za većinu timova to znači da najvažniji posao nije pisanje novog koda, već provera da li nešto u postojećoj konfiguraciji stoji na putu — zakucana lista grupa, stari firewall, ili LTS izdanje koje čeka svoju zakrpu.
Onaj drugi deo — ML-KEM i ML-DSA u sopstvenom kodu — nije hitan za sve, ali jeste za one koji čuvaju podatke sa dugim rokom. Lepa vest je da su API-ji obični, poznati i već u standardnoj biblioteci. Nema egzotike: KeyPairGenerator, Signature, KeyFactory. Samo drugi algoritmi iza njih.
Izvori: InfoQ, „Java 27 Released” (16. septembar 2026); OpenJDK JEP 452, 496, 497, 510, 524, 527 i 538; Oracle Java blog, „Post-Quantum Cryptography in Long-Term Support JDK Releases” (avgust 2026); Inside.java, „Post-Quantum Hybrid Key Exchange for TLS 1.3”; IETF RFC 9954 i RFC 10024, nacrt draft-ietf-tls-mlkem; NIST FIPS 203 i FIPS 204; dokumentacija Bouncy Castle 1.79+. Tekst je autorska obrada PsiMosaic redakcije.