---
id: df2ea4cfe0d5ec72a92e1b3cfd4156f2
author: snowmerak
title: Tapasztalataim az MLDSA és az MLKEM Go nyelvben történő használatáról
description: Ebben a útmutatóban bemutatjuk, hogyan használhatók a kvantumszámítógép-ellenálló MLDSA és MLKEM kriptográfiai algoritmusok a Go nyelvben, ismertetjük az egyes algoritmusok jellemzőit, és kódpéldákat adunk.
language: hu
date: 2024-12-22T08:17:58.797764292Z
path: /blog/posts/usage-of-mldsa-and-mlkem-in-the-go-language-zb0442110
category: security
---

## Áttekintés

### Háttér

Már régóta úgy tekintenek a kvantumszámítógépek gyors számításaira, mint az általánosan használt titkosítási rendszerekre leselkedő fenyegetésre. A hagyományos RSA és ECC például azért lehet sebezhető, mert a kvantumszámítógépek ilyen számítási képessége feltörheti őket. Néhány éve azonban, amikor a kvantumszámítógép fogalma kezdett kézzelfoghatóvá válni, elkezdték kutatni és fejleszteni az alternatíváikat, a NIST pedig folytatta a PQC (posztkvantum kriptográfia) szabványosítását.

### MLDSA és MLKEM

A NIST végül 2024 augusztusában szabványként fogadta el a CRYSTALS-Kyber és a CRYSTALS-Dilithium alapján készült MLKEM-et és MLDSA-t. Mindkét algoritmus az MLWE (Module Learning with Errors) problémán alapul. Ezt a típusú megoldást rácsalapú kriptográfiának nevezzük.

A rácsalapú kriptográfia, ahogy a neve is mutatja, olyan titkosítási rendszer, amely a rácsokon értelmezett matematikai problémák nehézségén alapul. Bár nincs mély matematikai tudásom erről, egy mondatban összefoglalva ez a `zajos lineáris egyenletrendszer megoldása moduláris rácsban` probléma. Hogy mennyire nehéz, azt nehéz elképzelni, de állítólag ezek a problémák a kvantumszámítógépekkel sem oldhatók meg.

## MLDSA

Először tehát az MLDSA-ról tanulunk.

### Felépítés

Ahogy a nevéből is látszik, az MLDSA egy aszimmetrikus aláírási algoritmus, amely összesen a következő két lépésből áll:

1. Aláírás generálása: a privát kulccsal aláírást hozunk létre az üzenethez
2. Aláírás ellenőrzése: a nyilvános kulcs segítségével ellenőrizzük a generált aláírás érvényességét

Az MLDSA-nak emellett a következő 4 tulajdonsága van:

1. Erős létezésbeli hamisíthatatlanság (strong existential unforgeability): egy aláírás és a nyilvános kulcs alapján nem lehet más, érvényes aláírást létrehozni.
2. Választott üzenetes támadás (chosen message attack): egyetlen üzenet aláírásával sem lehet a nyilvános kulcs birtokában új, érvényes aláírást létrehozni.
3. Oldalcsatornás támadás (side-channel attack): aláírás során mindig új véletlen értékeket és az üzenetből származtatott pszeudovéletlen értékeket használ, ezért a biztonsága magas.
4. Tartomány-szétválasztás (domain separation): különböző paraméterekhez különböző seedeket használ, ezzel megelőzve az ismétlődésből adódó biztonsági problémákat.

### Kód

Most bemutatok egy egyszerű Go nyelvű példakódot.
Ebben a példában a [cloudflare/circl](github.com/cloudflare/circl) csomag mldsa moduljátt használtam.

```go
package main

import (
	"crypto"
	"crypto/rand"
	"encoding/base64"
	"fmt"

	"github.com/cloudflare/circl/sign/mldsa/mldsa44"
)

func main() {
    // mldsa44 specifikációval generálunk kulcsot.
	pub, priv, err := mldsa44.GenerateKey(rand.Reader)
	if err != nil {
		panic(err)
	}

	message := []byte("Hello, World!")

    // Aláírást generálunk.
    // Fontos megjegyezni, hogy 2024. december 22-i verzió szerint a crypto.Hash(0) használata nélkül hiba lép fel.
	signature, err := priv.Sign(rand.Reader, message, crypto.Hash(0))
	if err != nil {
		panic(err)
	}

	encodedSignature := base64.URLEncoding.EncodeToString(signature)
	fmt.Println(len(encodedSignature), encodedSignature)

    // A nyilvános kulcs scheme metódusát hívva elvégezzük az ellenőrzést.
	ok := pub.Scheme().Verify(pub, message, signature, nil)
	fmt.Println(ok)
}
```

```
3228 oaSaOA-...
true
```

> A aláírás értéke túl hosszú, ezért kihagytam. Ha teljes egészében szeretnéd látni, futtasd le a [playground](https://go.dev/play/p/nqbUnKpFW3j) oldalon.

Bár base64-gyel kódoltuk, a 3228 bájt elég nagy méret, ami kissé terhesnek tűnhet.
Ha belegondolunk, hogy a közeljövőben a kvantumszámítógépek ellen védő aláírásokat kell majd cserélnünk ekkora méretben, az valóban kissé nyomasztó.

## MLKEM

### Felépítés

Az MLKEM egy kulcsbeágyazási mechanizmus (Key Encapsulation Mechanism, KEM). A KEM olyan algoritmus, amely nyilvános kulcsú titkosítást használva lehetővé teszi, hogy két fél között közös kulcs jöjjön létre. Az MLKEM kulcscsere-mechanizmusa a következő lépésekből áll:

1. Kulcsbeágyazás: a küldő a címzett nyilvános kulcsával létrehozza a titkosított üzenetet (ciphertext) és a megosztott kulcsot (shared key). Ezt a titkosított üzenetet a címzettnek továbbítja, hogy az felhasználhassa.
2. Kulcs-kibontás: a címzett a saját privát kulcsával kinyeri a megosztott kulcsot a titkosított üzenetből.

Az MLKEM-nek összesen 3 paramétere van: MLKEM-512, MLKEM-768 és MLKEM-1024. Minél kisebb a szám, annál kisebb kulcsokat és titkosított szöveget kapunk; minél nagyobb, annál hosszabb kulcsok és titkosított szövegek keletkeznek, és annál magasabb a biztonsági szint.

### Kód

Az MLKEM a Go 1.24-ben várhatóan megjelenik, ezért a jelenleg használható go 1.24rc1 verziót alkalmaztam.

```go
package main

import (
	"crypto/mlkem"
	"encoding/base64"
	"fmt"
)

func main() {
    // Létrehozzuk a címzett PrivateKey-ét.
	receiverKey, err := mlkem.GenerateKey1024()
	if err != nil {
		panic(err)
	}

    // Az MLKEM-ben a PublicKey helyett az EncapsulationKey kifejezést használjuk.
	receiverPubKey := receiverKey.EncapsulationKey()

    // Azért klónozom le, hogy bemutassam, hogyan lehet a kulcsot Bytes() és NewEncapsulationKeyX segítségével kinyerni és újra felhasználni.
    // Valójában ez a folyamat úgy tekinthető, mint amikor a küldő szöveges formában nyilvánosan elérhető címzetti EncapsulationKey-ből objektumot hoz létre.
	clonedReceiverPubKey, err := mlkem.NewEncapsulationKey1024(receiverPubKey.Bytes())
	if err != nil {
		panic(err)
	}

    // Az Encapsulate segítségével a küldő létrehozza a titkosított szöveget és a megosztott kulcsot.
	cipherText, SenderSharedKey := clonedReceiverPubKey.Encapsulate()

    // Azért klónozom le a címzett privát kulcsát, hogy bemutassam, hogyan lehet tárolni és visszaolvasni.
	clonedReceiverKey, err := mlkem.NewDecapsulationKey1024(receiverKey.Bytes())
	if err != nil {
		panic(err)
	}

    // A címzett a privát kulcsával Decapsulate-eli a titkosított szöveget, és így létrehozza a másik megosztott kulcsot.
	sharedKeyReceiver, err := clonedReceiverKey.Decapsulate(cipherText)
	if err != nil {
		panic(err)
	}

	fmt.Println(base64.StdEncoding.EncodeToString(SenderSharedKey))
	fmt.Println(base64.StdEncoding.EncodeToString(sharedKeyReceiver))
}
```

```sh
Q1ciS818WFHTK7D4MTvsQvciMTGF+dSGqMllOxW80ew=
Q1ciS818WFHTK7D4MTvsQvciMTGF+dSGqMllOxW80ew=
```

Ennek eredményeként láthatjuk, hogy azonos méretű megosztott kulcs jön létre!

Ez a kód a [playground](https://go.dev/play/p/n_cxNp435Qn?v=gotip) oldalon is megtekinthető.

## Következtetés

Az egyes algoritmusok specifikációi, biztonsági szintjei, valamint a privát kulcsok, nyilvános kulcsok, aláírások és titkosított szövegek méretei a következőképpen foglalhatók össze. Mindegyikük méltó a PQC elnevezéshez, nagy méretekkel büszkélkedve.

| Algoritmus  | NIST biztonsági szint | Privát kulcs mérete | Nyilvános kulcs mérete | Aláírás/titkosított szöveg mérete |
| ----------- | --------------------- | ------------------- | ---------------------- | --------------------------------- |
| 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                             |

Ezekkel az algoritmusokkal reméljük, hogy a kvantumszámítógépek korában is elég biztonságos lesz az internet, azonban a megnövekedett kulcs- és aláírás-/titkosítottszöveg-méretek miatt várhatóan több számításra lesz szükség, amit nem lehet elkerülni.

Mindazonáltal a Go nyelv hatékonyan implementálja ezeket az algoritmusokat, ezért bízom benne, hogy megfelelő helyeken aktívan hozzájárulnak majd a biztonságod védelméhez!
