ťařina
Obsah Soubory
Kryptografie

Veřejný a soukromý klíč

Aktualizováno 9 min čtení 1 709 slov

Veřejný a soukromý klíč

Asymetrická kryptografie je nejméně intuitivní věc v celé síťařině. Symetrická šifra dává smysl každému — máme společné heslo, tak si šifrujeme. Ale představa, že si můžeme vyměnit klíče veřejně, před zraky útočníka, a přesto se domluvit na tajemství, vypadá na první pohled jako podvod.

Není. Tahle stránka vysvětluje, jak to funguje, kde je to v praxi vidět a co s klíči doopravdy dělat.

Základní pojmy jsou na stavebních kamenech, samotná výměna klíčů na Diffie-Hellman.

Základní myšlenka

Máš dvojici klíčů, které vzniknou najednou a patří k sobě:

Soukromý klíč — jediná kopie, nikdy neopustí tvůj stroj. Z něj se dá spočítat veřejný klíč.

Veřejný klíč — rozdáš ho komukoliv. Klidně ho pověsíš na web. Ze znalosti veřejného klíče nejde odvodit soukromý — tohle je celá pointa a stojí na tom, že určité matematické operace se snadno počítají jedním směrem a prakticky nedají zvrátit.

Z toho plynou dvě různé operace, které se často pletou:

Operace Kdo použije soukromý Kdo použije veřejný K čemu
Šifrování příjemce dešifruje odesílatel šifruje důvěrnost
Podpis autor podepisuje kdokoliv ověří autenticita

Všimni si, že jsou to opačné směry. Když chceš někomu poslat tajnou zprávu, potřebuješ jeho veřejný klíč. Když chceš dokázat, že zpráva je od tebe, použiješ svůj soukromý klíč.

flowchart LR
    subgraph sif [Šifrování]
    A[Zpráva] -->|veřejný klíč Boba| B[Šifrový text]
    B -->|soukromý klíč Boba| C[Zpráva]
    end
    subgraph pod [Podpis]
    D[Zpráva] -->|soukromý klíč Alice| E[Podpis]
    E -->|veřejný klíč Alice| F[platí / neplatí]
    end

„Podpis je šifrování soukromým klíčem"

Tuhle větu najdeš ve stovkách návodů a je nesprávná. Vypadá pravdivě jen u RSA, protože jeho matematika je symetrická. U eliptických křivek — tedy u toho, co dnes používáš — je podpis úplně jiný algoritmus než šifrování a takové srovnání nedává smysl vůbec.

Správně: podpis a šifrování jsou dvě samostatné schopnosti. Některé rodiny umí obojí (RSA), některé jen jednu (ECDSA a Ed25519 umí jen podepisovat, X25519 umí jen výměnu klíčů).

Proč to funguje

Není potřeba počítat, ale bez téhle intuice zůstane všechno magie. Existují matematické operace, které jsou snadné jedním směrem a extrémně drahé zpátky:

Násobení versus rozklad na součin. Vynásobit dvě tisícimístná prvočísla umí telefon okamžitě. Dostat je z výsledku zpátky nikdo neumí. Na tom stojí RSA.

Umocňování ve zbytkové aritmetice versus diskrétní logaritmus. Spočítat g^a mod p je snadné. Dostat z výsledku a je nezvládnutelné. Na tom stojí klasický Diffie-Hellman a DSA.

Násobení bodu na eliptické křivce versus totéž zpátky. Sečíst bod sám se sebou a-krát je rychlé. Zjistit z výsledku a je řádově těžší než u předchozích. Na tom stojí ECDH, ECDSA a Ed25519.

To „extrémně drahé" má konkrétní čísla. Rozklad 2048bitového čísla je mimo dnešní možnosti kohokoliv na planetě. Rozklad 512bitového šel v roce 1999 a dnes to zvládne cloudová instance za pár hodin — proto se délky klíčů posouvají.

Zásadní upozornění: žádná z těch tří věcí není dokázaná jako těžká. Jen to nikdo padesát let nedokázal zlomit. To je slabší tvrzení, než jak se obvykle prezentuje, a je to důvod, proč se kryptografie umí měnit.

Proč jsou křivky lepší

Rozdíl je v tom, jak dobře fungují nejlepší známé útoky.

Na RSA a klasický DH existuje síto v číselném tělese — algoritmus, který sice trvá dlouho, ale roste podexponenciálně. Zdvojnásobení délky klíče proto sílu nezdvojnásobí, jen o kus přidá.

Na eliptických křivkách nic lepšího než obecné metody (Pollardovo rho) nikdo nenašel. Ty trvají zhruba odmocninu z velikosti skupiny, což je plně exponenciální v délce klíče. Každý přidaný bit klíče tedy stojí útočníka dvojnásobek.

Praktický důsledek:

RSA-3072 P-256 / X25519
Bezpečnostní úroveň 128 bitů 128 bitů
Veřejný klíč ~400 B 32 B
Podpis 384 B 64 B
Generování klíče sekundy milisekundy
Podepsání rychlé rychlé
Ověření podpisu velmi rychlé rychlé

RSA má jedinou přetrvávající výhodu: ověření podpisu je díky malému veřejnému exponentu (65537) mimořádně levné. Proto se pořád drží tam, kde se jeden podpis ověřuje milionkrát. Jinak nemá důvod.

Rodiny, které potkáš

RSA

Nejstarší (1977) a nejrozšířenější. Umí jako jediný z běžných algoritmů podepisovat i šifrovat.

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out rsa.pem
openssl pkey -in rsa.pem -pubout -out rsa.pub
openssl pkey -in rsa.pem -text -noout | head

Pravidla, pokud RSA používat musíš:

  • Minimálně 2048 bitů, raději 3072. Pod 2048 nic. Nad 4096 jen plýtváš výkonem.
  • Zarovnání OAEP pro šifrování, nikdy PKCS#1 v1.5. Ten má útok, který se pod různými jmény (Bleichenbacher, ROBOT) vrací každých pár let.
  • Zarovnání PSS pro podpisy, kde to protistrana umí.

RSA neumí zašifrovat velká data. Ta zpráva se musí vejít do klíče minus zarovnání — u 2048bitového klíče s OAEP a SHA-256 je to 190 bajtů. Proto se v reálu RSA nikdy nešifruje obsah, jen se jím přenese symetrický klíč. Tomu se říká key transport a TLS 1.3 ho úplně zrušilo, protože nemá dopředné utajení.

Eliptické křivky NIST (P-256, P-384)

prime256v1 / secp256r1 a secp384r1. Standardní, všude podporované, používané ve většině certifikátů.

Jsou v pořádku, ale implementují se hůř — jsou u nich potřeba kontroly platnosti bodu, převody souřadnic a snadno vzniknou postranní kanály. Navíc jsou u nich neveřejně zvolené konstanty, což od roku 2013 živí trvalou nedůvěru.

Curve25519: X25519 a Ed25519

Návrh z roku 2005, dnes výchozí volba. Jedna křivka, dvě použití, která se nedají zaměňovat:

X25519 — výměna klíčů (ECDH). Používá ji TLS 1.3, SSH i WireGuard. Veřejný klíč 32 bajtů, sdílené tajemství 32 bajtů.

Ed25519 — podpisy (EdDSA). Používá ji SSH, podepisování Git commitů, age, moderní balíčkovací systémy. Veřejný klíč 32 bajtů, podpis 64 bajtů.

Proč je to lepší než P-256:

  • Všechny konstanty jsou odvozené a vysvětlené. Nic není „prostě zvolené".
  • Nemá okrajové případy. Jakýchkoliv 32 bajtů je platný veřejný klíč, takže nejde poslat záludný vstup.
  • Implementace je přirozeně v konstantním čase, takže postranní kanály nevznikají mimoděk.
  • Ed25519 je deterministické. Náhodné číslo pro podpis se odvodí z klíče a zprávy, ne z generátoru. Tím odpadá nejhorší selhání ECDSA — viz níže.

ECDSA a smrtelná past s nonce

ECDSA potřebuje ke každému podpisu jednorázové náhodné číslo k. Když se k zopakuje u dvou různých zpráv, dá se ze dvou podpisů přímo dopočítat soukromý klíč. Ne oslabit, přímo spočítat.

Není to teorie:

  • Sony PlayStation 3 (2010) používalo pro všechny podpisy pevné k. Podpisový klíč konzole byl veřejně odvozen a nešel opravit, protože byl v hardwaru.
  • Android (2013) měl vadný generátor náhodných čísel a z peněženek Bitcoinu tak zmizely reálné peníze.

Ed25519 tenhle problém nemá z podstaty návrhu. Když si vybíráš a máš na výběr, ber Ed25519.

Co je mrtvé

DSA — 1024bitové omezení, stejná past s k, dnes nemá jediný důvod existovat. OpenSSH ho v roce 2024 vypnul a v roce 2025 z kódu odstranil.

RSA se SHA-1 (ssh-rsa) — OpenSSH ho vypnul ve verzi 8.8. Když ti staré zařízení hlásí no matching host key type, je to tohle. Řešením je zařízení aktualizovat, ne obcházet.

secp256k1 — křivka Bitcoinu. Je v pořádku, ale mimo kryptoměny nemá důvod.

Formáty klíčů, aneb odkud pochází zmatek

Jeden a tentýž klíč potkáš ve čtyřech zápisech a je užitečné vědět, který je který.

PEM — textový, -----BEGIN ... -----, obsah je base64. Nejběžnější u TLS.

-----BEGIN PRIVATE KEY-----      ← PKCS#8, moderní, jakýkoliv algoritmus
-----BEGIN RSA PRIVATE KEY-----  ← PKCS#1, jen RSA, staré
-----BEGIN EC PRIVATE KEY-----   ← SEC1, jen křivky, staré
-----BEGIN OPENSSH PRIVATE KEY-----  ← formát OpenSSH, ne OpenSSL
-----BEGIN CERTIFICATE-----      ← to není klíč, to je certifikát

DER — totéž binárně, bez base64. Používá Java a Windows, přípona .der nebo .cer.

PKCS#12 / PFX — jeden soubor .p12 obsahující klíč i certifikát i řetěz, chráněný heslem. Windows, Java, importy do prohlížeče.

Formát OpenSSH~/.ssh/id_ed25519. Vlastní formát, který se od OpenSSL liší a od verze 7.8 je výchozí. Umí soukromý klíč chránit heslem přes bcrypt_pbkdf, což ho dělá odolnějším proti hádání hesla než starý formát.

Převody, které budeš dřív nebo později potřebovat:

# PEM → DER
openssl pkey -in key.pem -outform DER -out key.der

# starý PKCS#1 → moderní PKCS#8
openssl pkey -in old-rsa.pem -out new.pem

# klíč + certifikát → PKCS#12
openssl pkcs12 -export -inkey key.pem -in cert.pem -certfile chain.pem -out bundle.p12

# PKCS#12 → PEM
openssl pkcs12 -in bundle.p12 -nodes -out all.pem

# SSH veřejný klíč z privátního (když ho ztratíš)
ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub

Chyba, která se stane každému: zaměnit certifikát a klíč. Certifikát je veřejný a začíná BEGIN CERTIFICATE. Klíč je tajný a začíná BEGIN ... PRIVATE KEY. Nginx si na to bude stěžovat větou PEM_read_bio_X509 a nebude vysvětlovat proč.

Jak zjistit, co vlastně mám

# typ a parametry klíče
openssl pkey -in key.pem -text -noout

# patří tenhle klíč k tomuhle certifikátu?
openssl pkey -in key.pem -pubout | openssl sha256
openssl x509 -in cert.pem -pubkey -noout | openssl sha256
# obě čísla musí být stejná

# co je v certifikátu
openssl x509 -in cert.pem -noout -subject -issuer -dates -ext subjectAltName

# SSH klíč: typ, délka a otisk
ssh-keygen -lf ~/.ssh/id_ed25519.pub

To porovnání otisků je nejrychlejší způsob, jak vyloučit nejčastější příčinu toho, že server po výměně certifikátu nenaběhne.

Fingerprint

Veřejné klíče se špatně porovnávají očima. Proto se z nich dělá otisk — hash veřejného klíče, který se dá přečíst do telefonu.

ssh-keygen -lf ~/.ssh/id_ed25519.pub
# 256 SHA256:5N3Yb... martin@notebook (ED25519)

Otisk nenahrazuje ověření, jen ho zkracuje. Když otisk získáš tou samou cestou, kterou by šel útočník, nedokázal jsi nic. Tohle je celý problém prvního připojení na SSH server, podrobně na SSH.

Historicky se používal MD5 (ssh-keygen -E md5) a u nich ta dvojtečkovaná šestnáctková čísla. Dnes SHA-256 v base64.

Kde se s tím v síti setkáš

Situace Kdo má soukromý klíč Co dokazuje
HTTPS server že web patří tomu, komu CA vystavila certifikát
SSH — host key server že jsi u toho stroje jako minule
SSH — klíč uživatele ty že jsi ten, kdo má klíč v authorized_keys
mTLS obě strany vzájemně; vyžaduje vlastní CA
WireGuard oba peery že protistrana zná klíč z konfigurace
Podpis balíčků APT správce repozitáře že balíček nikdo nepodstrčil
Podpis Git commitu autor kdo commit vytvořil
Passkey tvoje zařízení přihlášení bez hesla

Podstatné je, že ve všech případech jde o totéž. Naučíš se to jednou.

Certifikát: podepsané tvrzení o klíči

Veřejný klíč sám o sobě neříká, komu patří. Certifikát je veřejný klíč plus jméno plus doba platnosti, to celé podepsané někým, komu se dá věřit.

certifikát = { veřejný klíč, jména (SAN), platnost od–do, účel }
           + podpis certifikační autority přes to všechno

Když prohlížeč certifikát dostane, ověří podpis veřejným klíčem té CA — a její certifikát ověří proti další, až ke kořenu, který má v systému.

Certifikát tedy nezvyšuje sílu šifrování ani o bit. Řeší výhradně otázku, komu klíč patří.

Jak s klíči zacházet

Soukromý klíč se negeneruje jinde, než kde bude použitý. Když ti někdo pošle klíč mailem, není to tvůj klíč, je to sdílený klíč.

Nikdy ho neposílej. Ani sobě, ani do chatu, ani do repozitáře. Když se to stane, klíč je spálený a musí se vyměnit — smazání commitu nestačí, historie zůstává.

Chraň ho heslem. U SSH:

ssh-keygen -t ed25519 -a 100 -C "martin@notebook"

-a 100 je počet kol funkce odvození klíče z hesla. Zpomalí to hádání hesla, kdyby se soubor ztratil, a při přihlašování to nepoznáš. Aby tě heslo neotravovalo, je ssh-agent.

Práva 600. OpenSSH klíč s právy pro skupinu odmítne použít a udělá dobře.

chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub

Různé klíče na různé účely. Jeden pro server doma, jiný pro práci, jiný pro GitHub. Ztráta jednoho pak neznamená ztrátu všeho a odebrat jeden přístup je jeden řádek.

Nejlepší je klíč, který nejde zkopírovat. Hardwarový token (YubiKey, Nitrokey) drží soukromý klíč uvnitř čipu a operaci provádí sám. Malware ti ho nemůže ukrást, protože se nikdy neobjeví v paměti. OpenSSH to podporuje od verze 8.2:

ssh-keygen -t ed25519-sk -O resident -O verify-required

Vznikne klíč, který vyžaduje dotek tokenu u každého přihlášení a verify-required k tomu přidá PIN. resident znamená, že klíč lze z tokenu obnovit na novém počítači (ssh-keygen -K). Za devět stovek je tohle největší skok v bezpečnosti, jaký si můžeš koupit.

Měj plán na výměnu. Předem věz, jak by ses dostal na server, kdyby ti notebook shořel. Druhý klíč v trezoru, konzole u poskytovatele, přístup přes VPN z jiného stroje.

Praktické: podepsat a ověřit soubor

Nemusíš na to GPG. SSH klíč, který už máš, to umí od OpenSSH 8.0:

# podepsat
ssh-keygen -Y sign -f ~/.ssh/id_ed25519 -n file dokument.pdf
# vznikne dokument.pdf.sig

# ověřit — potřebuješ seznam povolených podepisujících
echo "martin@example.cz $(cat ~/.ssh/id_ed25519.pub)" > allowed_signers
ssh-keygen -Y verify -f allowed_signers -I martin@example.cz \
    -n file -s dokument.pdf.sig < dokument.pdf

Stejným mechanismem se podepisují Git commity, bez GPG a bez keyserverů:

git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true

Kam dál