---
id: df2ea4cfe0d5ec72a92e1b3cfd4156f2
author: snowmerak
title: Erfaringer med bruk av MLDSA og MLKEM i Go-språket
description: I Go-språket undersøkes bruken av de kvantemotstandsdyktige krypteringsalgoritmene MLDSA og MLKEM, og det gis en beskrivelse av egenskapene til hver algoritme samt kodeeksempler.
language: "no"
date: 2024-12-22T08:17:58.797764292Z
path: /blog/posts/usage-of-mldsa-and-mlkem-in-the-go-language-zb0442110
category: security
---

## Oversikt

### Bakgrunn

I lang tid har den raske beregningskapasiteten til kvantedatamaskiner blitt oppfattet som en trussel mot eksisterende krypteringssystemer. Dette skyldes at de etablerte algoritmene RSA og ECC kan bli knekket av nettopp denne beregningskapasiteten. Men da begrepet kvantedatamaskin for alvor begynte å ta form for noen år siden, startet forskning og utvikling av alternativer, og NIST har siden arbeidet med standardisering av PQC (post-kvantekryptografi).

### MLDSA og MLKEM

Til slutt vedtok NIST i august 2024 MLKEM og MLDSA, som bygger på CRYSTALS-Kyber og CRYSTALS-Dilithium, som standarder. Begge algoritmene opererer på grunnlag av problemet MLWE (Module Learning with Errors). Denne typen kalles gitterbasert kryptografi.

Gitterbasert kryptografi er, som navnet antyder, et krypteringssystem basert på vanskeligheten av matematiske problemer på gitter. Jeg har ikke en dyp matematisk kunnskap om dette, men oppsummert kan det beskrives som `problemet med å løse lineære likninger med støy i et modulgitter`. Hvor vanskelig dette er, er vanskelig å forestille seg, men det sies at slike problemer er så vanskelige at de ikke kan løses selv av kvantedatamaskiner.

## MLDSA

La oss først se nærmere på MLDSA.

### Oppbygning

MLDSA er, som navnet antyder, en asymmetrisk signaturalgoritme, og den består av totalt følgende to trinn.

1. Signaturgenerering: Generer en signatur for en melding ved hjelp av den private nøkkelen
2. Signaturverifisering: Bekreft gyldigheten av den genererte signaturen ved hjelp av den offentlige nøkkelen

MLDSA har dessuten følgende tre egenskaper.

1. Strong existential unforgeability: Det er ikke mulig å generere en annen gyldig signatur ut fra én signatur og den offentlige nøkkelen.
2. Chosen message attack: Selv med signaturen for en valgt melding er det ikke mulig å generere en ny gyldig signatur ved hjelp av den offentlige nøkkelen.
3. Side-channel attack: Ved signering brukes stadig nye tilfeldige verdier og pseudotilfeldige verdier avledet fra meldingen, noe som gir høy sikkerhet.
4. Domain separation: Ved å bruke ulike seed for ulike parametere forebygges gjentatte sikkerhetsproblemer.

### Kode

La oss se et enkelt eksempel i programmeringsspråket Go.
I dette eksemplet er mldsa fra [cloudflare/circl](github.com/cloudflare/circl) brukt.

```go
package main

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

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

func main() {
    // Genererer nøkler med mldsa44-spesifikasjonen.
	pub, priv, err := mldsa44.GenerateKey(rand.Reader)
	if err != nil {
		panic(err)
	}

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

    // Genererer signaturen.
    // En ting å merke seg er at med versjonen per 22. desember 2024 oppstår en feil dersom verdien ikke er 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)

    // Verifiserer ved å kalle scheme for den offentlige nøkkelen.
	ok := pub.Scheme().Verify(pub, message, signature, nil)
	fmt.Println(ok)
}
```

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

> Signaturverdien er utelatt fordi den er for lang. Hvis du vil se hele verdien, kan du kjøre koden på [playground](https://go.dev/play/p/nqbUnKpFW3j).

Selv om den er kodet i base64, er det nok litt tungt at den blir 3228 byte.
Når man tenker på at vi kanskje snart må utveksle signaturer av denne størrelsen for å motstå kvantedatamaskiner, er det litt tungt å tenke på..

## MLKEM

### Oppbygning

MLKEM er en nøkkelinnkapslingsmekanisme (Key Encapsulation Mechanism). En KEM er en algoritme som gjør det mulig å generere en delt nøkkel mellom to parter ved hjelp av en asymmetrisk krypteringsmetode. Nøkkelutvekslingsmekanismen i MLKEM består av følgende prosess.

1. Nøkkelinnkapsling: Avsenderen bruker mottakerens offentlige nøkkel til å generere en kryptert melding (cipher text) og en delt nøkkel (shared key). Denne krypterte meldingen overføres først til mottakeren for bruk.
2. Nøkkelutpakking: Mottakeren bruker sin private nøkkel til å hente den delte nøkkelen fra den krypterte meldingen.

MLKEM har totalt tre parametere: MLKEM-512, MLKEM-768 og MLKEM-1024. Jo lavere tallet er, desto mindre blir nøkkelen og den krypterte teksten; jo høyere tallet er, desto lengre blir nøkkelen og den krypterte teksten, og sikkerhetsnivået er høyere.

### Kode

MLKEM skal legges til i go 1.24, så derfor er go 1.24rc1, som er tilgjengelig nå, brukt.

```go
package main

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

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

    // I MLKEM brukes begrepet EncapsulationKey i stedet for PublicKey.
	receiverPubKey := receiverKey.EncapsulationKey()

    // For enkelhets skyld er EncapsulationKey kopiert for å vise at nøkkelen kan hentes ut med Bytes() og gjenopprettes med NewEncapsulationKeyX og deretter brukes igjen.
    // I praksis er denne prosessen den der avsenderen lager et objekt av mottakerens EncapsulationKey, som er offentlig tilgjengelig som tekst.
	clonedReceiverPubKey, err := mlkem.NewEncapsulationKey1024(receiverPubKey.Bytes())
	if err != nil {
		panic(err)
	}

    // Encapsulate: avsenderen genererer den krypterte teksten og den delte nøkkelen.
	cipherText, SenderSharedKey := clonedReceiverPubKey.Encapsulate()

    // Kopien er laget for å vise hvordan mottakerens private nøkkel kan lagres og hentes igjen.
	clonedReceiverKey, err := mlkem.NewDecapsulationKey1024(receiverKey.Bytes())
	if err != nil {
		panic(err)
	}

    // Mottakeren bruker sin private nøkkel til å Decapsulate den krypterte teksten og generere en annen delt nøkkel.
	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=
```

Resultatet viser at det genereres en delt nøkkel av samme størrelse!

Denne koden kan også sjekkes på [playground](https://go.dev/play/p/n_cxNp435Qn?v=gotip).

## Konklusjon

Spesifikasjonene, sikkerhetsnivåene og størrelsene på de private nøklene, de offentlige nøklene, signaturene eller chifferteksten for hver algoritme kan oppsummeres slik. Alle har, i tråd med navnet PQC, betydelig store størrelser.

| Algoritme   | NIST-sikkerhetsnivå | Størrelse privat nøkkel | Størrelse offentlig nøkkel | Størrelse signatur/chiffertekst |
| ----------- | ------------------- | ----------------------- | -------------------------- | ------------------------------- |
| 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 disse algoritmene forventer vi å kunne bruke et internett som er tilstrekkelig sikkert også mot kvantedatamaskiner, men på grunn av de relativt større nøklene og signaturene/chifferteksten virker det uunngåelig at det blir flere beregninger.

Likevel er Go et språk der hver algoritme er effektivt implementert, og vi håper at den vil bli aktivt brukt på riktige steder for å beskytte din sikkerhet!
