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 Kyber (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 |
---|---|---|---|
Kyber512 | 800 B | 1 632 B | 768 B |
Kyber738 | 1 184 B | 2 400 B | 1 088 B |
Kyber1024 | 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 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.Pqc.Crypto.Crystals.Dilithium; using Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber; using Org.BouncyCastle.Security; SecureRandom random = new SecureRandom(); KyberKeyGenerationParameters keyGenParameters = new KyberKeyGenerationParameters(random, KyberParameters.kyber768); KyberKeyPairGenerator kyberKeyPairGenerator = new KyberKeyPairGenerator(); kyberKeyPairGenerator.Init(keyGenParameters); // Ganerovanie klucoveho paru pre Alicu AsymmetricCipherKeyPair aliceKeyPair = kyberKeyPairGenerator.GenerateKeyPair(); // Zobrazenie klucov KyberPublicKeyParameters alicePublic = (KyberPublicKeyParameters)aliceKeyPair.Public; KyberPrivateKeyParameters alicePrivate = (KyberPrivateKeyParameters)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 KyberKemGenerator bobKyberKemGenerator = new KyberKemGenerator(random); ISecretWithEncapsulation encapsulatedSecret = bobKyberKemGenerator.GenerateEncapsulated(alicePublic); byte[] bobSecret = encapsulatedSecret.GetSecret(); Console.WriteLine($"Bob's Secret: {PrintData(bobSecret)}"); // Bon ziska chipertext a posle ho Alici byte[] cipherText = encapsulatedSecret.GetEncapsulation(); Console.WriteLine($"Cipher text: {PrintData(cipherText)}"); // Alica dekapsuluje secret pomocou svojho privatneho klucu KyberKemExtractor aliceKemExtractor = new KyberKemExtractor(alicePrivate); byte[] aliceSecret = aliceKemExtractor.ExtractSecret(cipherText); Console.WriteLine($"Alice's 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 Dilithium, Falcon a 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 |
---|---|---|---|---|
Crystals Dilithium 2 (Lattice) | 1 312 B | 2 528 B | 2 420 B | 128-bit |
Crystals Dilithium 3 | 1 952 B | 4 000 B | 3 293 B | 192-bit |
Crystals Dilithium 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 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.Pqc.Crypto.Crystals.Dilithium; using Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber; using Org.BouncyCastle.Security; SecureRandom random = new SecureRandom(); //Data na podpis byte[] data = new byte[32]; random.NextBytes(data); // Vygenerovanie klucoveho paru DilithiumKeyGenerationParameters keyGenParameters = new DilithiumKeyGenerationParameters(random, DilithiumParameters.Dilithium3); DilithiumKeyPairGenerator dilithiumKeyPairGenerator = new DilithiumKeyPairGenerator(); dilithiumKeyPairGenerator.Init(keyGenParameters); AsymmetricCipherKeyPair keyPair = dilithiumKeyPairGenerator.GenerateKeyPair(); // Export klucov DilithiumPublicKeyParameters publicKey = (DilithiumPublicKeyParameters)keyPair.Public; DilithiumPrivateKeyParameters privateKey = (DilithiumPrivateKeyParameters)keyPair.Private; byte[] pubEncoded = publicKey.GetEncoded(); byte[] privateEncoded = privateKey.GetEncoded(); Console.WriteLine($"Public key: {PrintData(pubEncoded)}"); Console.WriteLine($"Private key: {PrintData(privateEncoded)}"); // Podpis dat DilithiumSigner alice = new DilithiumSigner(); alice.Init(true, privateKey); byte[] signature = alice.GenerateSignature(data); Console.WriteLine($"Signature: {PrintData(signature)}"); // Overenie podpisu DilithiumSigner bob = new DilithiumSigner(); bob.Init(false, publicKey); bool verified = bob.VerifySignature(data, signature); Console.WriteLine($"Successfully verified? {verified}");
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.