Created
April 2, 2025 09:14
-
-
Save RichardSlater/34a8b641ef12006ce69004ef8a03688d to your computer and use it in GitHub Desktop.
Post-Quantum Block Ciphers in Go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"log" | |
"crypto/mlkem" | |
"crypto/aes" | |
"crypto/cipher" | |
"encoding/base64" | |
"io" | |
"crypto/rand" | |
"fmt" | |
) | |
func main() { | |
alice := Person{name: "Alice"} | |
encapsulationKey,err := alice.GenerateKey() | |
if err != nil { | |
log.Fatal(err) | |
} | |
bob := Person{name: "Bob"} | |
ciphertext,err := bob.Encapsulate(encapsulationKey) | |
if err != nil { | |
log.Fatal(err) | |
} | |
err = alice.Decapsulate(ciphertext) | |
if err != nil { | |
log.Fatal(err) | |
} | |
encrypted,err := alice.Encrypt("Hello, bob") | |
if err != nil { | |
log.Fatal(err) | |
} | |
decrypted, err := bob.Decrypt(encrypted) | |
if err != nil { | |
log.Fatal(err) | |
} | |
fmt.Printf("Decrypted message: %s\n", decrypted) | |
} | |
func (p *Person) GenerateKey() ([]byte, error) { | |
dk, err := mlkem.GenerateKey768() | |
if err != nil { | |
return nil, err | |
} | |
p.dk = dk.Bytes() | |
return dk.EncapsulationKey().Bytes(), nil | |
} | |
func (p *Person) Encapsulate(encapsulationKey []byte) ([]byte, error) { | |
ek, err := mlkem.NewEncapsulationKey768(encapsulationKey) | |
if err != nil { | |
log.Fatal(err) | |
} | |
sharedSecret, ciphertext := ek.Encapsulate() | |
p.sharedSecret = sharedSecret | |
return ciphertext, nil | |
} | |
func(p *Person) Decapsulate(cypertext []byte) error { | |
dk, err := mlkem.NewDecapsulationKey768(p.dk) | |
if err != nil { | |
return err | |
} | |
sharedSecret,err := dk.Decapsulate(cypertext) | |
if err != nil { | |
return err | |
} | |
p.sharedSecret = sharedSecret | |
return nil | |
} | |
func (p *Person) Encrypt(plaintext string) (string, error) { | |
block, err := aes.NewCipher(p.sharedSecret) | |
if err != nil { | |
return "", err | |
} | |
gcm, err := cipher.NewGCM(block) | |
if err != nil { | |
return "", err | |
} | |
nonce := make([]byte, gcm.NonceSize()) | |
_, err = io.ReadFull(rand.Reader, nonce) | |
if err != nil { | |
return "", err | |
} | |
ciphertext := gcm.Seal(nil, nonce, []byte(plaintext), nil) | |
return base64.RawStdEncoding.EncodeToString(append(nonce,ciphertext...)), nil | |
} | |
func (p *Person) Decrypt(ciphertext string) (string, error) { | |
block, err := aes.NewCipher(p.sharedSecret) | |
if err != nil { | |
return "", err | |
} | |
gcm, err := cipher.NewGCM(block) | |
if err != nil { | |
return "", err | |
} | |
cipherTextBytes, err := base64.RawStdEncoding.DecodeString(ciphertext) | |
if err != nil { | |
return "", err | |
} | |
nonceSize := gcm.NonceSize() | |
nonce, cipherTextBytes := cipherTextBytes[:nonceSize], cipherTextBytes[nonceSize:] | |
plaintext, err := gcm.Open(nil, nonce, cipherTextBytes, nil) | |
if err != nil { | |
return "", err | |
} | |
return string(plaintext), nil | |
} | |
type Person struct { | |
name string // Name of the person. | |
dk []byte // The person's decapsulation key. This is only set if the person calls GenerateKey. | |
sharedSecret []byte // The shared secret between the person and another person. | |
} | |
// cite: https://medium.com/@ajitem/cryptographic-enhancements-in-go-1-24-post-quantum-readiness-more-5b60374f8b8f |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment