---
id: df2ea4cfe0d5ec72a92e1b3cfd4156f2
author: snowmerak
title: Skúsenosti s používaním MLDSA a MLKEM v jazyku Go
description: V jazyku Go si predstavíme použitie postkvantovej kryptografie MLDSA a MLKEM, opíšeme charakteristiky jednotlivých algoritmov a poskytneme ukážky kódu.
language: sk
date: 2024-12-22T08:17:58.797764292Z
path: /blog/posts/usage-of-mldsa-and-mlkem-in-the-go-language-zb0442110
category: security
---

## Prehľad

### Pozadie

Už dlhší čas sa rýchle výpočty kvantových počítačov považujú za hrozbu pre existujúce kryptografické systémy. Tradičné algoritmy ako RSA alebo ECC by mohli byť dešifrované práve vďaka tejto výpočtovej schopnosti kvantových počítačov. Keď však pred niekoľkými rokmi začal pojem kvantového počítača nadobúdať konkrétnejšie kontúry, začali sa skúmať a vyvíjať alternatívy, a NIST pokračuje v štandardizácii PQC (post-kvantovej kryptografie).

### MLDSA a MLKEM

NIST nakoniec v auguste 2024 prijal ako štandardy MLKEM a MLDSA, ktoré vychádzajú z CRYSTALS-Kyber a CRYSTALS-Dilithium. Oba algoritmy fungujú na základe problému MLWE (Module Learning with Errors). Tento typ označujeme ako kryptografiu založenú na mriežkach.

Kryptografia založená na mriežkach je, ako už názov napovedá, kryptografický systém založený na obtiažnosti matematických úloh na mriežkach. Ani ja nemám hlboké matematické znalosti v tejto oblasti, no zhrnuté jednou vetou ide o problém `riešenia lineárnych rovníc s šumom v modulárnej mriežke`. Aký je to problém v praxi, si neviem celkom predstaviť, no údajne je natoľko náročný, že ho nemožno vyriešiť ani kvantovým počítačom.

## MLDSA

Najprv sa pozrieme na MLDSA.

### Zloženie

MLDSA je, ako napovedá jeho názov, algoritmus asymetrického podpisu a prebieha v nasledujúcich dvoch krokoch.

1. Generovanie podpisu: pomocou súkromného kľúča sa vytvorí podpis správy
2. Overenie podpisu: pomocou verejného kľúča sa overí platnosť vytvoreného podpisu

MLDSA má navyše tieto tri vlastnosti.

1. strong existential unforgeability: z jedného podpisu a verejného kľúča nemožno vytvoriť iný platný podpis.
2. chosen message attack: ani na základe podpisu ľubovoľnej správy nemožno pomocou verejného kľúča vytvoriť nový platný podpis.
3. side-channel attack: pri podpisovaní sa neustále používajú nové náhodné hodnoty a pseudonáhodné hodnoty odvodené zo správy, čím sa zvyšuje bezpečnosť.
4. domain separation: pre rôzne parametre sa používajú rôzne seedy, čím sa predchádza opakovaným bezpečnostným problémom.

### Kód

Teraz ukážem jednoduchý príklad kódu v jazyku Go.
V tomto príklade sa používa mldsa z [cloudflare/circl](github.com/cloudflare/circl).

```go
package main

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

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

func main() {
    // Vygenerujeme kľúč so špecifikáciou mldsa44.
	pub, priv, err := mldsa44.GenerateKey(rand.Reader)
	if err != nil {
		panic(err)
	}

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

    // Vytvoríme podpis.
    // Treba si dať pozor na to, že k dátumu 22. decembra 2024 v aktuálnej verzii vyvolá chybu, ak nie je crypto.Hash(0).
	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)

    // Overenie vykonáme volaním scheme verejného kľúča.
	ok := pub.Scheme().Verify(pub, message, signature, nil)
	fmt.Println(ok)
}
```

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

> Hodnota podpisu je príliš dlhá, preto bola vynechaná. Ak chcete vidieť celý výstup, spustite ho na [playground](https://go.dev/play/p/nqbUnKpFW3j).

Aj keď je výsledok zakódovaný v base64, 3228 bajtov je isto dosť veľa.
Keď si uvedomíme, že v blízkej budúcnosti budeme možno musieť takto veľké podpisy vymieňať kvôli ochrane pred kvantovými počítačmi, je to trochu znepokojujúce..

## MLKEM

### Zloženie

MLKEM je mechanizmus zapuzdrenia kľúča (Key Encapsulation Mechanism). KEM je algoritmus, ktorý umožňuje vytvoriť zdieľaný kľúč medzi dvoma stranami pomocou šifrovania verejným kľúčom. Výmena kľúčov v MLKEM prebieha v nasledujúcich krokoch.

1. Zapuzdrenie kľúča: odosielateľ pomocou verejného kľúča príjemcu vytvorí zašifrovanú správu (cipher text) a zdieľaný kľúč (shared key). Túto zašifrovanú správu odošle príjemcovi, aby ju mohol použiť.
2. Rozbalenie kľúča: príjemca pomocou svojho súkromného kľúča extrahuje zdieľaný kľúč zo zašifrovanej správy.

MLKEM má celkovo 3 parametre: MLKEM-512, MLKEM-768 a MLKEM-1024. Čím menší parameter, tým menšie kľúče a šifrový text; čím väčší, tým dlhšie kľúče a šifrový text a tým vyššia úroveň bezpečnosti.

### Kód

MLKEM má byť pridaný až v Go 1.24, preto som na použitie v súčasnosti zvolil go 1.24rc1.

```go
package main

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

func main() {
    // Vygenerujeme súkromný kľúč príjemcu.
	receiverKey, err := mlkem.GenerateKey1024()
	if err != nil {
		panic(err)
	}

    // V MLKEM sa namiesto pojmu PublicKey používa pojem EncapsulationKey.
	receiverPubKey := receiverKey.EncapsulationKey()

    // Pre jednoduchosť sme EncapsulationKey extrahovali pomocou Bytes() a znova vytvorili pomocou NewEncapsulationKeyX, aby sme ukázali, že ho možno znova použiť.
    // V praxi ide o to, že odosielateľ z textovej podoby verejného EncapsulationKey príjemcu, ktorý je zverejnený, vytvorí objekt.
	clonedReceiverPubKey, err := mlkem.NewEncapsulationKey1024(receiverPubKey.Bytes())
	if err != nil {
		panic(err)
	}

    // Pomocou Encapsulate odosielateľ vytvorí šifrovaný text a zdieľaný kľúč.
	cipherText, SenderSharedKey := clonedReceiverPubKey.Encapsulate()

    // Úmyselne klonujeme, aby sme ukázali uloženie a obnovenie súkromného kľúča príjemcu.
	clonedReceiverKey, err := mlkem.NewDecapsulationKey1024(receiverKey.Bytes())
	if err != nil {
		panic(err)
	}

    // Príjemca pomocou svojho súkromného kľúča Decapsulate šifrovaný text a vytvorí ďalší zdieľaný kľúč.
	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=
```

Výsledkom je, že sa vytvoria zdieľané kľúče rovnakej veľkosti, čo môžeme overiť!

Tento kód si môžete vyskúšať aj na [playground](https://go.dev/play/p/n_cxNp435Qn?v=gotip).

## Záver

Špecifikácie jednotlivých algoritmov, úroveň bezpečnosti a veľkosti súkromného kľúča, verejného kľúča, podpisu alebo šifrového textu možno zhrnúť takto. Každý z nich sa právom môže hrdiť názvom PQC a má pomerne veľké rozmery.

| Algoritmus  | Úroveň bezpečnosti NIST | Veľkosť súkromného kľúča | Veľkosť verejného kľúča | Veľkosť podpisu/šifrového textu |
| ----------- | ----------------------- | ------------------------ | ----------------------- | ------------------------------- |
| 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                           |

Týmito algoritmami dúfame, že na internete budeme môcť bezpečne komunikovať aj v prostredí kvantových počítačov, no vzhľadom na väčšie kľúče a podpisy/šifrové texty sa zrejme nevyhneme vyššej výpočtovej záťaži.

Jazyk Go má však jednotlivé algoritmy efektívne implementované, preto dúfam, že sa budú na vhodných miestach aktívne využívať na ochranu vašej bezpečnosti!
