Tento blog má byť taký malý praktický ťahák ku post-kvantovej kryptografii v C#. Nie je to ani prehľad, sú to len poznámky, príklady a zjednodušenia.
Post-kvantová kryptografia je klasická kryptografia, ktorá je odolná voči útokom kvantových počítačov.
Momentálne máme vymyslené algoritmy pre kvantové počítače, ktoré dokážu lámať asymetrickú kryptografiu - teda RSA a EC (eliptické krivky dokonca z trikrát menšou námahou ako RSA rovnakej bitovej bezpečnosti). Pre to sa už dlhšiu dobu vymýšľajú algoritmy asymetrickej kryptografie založené na iných problémoch ako faktorizácia prvočísiel alebo problém diskrétneho logaritmu.
Štandardné algoritmy symetrického šifrovania a kryptografických hashov ako AES (256), SHA2, SHA3, PBKDF2,… sa zatiaľ zdajú odolné voči útokom pomocou kvantových počítačov.
Tieto algoritmy sa používajú ako náhrada za asymetrické šifrovanie (RSA) alebo Diffie–Hellmanovu výmenu kľúčov (ECDH), no fungujú trochu inak. Pomocou verejného kľúča ide vytvoriť náhodné tajomstvo a jeho zašifrovanú podobu, ktorá ide rozšifrovať verejným kľúčom.
Momentálne je organizáciou NIST schválený algoritmus ML-KEN (CRYSTALS-Kyber). Algoritmy HQC, Bike a Classic Mceliece sú v procese schvalovania.
Nasledujúca tabuľka ukazuje parametre jednotlivých algoritmov.
Algoritmus | Veľkosť verejného kľúča | Veľkosť súkromného kľúča | Zašifrované dáta |
---|---|---|---|
ML-KEM 512 | 800 B | 1 632 B | 768 B |
ML-KEM 738 | 1 184 B | 2 400 B | 1 088 B |
ML-KEM 1024 | 1 568 B | 3 168 B | 1 568 B |
Bike128 | 1 541 B | 3 114 B | 1 573 B |
Bike192 | 3 083 B | 6 198 B | 3 115 B |
Bike256 | 5 122 B | 10 276 B | 5 154 B |
HQC128 | 2 249 B | 2 289 B | 4 497 B |
HQC192 | 4 522 B | 4 562 B | 9 042 B |
HQC256 | 7 245 B | 7 285 B | 14 485 B |
McEliece348864 | 261 120 B | 6 492 B | 196 B |
McEliece460896 | 524 160 B | 13 608 B | 156 B |
McEliece6688128 | 1 044 992 B | 13 932 B | 208 B |
McEliece6960119 | 1 047 319 B | 13 948 B | 194 B |
McEliece8192128 | 1 357 824 B | 14 120 B | 208 B |
NTRUhps2048509 | 699 B | 935 B | 699 B |
NTRUhps2048677 | 930 B | 1 234 B | 930 B |
NTRUhps4096821 | 1 230 B | 1 590 B | 1 230 B |
SIKEp434 | 330 B | 44 B | 346 B |
SIKEp503 | 378 B | 56 B | 402 B |
SIKEp751 | 564 B | 80 B | 596 B |
SIDH | 564 B | 48 B | 596 B |
LightSABER | 672 B | 1 568 B | 736 B |
SABER | 992 B | 2 304 B | 1 088 B |
FireSABER | 1 312 B | 3 040 B | 1 472 B |
Nasledujúci kód zobrazuje ukážku použitia algoritmu ML_KEM (podľa FIPS 203, pôvodne Kyber) v C# pomocou knižnice BouncyCastle.
Ostatné dostupné algoritmy využívajú takmer rovnaký kód jediný rozdiel je v názvoch použitých tried.
using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Kems; SecureRandom random = new SecureRandom(); MLKemKeyGenerationParameters keyGenParameters = new MLKemKeyGenerationParameters(random, MLKemParameters.ml_kem_512); MLKemKeyPairGenerator kyberKeyPairGenerator = new MLKemKeyPairGenerator(); kyberKeyPairGenerator.Init(keyGenParameters); // Ganerovanie klucoveho paru pre Alicu AsymmetricCipherKeyPair aliceKeyPair = kyberKeyPairGenerator.GenerateKeyPair(); // Zobrazenie klucov MLKemPublicKeyParameters alicePublic = (MLKemPublicKeyParameters)aliceKeyPair.Public; MLKemPrivateKeyParameters alicePrivate = (MLKemPrivateKeyParameters)aliceKeyPair.Private; byte[] pubEncoded = alicePublic.GetEncoded(); byte[] privateEncoded = alicePrivate.GetEncoded(); Console.WriteLine($"Alice's Public key: {PrintData(pubEncoded)}"); Console.WriteLine($"Alice's Private key: {PrintData(privateEncoded)}"); // Bob enakpsuluje secret a pomocou verejneho klucu Alice MLKemEncapsulator bobKyberKemGenerator = new MLKemEncapsulator(MLKemParameters.ml_kem_512); bobKyberKemGenerator.Init(new ParametersWithRandom(alicePublic, random)); byte[] encodedBytes = new byte[bobKyberKemGenerator.EncapsulationLength]; byte[] bobSecret = new byte[bobKyberKemGenerator.SecretLength]; bobKyberKemGenerator.Encapsulate(encodedBytes, 0, encodedBytes.Length, bobSecret, 0, bobSecret.Length); Console.WriteLine($"Encoded secret from Bob: {PrintData(encodedBytes)}"); Console.WriteLine($"Bob secret: {PrintData(bobSecret)}"); // Alice dekapsuluje secret a pomocou svojho privatneho klucu MLKemDecapsulator decapsulator = new MLKemDecapsulator(MLKemParameters.ml_kem_512); decapsulator.Init(alicePrivate); byte[] aliceSecret = new byte[decapsulator.SecretLength]; decapsulator.Decapsulate(encodedBytes, 0, encodedBytes.Length, aliceSecret, 0, aliceSecret.Length); Console.WriteLine($"Alice secret: {PrintData(aliceSecret)}");
Tieto algoritmy sú pre podpis dát privátnym kľúčom a overenie podpisu verejným kľúčom.
Momentálne sú NIST-om schválené algoritmy ML-DSA (Dilithium), Falcon a SLH-DSA (SPHINCS+).
Nasledujúca tabuľka ukazuje parametre jednotlivých algoritmov.
Algoritmus | Veľkosť verejného kľúča | Veľkosť súkromného kľúča | Veľkosť podpisu | Security |
---|---|---|---|---|
ML-DSA 2 (Lattice) | 1 312 B | 2 528 B | 2 420 B | 128-bit |
ML-DSA 3 | 1 952 B | 4 000 B | 3 293 B | 192-bit |
ML-DSA 5 | 2 592 B | 4 864 B | 4 595 B | 256-bit |
Falcon 512 (Lattice) | 897 B | 1 281 B | 690 B | 128-bit |
Falcon 1024 | 1 793 B | 2 305 B | 1 330 B | 256-bit |
Rainbow Level Ia (Oil-and-Vineger) | 161 600 B | 103 648 B | 66 B | 128-bit |
Rainbow Level IIIa | 861 400 B | 611 300 B | 164 B | 192-bit |
Rainbow Level Vc | 1 885 400 B | 1 375 700 B | 204 B | 256-bit |
Sphincs SHA256-128f Simple | 32 B | 64 B | 17 088 B | 128-bit |
Sphincs SHA256-192f Simple | 48 B | 96 B | 35 664 B | 192-bit |
Sphincs SHA256-256f Simple | 64 B | 128 B | 49 856 B | 256-bit |
Picnic 3 Full | 49 B | 73 B | 71 179 B | 192-bit |
GeMSS 128 | 352 188 B | 16 B | 33 B | 128-bit |
GeMSS 192 | 1 237 964 B | 24 B | 53 B | 128-bit |
Nasledujúci kód zobrazuje ukážku použitia algoritmu ML-DSA (podľa FIPS 204, pôvodne Crystals Dilithium) v C# pomocou knižnice BouncyCastle.
Ostatné dostupné algoritmy využívajú takmer rovnaký kód jediný rozdiel je v názvoch použitých tried.
using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Signers; SecureRandom random = new SecureRandom(); //Data na podpis byte[] data = new byte[32]; random.NextBytes(data); MLDsaKeyPairGenerator kpg = new MLDsaKeyPairGenerator(); kpg.Init(new MLDsaKeyGenerationParameters(random, MLDsaParameters.ml_dsa_65)); AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair(); MLDsaPublicKeyParameters publicKey = (MLDsaPublicKeyParameters)kp.Public; MLDsaPrivateKeyParameters privateKey = (MLDsaPrivateKeyParameters)kp.Private; Console.WriteLine($"Public key: {PrintData(publicKey.GetEncoded())}"); Console.WriteLine($"Private key: {PrintData(privateKey.GetEncoded())}"); MLDsaSigner signer = new MLDsaSigner(MLDsaParameters.ml_dsa_65, false); signer.Init(true, privateKey); signer.BlockUpdate(data); byte[] signature = signer.GenerateSignature(); Console.WriteLine($"Signature: {PrintData(signature)}"); MLDsaSigner verifitier = new MLDsaSigner(MLDsaParameters.ml_dsa_65, false); verifitier.Init(false, publicKey); verifitier.BlockUpdate(data); bool signatureIsVerified = verifitier.VerifySignature(signature); Console.WriteLine($"Signature is verified: {signatureIsVerified}");
Metóda na výpis dát:
private static string PrintData(byte[] bytes) { string base64 = Convert.ToBase64String(bytes); return (base64.Length > 50) ? $"({bytes.Length}B) {base64[..25]}…{base64[^25..]}" : $"({bytes.Length}B) {base64}"; }
Nie som odborník na interné fungovanie týchto algoritmov a ako pri inej kryptografii, treba sa riadiť odporúčaním organizácií venujúcim sa kryptografii. Takže použitie na vlastné riziko.
BouncyCastle má zatiaľ experimentálne implementácie CRYSTALS-Dilithium, CRYSTALS-Kyber, Falcon, SPHINCS+, Classic McEliece, FrodoKEM, NTRU, NTRU Prime, Picnic, Saber, BIKE a SIKE. Pričom algoritmus SIKE bude odstránený.
Pre ďalšie čítanie odporúčam nasledujúce zdroje.
Tieto algoritmy boli aj schválené.