Go-kielen MLDSA:n ja MLKEM:n käyttö
Yleiskatsaus
Tausta
Jo jonkin aikaa kvanttitietokoneiden nopea laskentateho on nähty uhkana olemassa oleville salausjärjestelmille. Nykyiset järjestelmät, kuten RSA tai ECC, voivat olla alttiita kvanttitietokoneiden laskentakyvylle, jonka vuoksi ne voidaan mahdollisesti purkaa. Kuitenkin, kun kvanttitietokoneiden konsepti alkoi hahmottua konkreettisemmin useita vuosia sitten, vaihtoehtojen tutkimus ja kehitys alkoi. Tämän seurauksena NIST on jatkanut PQC:n (kvantinkestävä salaus) standardisointia.
MLDSA ja MLKEM
Lopulta NIST hyväksyi MLKEM:in ja MLDSA:n standardeiksi elokuussa 2024, jotka perustuvat CRYSTALS-Kyberiin ja CRYSTALS-Dilithiumiin. Molemmat algoritmit toimivat MLWE (Module Learning with Errors) -ongelman pohjalta. Tätä muotoa kutsutaan ristikkoon perustuvaksi salaukseksi.
Ristikkoon perustuva salaus on, kuten nimestä voi päätellä, salausjärjestelmä, joka perustuu matemaattisten ongelmien vaikeuteen ristikossa. Minulla ei ole syvällistä matemaattista tietämystä aiheesta, mutta sen voi tiivistää yhteen lauseeseen: se on meluisan lineaarisen yhtälön ratkaiseminen moduuliritikossa
. Vaikka on vaikea hahmottaa, kuinka vaikeaa se on, sanotaan, että tämä ongelma on niin vaikea, ettei edes kvanttitietokone pysty ratkaisemaan sitä.
MLDSA
Katsotaanpa ensin MLDSA:ta.
Rakenne
MLDSA on, kuten nimestä voi päätellä, epäsymmetrinen allekirjoitusalgoritmi, joka käy läpi kaksi vaihetta:
- Allekirjoituksen luominen: Allekirjoituksen luominen viestille käyttämällä yksityistä avainta.
- Allekirjoituksen vahvistaminen: Luodun allekirjoituksen validiteetin vahvistaminen julkisella avaimella.
Lisäksi MLDSA:lla on seuraavat kolme ominaisuutta:
- strong existential unforgeability: Yhdellä allekirjoituksella ja julkisella avaimella ei ole mahdollista luoda toista pätevää allekirjoitusta.
- chosen message attack: Millään viestin allekirjoituksella ei voida luoda uutta pätevää allekirjoitusta julkisella avaimella.
- side-channel attack: Turvallisuus on korkea, sillä allekirjoituksen luomisessa käytetään jatkuvasti uusia satunnaisia arvoja ja viestistä johdettuja pseudosatunnaisia arvoja.
- domain separation: Toistuvien turvallisuusongelmien ehkäisemiseksi eri parametreille käytetään eri siemeniä.
Koodi
Seuraavassa on yksinkertainen esimerkki Go-kielellä.
Tässä esimerkissä käytimme cloudflare/circl mldsa:ta.
1package main
2
3import (
4 "crypto"
5 "crypto/rand"
6 "encoding/base64"
7 "fmt"
8
9 "github.com/cloudflare/circl/sign/mldsa/mldsa44"
10)
11
12func main() {
13 // Luo avaimet mldsa44-spesifikaation mukaan.
14 pub, priv, err := mldsa44.GenerateKey(rand.Reader)
15 if err != nil {
16 panic(err)
17 }
18
19 message := []byte("Hello, World!")
20
21 // Luo allekirjoitus.
22 // Huomioi, että nykyisen version (22.12.2024) mukaan virhe tapahtuu, jos käytetään muuta kuin crypto.Hash(0):aa.
23 signature, err := priv.Sign(rand.Reader, message, crypto.Hash(0))
24 if err != nil {
25 panic(err)
26 }
27
28 encodedSignature := base64.URLEncoding.EncodeToString(signature)
29 fmt.Println(len(encodedSignature), encodedSignature)
30
31 // Vahvista allekirjoitus julkisen avaimen scheme-metodilla.
32 ok := pub.Scheme().Verify(pub, message, signature, nil)
33 fmt.Println(ok)
34}
13228 oaSaOA-...
2true
Allekirjoitusarvo on liian pitkä, joten se on jätetty pois. Jos haluat nähdä koko arvon, kokeile suorittaa se playgroundissa.
Vaikka se on koodattu base64:llä, 3228 tavua on hieman rasittava määrä.
On hieman huolestuttavaa ajatella, että meidän on pian vaihdettava tämän kokoisia allekirjoituksia kvanttitietokoneita vastaan.
MLKEM
Rakenne
MLKEM on avainten kapselointimekanismi (Key Encapsulation Mechanism). KEM on algoritmi, joka mahdollistaa jaetun avaimen luomisen kahden osapuolen välille käyttämällä julkisen avaimen salausta. MLKEM:in avaimenvaihtomekanismi toimii seuraavasti:
- Avainten kapselointi: Lähettäjä luo salatun viestin (cipher text) ja jaetun avaimen käyttämällä vastaanottajan julkista avainta. Tämä salattu viesti välitetään alun perin vastaanottajalle käytettäväksi.
- Avainten dekapselointi: Vastaanottaja purkaa jaetun avaimen salatusta viestistä käyttämällä omaa yksityistä avaintaan.
MLKEM:ssä on yhteensä kolme parametria. On olemassa MLKEM-512, MLKEM-768 ja MLKEM-1024. Mitä pienempi luku on, sitä pienemmät avaimet ja salattu teksti ovat, ja mitä suurempi luku on, sitä pidemmät avaimet ja salattu teksti ovat, ja sitä korkeampi on turvallisuustaso.
Koodi
MLKEM lisätään go 1.24:ään, joten käytimme go 1.24rc1:tä, joka on käytettävissä tällä hetkellä.
1package main
2
3import (
4 "crypto/mlkem"
5 "encoding/base64"
6 "fmt"
7)
8
9func main() {
10 // Luo vastaanottajan PrivateKey.
11 receiverKey, err := mlkem.GenerateKey1024()
12 if err != nil {
13 panic(err)
14 }
15
16 // MLKEM:ssä käytetään termiä EncapsulationKey PublicKey:n sijaan.
17 receiverPubKey := receiverKey.EncapsulationKey()
18
19 // Osoitimme yksinkertaisesti, että EncapsulationKey:n Bytes() ja NewEncapsulationKeyX mahdollistavat avaimen purkamisen ja uudelleenkäytön.
20 // Toki todellisuudessa tämä prosessi tarkoittaa, että lähettäjä luo objektin vastaanottajan EncapsulationKey-avaimesta, joka on julkinen teksti.
21 clonedReceiverPubKey, err := mlkem.NewEncapsulationKey1024(receiverPubKey.Bytes())
22 if err != nil {
23 panic(err)
24 }
25
26 // Encapsulate-metodi luo salatun tekstin ja jaetun avaimen lähettäjälle.
27 cipherText, SenderSharedKey := clonedReceiverPubKey.Encapsulate()
28
29 // Vahvistaaksemme, että vastaanottaja voi tallentaa ja käyttää yksityistä avainta, kopioimme sen.
30 clonedReceiverKey, err := mlkem.NewDecapsulationKey1024(receiverKey.Bytes())
31 if err != nil {
32 panic(err)
33 }
34
35 // Vastaanottaja purkaa salatun tekstin Decapsulate-metodilla käyttäen yksityistä avaintaan ja luo toisen jaetun avaimen.
36 sharedKeyReceiver, err := clonedReceiverKey.Decapsulate(cipherText)
37 if err != nil {
38 panic(err)
39 }
40
41 fmt.Println(base64.StdEncoding.EncodeToString(SenderSharedKey))
42 fmt.Println(base64.StdEncoding.EncodeToString(sharedKeyReceiver))
43}
1Q1ciS818WFHTK7D4MTvsQvciMTGF+dSGqMllOxW80ew=
2Q1ciS818WFHTK7D4MTvsQvciMTGF+dSGqMllOxW80ew=
Lopputuloksena voidaan nähdä, että luodaan saman kokoiset jaetut avaimet!
Tämä koodi on nähtävissä myös playgroundissa.
Johtopäätös
Kunkin algoritmin spesifikaatiot, turvallisuustasot ja yksityisten avainten, julkisten avainten, allekirjoitusten ja salakirjoitusten koot voidaan tiivistää seuraavasti. Jokainen niistä on melko suuri, kuten PQC:n nimestä voi päätellä.
Algoritmi | NIST:n turvallisuustaso | Yksityisen avaimen koko | Julkisen avaimen koko | Allekirjoituksen/salakirjoituksen koko |
---|---|---|---|---|
ML-DSA-44 | 2 | 2,560 | 1,312 | 2,420 |
ML-DSA-65 | 3 | 4,032 | 1,952 | 3,309 |
ML-DSA-87 | 5 | 4,896 | 2,592 | 4,627 |
ML-KEM-512 | 1 | 1,632 | 800 | 768 |
ML-KEM-768 | 3 | 2,400 | 1,184 | 1,088 |
ML-KEM-1024 | 5 | 3,168 | 1,568 | 1,568 |
Näiden algoritmien ansiosta toivomme, että voimme käyttää turvallista internetiä myös kvanttitietokoneissa, mutta on väistämätöntä, että suurentuneet avaimet ja allekirjoitusten/salakirjoitusten koot edellyttävät enemmän laskentatehoa.
Onneksi Go-kieli on toteuttanut kunkin algoritmin tehokkaasti, joten toivon, että niitä käytetään aktiivisesti turvallisuuden ylläpitämiseen sopivissa paikoissa!