safing-jess/tools/ecdh/x25519.go

147 lines
3.2 KiB
Go

package ecdh
import (
"crypto"
"fmt"
"github.com/aead/ecdh"
"github.com/safing/jess/tools"
"github.com/safing/structures/container"
)
func init() {
tools.Register(&tools.Tool{
Info: &tools.ToolInfo{
Name: "ECDH-X25519",
Purpose: tools.PurposeKeyExchange,
SecurityLevel: 128,
Comment: "",
Author: "Daniel J. Bernstein, 2005",
},
Factory: func() tools.ToolLogic { return &X25519Curve{} },
})
}
// X25519Curve implements the cryptographic interface for the ECDH X25519 key exchange.
type X25519Curve struct {
tools.ToolLogicBase
}
// MakeSharedKey implements the ToolLogic interface.
func (ec *X25519Curve) MakeSharedKey(local tools.SignetInt, remote tools.SignetInt) ([]byte, error) {
return ecdh.X25519().ComputeSecret(local.PrivateKey(), remote.PublicKey()), nil
}
// LoadKey implements the ToolLogic interface.
func (ec *X25519Curve) LoadKey(signet tools.SignetInt) error {
var pubKey crypto.PublicKey
var privKey crypto.PrivateKey
key, public := signet.GetStoredKey()
c := container.New(key)
// check serialization version
version, err := c.GetNextN8()
if err != nil || version != 1 {
return tools.ErrInvalidKey
}
// load public key
data, err := c.Get(32)
if err != nil {
return tools.ErrInvalidKey
}
var pubKeyData [32]byte
copy(pubKeyData[:], data)
pubKey = pubKeyData
// check public key
err = ecdh.X25519().Check(pubKey)
if err != nil {
return tools.ErrInvalidKey
}
// load private key
if !public {
data, err = c.Get(32)
if err != nil {
return tools.ErrInvalidKey
}
var privKeyData [32]byte
copy(privKeyData[:], data)
privKey = privKeyData
}
signet.SetLoadedKeys(pubKey, privKey)
return nil
}
// StoreKey implements the ToolLogic interface.
func (ec *X25519Curve) StoreKey(signet tools.SignetInt) error {
pubKey := signet.PublicKey()
privKey := signet.PrivateKey()
public := privKey == nil
// create storage with serialization version
c := container.New()
c.AppendNumber(1)
// store keys
pubKeyData, ok := pubKey.([32]byte)
if !ok {
return fmt.Errorf("public key of invalid type %T", pubKey)
}
c.Append(pubKeyData[:])
if !public {
privKeyData, ok := privKey.([32]byte)
if !ok {
return fmt.Errorf("private key of invalid type %T", privKey)
}
c.Append(privKeyData[:])
}
signet.SetStoredKey(c.CompileData(), public)
return nil
}
// GenerateKey implements the ToolLogic interface.
func (ec *X25519Curve) GenerateKey(signet tools.SignetInt) error {
// define variable types for API security
var pubKey crypto.PublicKey
var privKey crypto.PrivateKey
var err error
// generate keys
privKey, pubKey, err = ecdh.X25519().GenerateKey(ec.Helper().Random())
if err != nil {
return err
}
signet.SetLoadedKeys(pubKey, privKey)
return nil
}
// BurnKey implements the ToolLogic interface. This is currently ineffective, see known issues in the project's README.
func (ec *X25519Curve) BurnKey(signet tools.SignetInt) error {
pubKey := signet.PublicKey()
privKey := signet.PrivateKey()
// burn public key
if pubKey != nil {
data, ok := pubKey.([32]byte)
if ok {
ec.Helper().Burn(data[:])
}
}
// burn private key
if privKey != nil {
data, ok := privKey.([32]byte)
if ok {
ec.Helper().Burn(data[:])
}
}
return nil
}