---
id: df2ea4cfe0d5ec72a92e1b3cfd4156f2
author: snowmerak
title: Erfarenheter av att använda MLDSA och MLKEM i Go-språket
description: Här presenteras hur de post-quantum cryptography-algoritmerna MLDSA och MLKEM används i Go, och varje algoritms egenskaper beskrivs tillsammans med kodexempel.
language: sv
date: 2024-12-22T08:17:58.797764292Z
path: /blog/posts/usage-of-mldsa-and-mlkem-in-the-go-language-zb0442110
category: security
---

## Översikt

### Bakgrund

Sedan för ganska länge sedan har kvantdatorers snabba beräkningsförmåga betraktats som ett hot mot befintliga krypteringssystem. Detta beror på att de traditionella algoritmerna RSA och ECC kan komma att knäckas genom just denna beräkningsförmåga hos kvantdatorer. Men sedan för några år tillbaka, när begreppet kvantdatorer började ta mer konkret form, inleddes forskning och utveckling av alternativ, och NIST har sedan dess drivit standardiseringen av PQC (Post-Quantum Cryptography, kvantresistent kryptering).

### MLDSA och MLKEM

Slutligen antog NIST i augusti 2024 MLKEM och MLDSA, vilka baseras på CRYSTALS-Kyber och CRYSTALS-Dilithium, som standarder. Båda algoritmerna fungerar utifrån problemet MLWE (Module Learning with Errors). Denna typ kallas av oss för gitterbaserad kryptering.

Gitterbaserad kryptering är, som namnet antyder, ett krypteringssystem som bygger på svårigheten hos matematiska problem på gitter. Jag saknar själv djupgående matematiska kunskaper inom området, men sammanfattat i en mening sägs det vara `problemet att lösa ett linjärt ekvationssystem med brus i ett modulgitter`. Hur svårt det är går inte riktigt att greppa, men dessa problem sägs vara så svåra att de inte ens kan lösas av kvantdatorer.

## MLDSA

Låt oss först titta närmare på MLDSA.

### Uppbyggnad

MLDSA är, som namnet antyder, en asymmetrisk signaturalgoritm och genomgår totalt följande två steg.

1. Signaturgenerering: En signatur för ett meddelande skapas med hjälp av den privata nyckeln
2. Signaturverifiering: Giltigheten hos den genererade signaturen kontrolleras med hjälp av den publika nyckeln

MLDSA har dessutom följande tre egenskaper.

1. Strong existential unforgeability: Med en signatur och en publik nyckel kan ingen annan giltig signatur skapas.
2. Chosen message attack: Med en signatur för ett godtyckligt meddelande kan ingen ny giltig signatur skapas med hjälp av den publika nyckeln.
3. Side-channel attack: Vid signering används hela tiden nya slumpmässiga värden och pseudoslumpmässiga värden härledda från meddelandet, vilket ger hög säkerhet.
4. Domain separation: Olika seed används för olika parametrar, vilket förebygger upprepade säkerhetsproblem.

### Kod

Här är ett enkelt exempel i Go-språket.
I detta exempel används mldsa från [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() {
    // Genererar nycklar med mldsa44-specifikationen.
	pub, priv, err := mldsa44.GenerateKey(rand.Reader)
	if err != nil {
		panic(err)
	}

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

    // Genererar signaturen.
    // En sak att notera är att med versionen per den 22 december 2024 uppstår ett fel om inte crypto.Hash(0) används.
	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)

    // Verifierar genom att anropa schemat för den publika nyckeln.
	ok := pub.Scheme().Verify(pub, message, signature, nil)
	fmt.Println(ok)
}
```

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

> Signaturvärdet har utelämnats eftersom det är för långt. Om du vill se hela värdet kan du köra det på [playground](https://go.dev/play/p/nqbUnKpFW3j).

Även om det är base64-kodat är det kanske lite betungande att det blir 3228 byte.
När man tänker på att vi inom kort kanske behöver utbyta signaturer med denna storlek för att skydda oss mot kvantdatorer känns det lite betungande, faktiskt..

## MLKEM

### Uppbyggnad

MLKEM är en Key Encapsulation Mechanism (nyckelinkapslingsmekanism). KEM är en algoritm som med hjälp av asymmetrisk kryptering gör det möjligt för två parter att skapa en gemensam nyckel. Nyckelutbytesmekanismen i MLKEM genomgår följande process.

1. Nyckelinkapsling: Avsändaren skapar en krypterad meddelandetext (cipher text) och en delad nyckel (shared key) med hjälp av mottagarens publika nyckel. Den krypterade meddelandetexten överförs först till mottagaren för användning.
2. Nyckelupplösning: Mottagaren extraherar den delade nyckeln från den krypterade meddelandetexten med hjälp av sin privata nyckel.

MLKEM har totalt tre parametrar. Det finns MLKEM-512, MLKEM-768 och MLKEM-1024. Ju lägre siffra, desto mindre nycklar och krypterad text, och ju högre siffra, desto längre nycklar och krypterad text samt en högre säkerhetsnivå.

### Kod

MLKEM planeras att läggas till i Go 1.24, så vi använde go 1.24rc1, som är tillgänglig i nuläget.

```go
package main

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

func main() {
    // Genererar mottagarens PrivateKey.
	receiverKey, err := mlkem.GenerateKey1024()
	if err != nil {
		panic(err)
	}

    // I MLKEM används termen EncapsulationKey i stället för PublicKey.
	receiverPubKey := receiverKey.EncapsulationKey()

    // För att enkelt visa att EncapsulationKey kan extraheras med Bytes() och återskapas med NewEncapsulationKeyX och användas igen har den klonats.
    // I verkligheten är detta steg den process i vilken avsändaren skapar ett objekt av mottagarens EncapsulationKey, som tidigare publicerats som text.
	clonedReceiverPubKey, err := mlkem.NewEncapsulationKey1024(receiverPubKey.Bytes())
	if err != nil {
		panic(err)
	}

    // Med Encapsulate skapar avsändaren den krypterade texten och den delade nyckeln.
	cipherText, SenderSharedKey := clonedReceiverPubKey.Encapsulate()

    // Klonas medvetet för att visa hur mottagarens privata nyckel kan lagras och hämtas igen.
	clonedReceiverKey, err := mlkem.NewDecapsulationKey1024(receiverKey.Bytes())
	if err != nil {
		panic(err)
	}

    // Mottagaren använder sin privata nyckel för att Decapsulate den krypterade texten och skapar en annan delad nyckel.
	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=
```

Som resultat kan vi se att delade nycklar av samma storlek skapas!

Koden kan också köras på [playground](https://go.dev/play/p/n_cxNp435Qn?v=gotip).

## Slutsats

Specifikationerna, säkerhetsnivåerna samt storlekarna för privata nycklar, publika nycklar, signaturer och krypterad text för varje algoritm kan sammanfattas enligt följande tabell. Alla uppvisar, i linje med namnet PQC, betydande storlekar.

| Algoritm    | NIST säkerhetsnivå | Privat nyckel storlek | Publik nyckel storlek | Signatur/krypterad text storlek |
| ----------- | ------------------ | --------------------- | --------------------- | ------------------------------- |
| 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                           |

Med hjälp av dessa algoritmer hoppas vi kunna använda internet på ett säkert sätt även i en värld med kvantdatorer, men de relativt större nycklarna samt signaturerna och krypterad text innebär att fler beräkningar oundvikligen kommer att behövas.

Ändå är Go-språket väl lämpat, eftersom varje algoritm är effektivt implementerad, och vi hoppas att den kommer att användas aktivt på rätt ställen för att skydda er säkerhet!
