---
id: df2ea4cfe0d5ec72a92e1b3cfd4156f2
author: snowmerak
title: Ervaringen met MLDSA en MLKEM in de Go-taal
description: Leer hoe u de post-quantum cryptografische algoritmen MLDSA en MLKEM in Go kunt gebruiken, en bekijk de kenmerken van elk algoritme en voorbeeldcode.
language: nl
date: 2024-12-22T08:17:58.797764292Z
path: /blog/posts/usage-of-mldsa-and-mlkem-in-the-go-language-zb0442110
category: security
---

## Overzicht

### Achtergrond

Al geruime tijd wordt het snelle rekenvermogen van kwantumcomputers beschouwd als een bedreiging voor bestaande cryptografische systemen. Traditionele versleutelingsmethoden zoals RSA en ECC lopen het risico te worden gekraakt door dit rekenvermogen. Sinds enkele jaren het concept van kwantumcomputers meer concreet vorm begint te krijgen, zijn er echter alternatieven onderzocht en ontwikkeld, en heeft NIST de standaardisatie van PQC (Post-Quantum Cryptography, kwantumbestendige versleuteling) doorgevoerd.

### MLDSA en MLKEM

Uiteindelijk heeft NIST in augustus 2024 MLKEM en MLDSA, gebaseerd op CRYSTALS-Kyber en CRYSTALS-Dilithium, als standaard aangenomen. Beide algoritmen werken op basis van het probleem Module Learning with Errors (MLWE). Deze vorm noemen wij gittergebaseerde versleuteling.

Gittergebaseerde versleuteling is, zoals de naam al aangeeft, een versleutelingssysteem dat berust op de moeilijkheid van wiskundige problemen op een rooster. Hoewel ik zelf geen diepgaande wiskundige kennis hierover heb, wordt het in één zin samengevat als `het oplossen van een lineaire vergelijking met ruis in een modulair rooster`. Hoe moeilijk dit precies is, is moeilijk in te schatten, maar men zegt dat dit soort problemen zelfs voor kwantumcomputers te moeilijk zijn om op te lossen.

## MLDSA

Laten we eerst kijken naar MLDSA.

### Opbouw

Zoals de naam al laat zien, is MLDSA een asymmetrisch handtekeningalgoritme dat in totaal de volgende twee stappen doorloopt.

1. Handtekening genereren: een handtekening voor een bericht genereren met behulp van de privésleutel
2. Handtekening verifiëren: de geldigheid van de gegenereerde handtekening controleren met behulp van de publieke sleutel

Bovendien heeft MLDSA de volgende drie kenmerken.

1. Strong existential unforgeability: met één handtekening en de publieke sleutel kan geen andere geldige handtekening worden gegenereerd.
2. Chosen message attack: ook met handtekeningen voor willekeurige berichten kan met de publieke sleutel geen nieuwe geldige handtekening worden gegenereerd.
3. Side-channel attack: bij het ondertekenen worden steeds nieuwe willekeurige waarden en pseudowillekeurige waarden afgeleid van het bericht gebruikt, wat de beveiliging verhoogt.
4. Domain separation: voor verschillende parameters worden verschillende seeds gebruikt, zodat herhaalde beveiligingsproblemen worden voorkomen.

### Code

Hieronder volgt een eenvoudig voorbeeld in de programmeertaal Go.
In dit voorbeeld is de mldsa van [cloudflare/circl](github.com/cloudflare/circl) gebruikt.

```go
package main

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

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

func main() {
    // Genereer een sleutel met de mldsa44-specificatie.
	pub, priv, err := mldsa44.GenerateKey(rand.Reader)
	if err != nil {
		panic(err)
	}

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

    // Genereer een handtekening.
    // Let op: volgens de versie van 22 december 2024 treedt een fout op als crypto.Hash(0) niet wordt gebruikt.
	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)

    // Verifieer via het Scheme van de publieke sleutel.
	ok := pub.Scheme().Verify(pub, message, signature, nil)
	fmt.Println(ok)
}
```

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

> De handtekeningwaarde is weggelaten omdat deze te lang is. Wilt u de volledige tekst zien, voer dan de code uit op de [playground](https://go.dev/play/p/nqbUnKpFW3j).

Ook al is de handtekening met base64 gecodeerd, het feit dat het 3228 bytes zijn, zal wel enigszins belastend zijn.
Wanneer ik bedenk dat we in de nabije toekomst mogelijk handtekeningen van deze omvang moeten uitwisselen om ons tegen kwantumcomputers te beschermen, vind ik dit toch wel een beetje zwaar..

## MLKEM

### Opbouw

MLKEM is een Key Encapsulation Mechanism (KEM). Een KEM is een algoritme dat met behulp van een asymmetrische versleutelingsmethode een gedeelde sleutel tussen twee partijen kan genereren. Het sleuteluitwisselingsmechanisme van MLKEM verloopt via de volgende stappen.

1. Sleutelinkapseling: de afzender genereert met de publieke sleutel van de ontvanger een versleuteld bericht (ciphertext) en een gedeelde sleutel (shared key). Dit versleutelde bericht wordt eerst aan de ontvanger overgedragen zodat deze het kan gebruiken.
2. Sleutelontkapseling: de ontvanger haalt met zijn of haar privésleutel de gedeelde sleutel uit het versleutelde bericht.

MLKEM kent in totaal drie parameters: MLKEM-512, MLKEM-768 en MLKEM-1024. Hoe kleiner het getal, hoe kleiner de sleutels en het versleutelde bericht; hoe groter het getal, hoe langer de sleutels en het versleutelde bericht, en hoe hoger het beveiligingsniveau.

### Code

Aangezien MLKEM naar verwachting in Go 1.24 zal worden toegevoegd, is op dit moment go 1.24rc1 gebruikt, die al beschikbaar is.

```go
package main

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

func main() {
    // Genereer de PrivateKey van de ontvanger.
	receiverKey, err := mlkem.GenerateKey1024()
	if err != nil {
		panic(err)
	}

    // In MLKEM wordt de term EncapsulationKey gebruikt in plaats van PublicKey.
	receiverPubKey := receiverKey.EncapsulationKey()

    // Om eenvoudig te laten zien dat de EncapsulationKey via Bytes() kan worden geëxtraheerd en via NewEncapsulationKey1024 opnieuw kan worden gebruikt, is deze gekloond.
    // In de praktijk is dit proces, waarin de EncapsulationKey van de ontvanger die als tekst openbaar is gemaakt door de afzender als object wordt aangemaakt, te zien als de werkelijke situatie.
	clonedReceiverPubKey, err := mlkem.NewEncapsulationKey1024(receiverPubKey.Bytes())
	if err != nil {
		panic(err)
	}

    // De afzender genereert met Encapsulate de ciphertext en de gedeelde sleutel.
	cipherText, SenderSharedKey := clonedReceiverPubKey.Encapsulate()

    // Om te laten zien hoe de privésleutel van de ontvanger wordt opgeslagen en teruggehaald, is deze bewust gekloond.
	clonedReceiverKey, err := mlkem.NewDecapsulationKey1024(receiverKey.Bytes())
	if err != nil {
		panic(err)
	}

    // De ontvanger gebruikt zijn privésleutel om de ciphertext te Decapsulate en genereert zo een andere gedeelde sleutel.
	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=
```

Het resultaat laat zien dat er gedeelde sleutels van dezelfde grootte worden gegenereerd!

Deze code kan ook worden bekeken op de [playground](https://go.dev/play/p/n_cxNp435Qn?v=gotip).

## Conclusie

De specificaties, beveiligingsniveaus en de groottes van privésleutels, publieke sleutels, handtekeningen of ciphertexten van elk algoritme kunnen als volgt worden samengevat. Elk van deze algoritmen toont, passend bij de naam PQC, een flinke omvang.

| Algoritme   | NIST-beveiligingsniveau | Grootte privésleutel | Grootte publieke sleutel | Grootte handtekening/ciphertext |
| ----------- | ----------------------- | -------------------- | ------------------------ | ------------------------------- |
| 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                           |

Met deze algoritmen hopen wij dat we ook in een kwantumcomputertijdperk een voldoende veilig internet kunnen gebruiken, maar door de relatief grotere sleutels en handtekening- en ciphertextgroottes lijkt een toename van het aantal berekeningen onvermijdelijk.

Desalniettemin is Go goed in staat deze algoritmen effectief te implementeren, en wij hopen dat het op de juiste plaatsen actief wordt ingezet om uw veiligheid te waarborgen!
