Post-kvantová kryptografia v C#

Marec 2024

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

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.

Algoritmy pre enakapsuláciu (KEM)

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, BikeClassic Mceliece sú v procese schvalovania.

Nasledujúca tabuľka ukazuje parametre jednotlivých algoritmov.

AlgoritmusVeľkosť verejného kľúčaVeľkosť súkromného kľúčaZašifrované dáta
Kyber512800 B1 632 B768 B
Kyber7381 184 B2 400 B1 088 B
Kyber10241 568 B3 168 B1 568 B
Bike1281 541 B3 114 B1 573 B
Bike1923 083 B6 198 B3 115 B
Bike2565 122 B10 276 B5 154 B
HQC1282 249 B2 289 B4 497 B
HQC1924 522 B4 562 B9 042 B
HQC2567 245 B7 285 B14 485 B
McEliece348864261 120 B6 492 B196 B
McEliece460896524 160 B13 608 B156 B
McEliece66881281 044 992 B13 932 B208 B
McEliece69601191 047 319 B13 948 B194 B
McEliece81921281 357 824 B14 120 B208 B
NTRUhps2048509699 B935 B699 B
NTRUhps2048677930 B1 234 B930 B
NTRUhps40968211 230 B1 590 B1 230 B
SIKEp434330 B44 B346 B
SIKEp503378 B56 B402 B
SIKEp751564 B80 B596 B
SIDH564 B48 B596 B
LightSABER672 B1 568 B736 B
SABER992 B2 304 B1 088 B
FireSABER1 312 B3 040 B1 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)}");

Algoritmy pre podpis

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, FalconSPHINCS+.

Nasledujúca tabuľka ukazuje parametre jednotlivých algoritmov.

AlgoritmusVeľkosť verejného kľúčaVeľkosť súkromného kľúčaVeľkosť podpisuSecurity
Crystals Dilithium 2 (Lattice)1 312 B2 528 B2 420 B128-bit
Crystals Dilithium 31 952 B4 000 B3 293 B192-bit
Crystals Dilithium 52 592 B4 864 B4 595 B256-bit
Falcon 512 (Lattice)897 B1 281 B690 B128-bit
Falcon 10241 793 B2 305 B1 330 B256-bit
Rainbow Level Ia (Oil-and-Vineger)161 600 B103 648 B66 B128-bit
Rainbow Level IIIa861 400 B611 300 B164 B192-bit
Rainbow Level Vc1 885 400 B1 375 700 B204 B256-bit
Sphincs SHA256-128f Simple32 B64 B17 088 B128-bit
Sphincs SHA256-192f Simple48 B96 B35 664 B192-bit
Sphincs SHA256-256f Simple64 B128 B49 856 B256-bit
Picnic 3 Full49 B73 B71 179 B192-bit
GeMSS 128352 188 B16 B33 B128-bit
GeMSS 1921 237 964 B24 B53 B128-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}";
}

Upozornenie

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, BIKESIKE. Pričom algoritmus SIKE bude odstránený.

Pre ďalšie čítanie odporúčam nasledujúce zdroje.

Zdroje

  1. https://www.nist.gov/news-events/news/2022/07/nist-announces-first-four-quantum-resistant-cryptographic-algorithms
  2. https://billatnapier.medium.com/post-quantum-cryptography-pqc-with-bouncy-castle-and-c-4424dea684ec
  3. https://www.strathweb.com/2023/02/post-quantum-cryptography-in-net/
  4. https://medium.com/asecuritysite-when-bob-met-alice/goodbye-ecdh-and-hello-to-kyber-46415ef23d30
  5. https://github.com/filipw?tab=repositories&q=&type=source&language=c%23&sort=
  6. https://www.youtube.com/watch?v=JcfcSmwlFZ0