Yeterince büyük bir kuantum bilgisayar, Açık Anahtar Kriptografisi sayfasındaki her eğri üzerinde RSA'yı, X25519/X448'i ve ECDSA/ECDH'yi kırar: bu matematiğin hiçbiri Shor'un algoritmasına dayanamaz. Bunun bir sorun olması için bugün var olması gerekmez; bir düşman şifreli trafiği şimdi kaydedebilir ve böyle bir makine var olduğunda şifresini çözebilir; bu genellikle "şimdi topla, sonra çöz" olarak adlandırılan bir stratejidir. Günler değil yıllar boyunca gizli kalması gereken her şey, zaten kuantum sonrası anahtar değişimine geçiyor olmalıdır.
NIST üç şemayı standartlaştırdı; hepsi burada uygulanmıştır ve hepsi yalnızca SHAKE üzerine kuruludur (bkz. Hash'leme ve Mesaj Kimlik Doğrulama), bu yüzden güvenlikleri yalnızca hash'in sağlam olmasına dayanır: kırılacak hiçbir kafes veya sayı teorisi varsayımı yoktur.
| Şema | Amaç | Standart | Birim |
| ML-KEM | Anahtar kapsülleme, Diffie-Hellman'ın yerini alır | FIPS 203 | sgcCrypto_MLKEM |
| ML-DSA | İmzalar, kafes tabanlı, varsayılan seçim | FIPS 204 | sgcCrypto_MLDSA |
| SLH-DSA | İmzalar, yalnızca hash tabanlı, muhafazakar yedek seçenek | FIPS 205 | sgcCrypto_SLHDSA |
ML-KEM ve hibrit yapı (önerilir)
ML-KEM, bir Diffie-Hellman değişimini değiştirir: gönderen, alıcının açık anahtarına paylaşılan bir gizli değeri kapsüller, alıcı bunu özel anahtarla açar ve her ikisi de aynı 32 bayta ulaşır. Daha büyük olanı daha büyük bir güvenlik marjı ve daha büyük anahtarlar anlamına gelen üç parametre kümesiyle gelir.
procedure sgcMLKEM_GenerateKeyPair(aParams: TsgcMLKEMParams; out aPublicKey, aPrivateKey: TBytes);
procedure sgcMLKEM_Encapsulate(aParams: TsgcMLKEMParams; const aPublicKey: TBytes; out aCiphertext, aSharedSecret: TBytes);
function sgcMLKEM_Decapsulate(aParams: TsgcMLKEMParams; const aPrivateKey, aCiphertext: TBytes): TBytes;
var
oPub, oPriv, oCiphertext, oSecretA, oSecretB: TBytes;
begin
sgcMLKEM_GenerateKeyPair(mlkem768, oPub, oPriv);
sgcMLKEM_Encapsulate(mlkem768, oPub, oCiphertext, oSecretA); { sender }
oSecretB := sgcMLKEM_Decapsulate(mlkem768, oPriv, oCiphertext); { recipient }
{ oSecretA = oSecretB }
end;
FIPS 203 açma (decapsulation) asla başarısız olmaz.
Bozuk veya kötü niyetli bir şifreli metin bir hata vermez; sessizce özel anahtara gömülü örtük bir reddetme değerinden türetilen farklı bir gizli değer döndürür. Bunun yerine bir hata döndürmek, bir saldırgana özel anahtarı araştırmak için bir şifre çözme kehanet aracı (oracle) verirdi; standart, bunu tasarım gereği önler. Türetilen gizli değerin koruduğu her ne ise, uyumsuzluğu kendi başına tespit etmek zorundadır; örneğin akışın devamında doğrulaması başarısız olan bir AEAD etiketi gibi.
Bugün gerçekten devreye alınması gereken şey hibrit yapıdır: ML-KEM-768 ile birleştirilmiş X25519, böylece paylaşılan gizli değer ikisine de bağlıdır. ML-KEM bir kriptanaliz ilerlemesiyle bir gün kırılırsa güvenli kalır ve bir kuantum bilgisayar X25519'u kırarsa güvenli kalır; bir saldırganın ikisinin de aynı anda başarısız olmasına ihtiyacı vardır.
procedure sgcHybrid_GenerateKeyPair(out aPublicKey, aPrivateKey: TBytes);
procedure sgcHybrid_Encapsulate(const aPublicKey: TBytes; out aCiphertext, aSharedSecret: TBytes);
function sgcHybrid_Decapsulate(const aPrivateKey, aCiphertext: TBytes; out aSharedSecret: TBytes): Boolean;
X-Wing ve TLS 1.3 hibrit grupları
sgcCrypto_MLKEM_Hybrid üç hibrit aile barındırır. Yukarıdaki sgcHybrid_ fonksiyonları özgün sgcCrypto biçimidir ve uyumluluk için korunmaktadır. X-Wing, standartlaştırılmış genel amaçlı hibrit KEM'dir, ML-KEM-768 ile birleştirilmiş X25519'dur, ve TLS dışındaki yeni kodda kullanılması gereken odur. Üçüncü aile yalnızca TLS 1.3 hibrit anahtar paylaşımlarını oluşturur, başka hiçbir şey yapmaz.
X-Wing (draft-connolly-cfrg-xwing-kem-10) tek bir gizli değer saklar: özel anahtar 32 baytlık bir tohumdur ve her işlem onu ihtiyaç duyduğu ML-KEM-768 ve X25519 materyaline genişletir. Açık anahtar 1216 bayt, şifreli metin 1120 bayt ve paylaşılan gizli değer 32 bayttır. Kapsülleme, FIPS 203 kapsülleme anahtarı denetimini çalıştırır ve açık anahtar bu denetimden geçemediğinde hata verir.
procedure sgcXWing_GenerateKeyPair(out aPublicKey, aPrivateKey: TBytes);
procedure sgcXWing_Encapsulate(const aPublicKey: TBytes; out aCiphertext, aSharedSecret: TBytes);
function sgcXWing_Decapsulate(const aPrivateKey, aCiphertext: TBytes; out aSharedSecret: TBytes): Boolean;
var
oPub, oPriv, oCiphertext, oSecretA, oSecretB: TBytes;
begin
sgcXWing_GenerateKeyPair(oPub, oPriv);
sgcXWing_Encapsulate(oPub, oCiphertext, oSecretA); { sender }
if sgcXWing_Decapsulate(oPriv, oCiphertext, oSecretB) then
{ oSecretA = oSecretB };
end;
RFC 10024'ün TLS 1.3 hibrit anahtar paylaşımları X25519MLKEM768, SecP256r1MLKEM768 ve SecP384r1MLKEM1024'tür; IANA kod noktaları 0x11EC, 0x11EB ve 0x11ED'dir. Bunlar tek başlarına kullanabileceğiniz KEM'ler değildir. Paylaşılan gizli değer iki yarının düz birleştirilmesidir; bu yalnızca TLS onu el sıkışma dökümüyle birlikte kendi anahtar çizelgesine verdiği için güvenlidir, bu yüzden bunları yalnızca bir TLS anahtar paylaşımı oluşturmak için kullanın, başka hiçbir şey için değil. Native TLS motoru varsayılan olarak ilk sırada X25519MLKEM768 önerir, bu yüzden onu kullanan bir istemci veya sunucu, fazladan hiçbir kod olmadan zaten kuantum sonrası bir anahtar değişimi müzakere eder.
Hibrit gruplar yalnızca TLS 1.3'te bulunur. Yerel motor TLS 1.2'yi de konuşur, ve eşin TLS 1.3 yapamaması nedeniyle ona geri dönen bir bağlantı, kuantum sonrası korumadan yoksun klasik bir grup kullanır: X25519, secp256r1 veya secp384r1. Anahtar değişiminin her zaman kuantum sonrası olması gerektiğinde, bir istemcide TLSOptions.Version veya bir sunucuda SSLOptions.Version değerini tls1_3 olarak ayarlayın, ve NativeTLS_Options.Groups içinde yalnızca hibrit grupları listeleyin.
Kuantum Sonrası TLS demosu, Demos\18.Cryptography\08.PostQuantum_TLS, TLS 1.3 ve TLS 1.2, yalnızca TLS 1.3 ve yalnızca TLS 1.2 seçenekleriyle bir TLS sürümü seçici ve bir şifre paketi seçici sunar, ve durum satırı müzakere edilen sürümü, grubu ve şifre paketini gösterir. Sunucu demosu, yalnızca TLS 1.3 istemcilerine hizmet eden bir ML-DSA-44 sertifikasıyla imzalayabilir, çünkü TLS 1.2'de ML-DSA imza şeması yoktur.
type
TsgcTLSHybridGroup = (thgX25519MLKEM768, thgSecP256r1MLKEM768, thgSecP384r1MLKEM1024);
function sgcTLSHybrid_GroupID(aGroup: TsgcTLSHybridGroup): Word;
function sgcTLSHybrid_GroupName(aGroup: TsgcTLSHybridGroup): string;
function sgcTLSHybrid_Available(aGroup: TsgcTLSHybridGroup): Boolean;
procedure sgcTLSHybrid_ClientKeyShare(aGroup: TsgcTLSHybridGroup; out aKeyShare, aPrivateState: TBytes);
function sgcTLSHybrid_ServerKeyShare(aGroup: TsgcTLSHybridGroup; const aClientKeyShare: TBytes;
out aKeyShare, aSharedSecret: TBytes): Boolean;
function sgcTLSHybrid_ClientSharedSecret(aGroup: TsgcTLSHybridGroup;
const aPrivateState, aServerKeyShare: TBytes; out aSharedSecret: TBytes): Boolean;
İstemci aPrivateState'i gizli tutar, onu değiştirmeden sgcTLSHybrid_ClientSharedSecret fonksiyonuna geçirir ve sonrasında siler; yerleşimi API'nin bir parçası değildir. İki Boolean fonksiyon, geçersiz her eş girdisinde tüm çıktılar boş olacak şekilde False döndürür: yanlış uzunlukta bir anahtar paylaşımı, FIPS 203 denetiminden geçemeyen bir ML-KEM kapsülleme anahtarı, eğri üzerinde olmayan bir nokta veya tamamı sıfır olan bir X25519 sonucu. RFC 10024, bu durumların her birinde bağlantının bir illegal_parameter uyarısıyla sonlandırılmasını gerektirir.
X25519 üzerine kurulu olan her şey, yani sgcHybrid_ fonksiyonları, X-Wing ve X25519MLKEM768 grubu, bir SGC_CRYPTO_FIPS derlemesinde derleme dışı bırakılır; bkz. FIPS Modu. İki SecP grubu kalır, çünkü P-256, P-384 ve ML-KEM'in hepsi onaylı algoritmalardır. Bir grubu önermeden veya kabul etmeden önce, orada olduğunu varsaymak yerine sgcTLSHybrid_Available fonksiyonunu çağırın.
ML-DSA (imzalar için önerilir)
İmzalama bir maskeleme vektörü çeker ve bir imza oluşturmayı dener; deneme anahtar hakkında bilgi sızdıracaksa yeniden başlar; beklenen deneme sayısı küçüktür ama sabit değildir, bu yüzden imzalama değişken bir süre alır. Bu şemaya özgüdür ve anahtar üzerinde bir yan kanal değildir. İmzalar büyüktür: Ed25519 için 64'e karşı ML-DSA-44 için 2420 bayt, ve açık anahtarlar 32'ye karşı 1312 bayt; bu yüzden boyuta duyarlı bir protokolde bunu benimsemeden önce farkı bütçeleyin.
procedure sgcMLDSA_GenerateKeyPair(aParams: TsgcMLDSAParams; out aPublicKey, aPrivateKey: TBytes);
function sgcMLDSA_Sign(aParams: TsgcMLDSAParams; const aPrivateKey, aMessage, aContext: TBytes): TBytes;
function sgcMLDSA_Verify(aParams: TsgcMLDSAParams; const aPublicKey, aMessage, aSignature, aContext: TBytes): Boolean;
var
oPub, oPriv, oSignature, oEmpty: TBytes;
begin
sgcMLDSA_GenerateKeyPair(mldsa44, oPub, oPriv);
oSignature := sgcMLDSA_Sign(mldsa44, oPriv, oMessage, oEmpty);
if sgcMLDSA_Verify(mldsa44, oPub, oMessage, oSignature, oEmpty) then
{ valid };
end;
SLH-DSA (muhafazakar yedek seçenek)
SLH-DSA yalnızca hash fonksiyonuna dayanır: gelecekte herhangi bir noktada kırılacak hiçbir kafes problemi yoktur. Bu garanti pahalıdır. Bir imza, en küçüğü olan SLH-DSA-SHAKE-128s için 7856 bayttan, en büyüğü olan SLH-DSA-SHAKE-256f için 49856 bayta kadar uzanır; ve bir s (küçük) parametre kümesiyle imzalamak yüz binlerce hash işleminde dolaşır ve onlarca saniye sürebilir; f (hızlı) kümeleri, imza boyutunun kabaca iki katı pahasına bir ile yedi saniye civarında imzalar. Doğrulama her parametre kümesi için hızlıdır; bu da etkileşimli bir protokolden daha çok, aygıt yazılımı veya kod imzalama gibi nadiren-imzala-sıkça-doğrula kullanım durumuna uyar.
procedure sgcSLHDSA_GenerateKeyPair(aParams: TsgcSLHDSAParams; out aPublicKey, aPrivateKey: TBytes);
function sgcSLHDSA_Sign(aParams: TsgcSLHDSAParams; const aPrivateKey, aMessage, aContext: TBytes;
aDeterministic: Boolean = True): TBytes;
function sgcSLHDSA_Verify(aParams: TsgcSLHDSAParams; const aPublicKey, aMessage, aSignature, aContext: TBytes): Boolean;
Anahtar biçimleri: SubjectPublicKeyInfo, PKCS#8 ve PEM
FIPS algoritmalarının tükettiği ham bayt dizileri bir saklama biçimi değildir ve başka hiçbir uygulama bunları okumaz. Bir anahtarı diske yazmak, bir sertifikaya koymak veya başka bir kütüphaneye vermek için onu standart kapsayıcılarda dışa aktarın: açık anahtar için bir X.509 SubjectPublicKeyInfo, özel anahtar için bir PKCS#8 OneAsymmetricKey ve ikisinin de çevresinde PUBLIC KEY ve PRIVATE KEY etiketli PEM zırhı (RFC 7468). Üç şema da aynı sekiz fonksiyonu sunar ve her biri kendi kodlamasını tanımlayan RFC'yi izler.
| Şema | Kapsayıcı RFC | DER fonksiyonları | PEM fonksiyonları |
| ML-DSA | RFC 9881 | sgcMLDSA_ExportSubjectPublicKeyInfo, sgcMLDSA_ImportSubjectPublicKeyInfo, sgcMLDSA_ExportPrivateKeyInfo, sgcMLDSA_ImportPrivateKeyInfo | sgcMLDSA_ExportPublicKeyPEM, sgcMLDSA_ImportPublicKeyPEM, sgcMLDSA_ExportPrivateKeyPEM, sgcMLDSA_ImportPrivateKeyPEM |
| ML-KEM | RFC 9935 | sgcMLKEM_ExportSubjectPublicKeyInfo, sgcMLKEM_ImportSubjectPublicKeyInfo, sgcMLKEM_ExportPrivateKeyInfo, sgcMLKEM_ImportPrivateKeyInfo | sgcMLKEM_ExportPublicKeyPEM, sgcMLKEM_ImportPublicKeyPEM, sgcMLKEM_ExportPrivateKeyPEM, sgcMLKEM_ImportPrivateKeyPEM |
| SLH-DSA | RFC 9909 | sgcSLHDSA_ExportSubjectPublicKeyInfo, sgcSLHDSA_ImportSubjectPublicKeyInfo, sgcSLHDSA_ExportPrivateKeyInfo, sgcSLHDSA_ImportPrivateKeyInfo | sgcSLHDSA_ExportPublicKeyPEM, sgcSLHDSA_ImportPublicKeyPEM, sgcSLHDSA_ExportPrivateKeyPEM, sgcSLHDSA_ImportPrivateKeyPEM |
Algoritma tanımlayıcısı, parametreler yokken NIST nesne tanımlayıcısını taşır, bu yüzden parametre kümesi anahtarla birlikte seyahat eder ve içe aktarma onu döndürür. sgcMLDSA_OID, sgcMLKEM_OID ve sgcSLHDSA_OID noktalı dizeyi verir, ve eşleşen ParamsFromOID fonksiyonları birini geri eşler.
ML-DSA ve ML-KEM için üç özel anahtar biçimi.
Dışa aktarma fonksiyonları, sgcCrypto_DER içinde bildirilen TsgcPQCPrivateKeyFormat türünde bir aFormat parametresi alır. Varsayılan olan pqkfSeed, yalnızca tohumu yazar; ML-DSA için 32 bayt ve ML-KEM için 64 baytlık d || z. Her iki RFC'nin de önerdiği biçim budur ve açık ara en küçüğüdür. pqkfExpanded, genişletilmiş FIPS özel anahtarını yazar. pqkfBoth ikisini de yazar ve genişletilmiş anahtar tohumun genişlemesi değilse hata verir; RFC'lerin bozuk anahtar dediği şey budur.
Bir tohum, sonradan genişletilmiş bir anahtardan geri elde edilemez, bu yüzden önerilen biçimi saklamayı düşünüyorsanız onu üretim anında sgcMLDSA_GenerateKeyPairAndSeed veya sgcMLKEM_GenerateKeyPairAndSeed ile isteyin. SLH-DSA'nın tek bir özel anahtar biçimi vardır, SK.seed || SK.prf || PK.seed || PK.root, bu yüzden dışa aktarması bir biçim parametresi almaz.
function sgcMLDSA_ExportPrivateKeyPEM(aParams: TsgcMLDSAParams; const aSeed, aPrivateKey: TBytes;
aFormat: TsgcPQCPrivateKeyFormat = pqkfSeed): string;
function sgcMLDSA_ImportPrivateKeyPEM(const aPEM: string; out aParams: TsgcMLDSAParams;
out aSeed, aPrivateKey, aPublicKey: TBytes): Boolean;
var
vParams: TsgcMLDSAParams;
oSeed, oPub, oPriv: TBytes;
vPublicPEM, vPrivatePEM: string;
begin
sgcMLDSA_GenerateKeyPairAndSeed(mldsa65, oSeed, oPub, oPriv);
vPublicPEM := sgcMLDSA_ExportPublicKeyPEM(mldsa65, oPub);
vPrivatePEM := sgcMLDSA_ExportPrivateKeyPEM(mldsa65, oSeed, oPriv, pqkfSeed);
{ reading it back: the parameter set comes from the key itself }
if sgcMLDSA_ImportPrivateKeyPEM(vPrivatePEM, vParams, oSeed, oPriv, oPub) then
{ vParams = mldsa65, and oPriv and oPub are the expansion of oSeed };
end;
İçe aktarma doğrular, güvenmez.
Her içe aktarma fonksiyonu hata vermek yerine False döndürür; bozuk DER'de, artık veride, bilinmeyen bir nesne tanımlayıcısında, yok olması gerekirken var olan parametrelerde ve uzunluğu parametre kümesiyle eşleşmeyen bir anahtarda False döndürür. Yapının ötesinde, bir ML-KEM açık anahtarı FIPS 203 modül denetiminden geçmelidir, genişletilmiş bir ML-KEM özel anahtarı hash denetiminden ve ikili tutarlılık testinden geçmelidir, ve genişletilmiş bir ML-DSA özel anahtarı kendi açık anahtarına yeniden inşa edilir, böylece saklanan t0 ve tr değerlerinin ikisi de onunla uyuşmak zorundadır. Özel anahtarla eşleşmeyen gömülü bir açık anahtar reddedilir. Bir özel anahtar bir tohum taşıdığında üç çıktı da dolu gelir, bu yüzden bir çağıranın onu ayrıca genişletmesi hiç gerekmez.
sgcSLHDSA_ImportPrivateKeyInfo ve sgcSLHDSA_ImportPrivateKeyPEM, varsayılanı True olan fazladan bir aVerify parametresi alır; bu parametre PK.root değerini özel tohumdan yeniden hesaplar ve saklanan kökü farklı olan bir anahtarı reddeder. Bu yeniden inşa, bir anahtar üretimi kadar pahalıdır; bu da s parametre kümeleri için saniyeler demektir, bu yüzden False değerini yalnızca kendi uygulamanızın ürettiği veya zaten güvendiği anahtarlar için geçirin. False olduğunda da nesne tanımlayıcısı, uzunluklar ve yapı yine denetlenir.
Kütüphanenin geri kalanının okuduğu kapsayıcılar bunlardır. Bir PKCS#8 ML-DSA özel anahtarı, JWT istemcisinin imzaladığı şeydir, bir SubjectPublicKeyInfo ise JWT sunucusunun doğruladığı şeydir, ve ikisi de Sertifikalar ve PKI sayfasının bir sertifikaya veya bir sertifika imzalama isteğine koyduğu şeydir.
Bir parametre kümesi seçme
Her boyut çağrısı (sgcMLKEM_PublicKeySize, sgcMLDSA_SignatureSize, sgcSLHDSA_SignatureSize ve bunların PrivateKeySize karşılıkları), işlemin kendisiyle aynı parametre sıralamasını (enum) alır; böylece bir protokol, herhangi bir kriptografi yapmadan önce arabelleklerini boyutlandırabilir:
| Parametre kümesi | Açık anahtar | Özel anahtar | Şifreli metin / İmza |
| ML-KEM-512 | 800 | 1632 | 768 |
| ML-KEM-768 | 1184 | 2400 | 1088 |
| ML-KEM-1024 | 1568 | 3168 | 1568 |
| ML-DSA-44 | 1312 | 2560 | 2420 |
| ML-DSA-65 | 1952 | 4032 | 3309 |
| ML-DSA-87 | 2592 | 4896 | 4627 |
| SLH-DSA-SHAKE-128s | 32 | 64 | 7856 |
| SLH-DSA-SHAKE-128f | 32 | 64 | 17088 |
| SLH-DSA-SHAKE-192s | 48 | 96 | 16224 |
| SLH-DSA-SHAKE-192f | 48 | 96 | 35664 |
| SLH-DSA-SHAKE-256s | 64 | 128 | 29792 |
| SLH-DSA-SHAKE-256f | 64 | 128 | 49856 |
Tüm boyutlar bayt cinsindendir. ML-KEM paylaşılan gizli değeri, parametre kümesinden bağımsız olarak her zaman 32 bayttır (sgcMLKEM_SharedSecretSize).