Skip to content

Instantly share code, notes, and snippets.

@alessiodionisi
Created April 29, 2022 13:50
Show Gist options
  • Save alessiodionisi/2cd553cc2bf2f777f2aead9970b45218 to your computer and use it in GitHub Desktop.
Save alessiodionisi/2cd553cc2bf2f777f2aead9970b45218 to your computer and use it in GitHub Desktop.
Elliptic-Curve Diffie-Hellman AES-GCM chat example
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"github.com/adnsio/ecdh/ecdh25519"
)
type Chat struct {
PublicKey ecdh25519.PublicKey
PrivateKey ecdh25519.PrivateKey
SharedSecret []byte
GCM cipher.AEAD
}
func (c *Chat) GenerateKeyPair() error {
var err error
c.PublicKey, c.PrivateKey, err = ecdh25519.GenerateKeyPair(rand.Reader)
if err != nil {
return err
}
return nil
}
func (c *Chat) GenerateSharedSecret(otherPublicKey ecdh25519.PublicKey) error {
var err error
c.SharedSecret, err = ecdh25519.GenerateSharedSecret(c.PrivateKey, otherPublicKey)
if err != nil {
return err
}
return nil
}
func (c *Chat) InitializeGCM() error {
aesCipher, err := aes.NewCipher(c.SharedSecret)
if err != nil {
return err
}
c.GCM, err = cipher.NewGCM(aesCipher)
if err != nil {
return err
}
return err
}
func (c *Chat) Seal(plaintext []byte) ([]byte, []byte, error) {
nonce := make([]byte, c.GCM.NonceSize())
if _, err := rand.Read(nonce); err != nil {
return nil, nil, err
}
return nonce, c.GCM.Seal(nil, nonce, plaintext, nil), nil
}
func (c *Chat) Open(nonce []byte, ciphertext []byte) ([]byte, error) {
return c.GCM.Open(nil, nonce, ciphertext, nil)
}
func main() {
aliceBob := &Chat{}
if err := aliceBob.GenerateKeyPair(); err != nil {
panic(err)
}
bobAlice := &Chat{}
if err := bobAlice.GenerateKeyPair(); err != nil {
panic(err)
}
if err := aliceBob.GenerateSharedSecret(bobAlice.PublicKey); err != nil {
panic(err)
}
if err := bobAlice.GenerateSharedSecret(aliceBob.PublicKey); err != nil {
panic(err)
}
if bytes.Equal(aliceBob.SharedSecret, bobAlice.SharedSecret) {
fmt.Printf("shared secrets are equal\n")
}
if err := aliceBob.InitializeGCM(); err != nil {
panic(err)
}
if err := bobAlice.InitializeGCM(); err != nil {
panic(err)
}
messageForBob1Nonnce, messageForBob1Ciphertext, err := aliceBob.Seal([]byte("hello bob!"))
if err != nil {
panic(err)
}
messageForBob1Plaintext, err := bobAlice.Open(messageForBob1Nonnce, messageForBob1Ciphertext)
if err != nil {
panic(err)
}
fmt.Printf("alice > bob: %s (encrypted: %b, nonce: %b)\n", messageForBob1Plaintext, messageForBob1Ciphertext, messageForBob1Nonnce)
messageForAlice1Nonnce, messageForAlice1Ciphertext, err := bobAlice.Seal([]byte("hello alice!"))
if err != nil {
panic(err)
}
messageForAlice1Plaintext, err := aliceBob.Open(messageForAlice1Nonnce, messageForAlice1Ciphertext)
if err != nil {
panic(err)
}
fmt.Printf("bob > alice: %s (encrypted: %b, nonce: %b)\n", messageForAlice1Plaintext, messageForAlice1Ciphertext, messageForAlice1Nonnce)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment