142 lines
3.5 KiB
Go
142 lines
3.5 KiB
Go
package nebula
|
|
|
|
import (
|
|
"crypto/ecdh"
|
|
"crypto/rand"
|
|
"fmt"
|
|
|
|
"github.com/slackhq/nebula/cert"
|
|
)
|
|
|
|
var (
|
|
encPrivKeyPrefix = []byte("x0")
|
|
encPubKeyPrefix = []byte("X0")
|
|
|
|
x25519 = ecdh.X25519()
|
|
)
|
|
|
|
// EncryptingPublicKey wraps an X25519-based ECDH public key to provide
|
|
// convenient text (un)marshaling methods.
|
|
type EncryptingPublicKey struct{ inner *ecdh.PublicKey }
|
|
|
|
// MarshalText implements the encoding.TextMarshaler interface.
|
|
func (pk EncryptingPublicKey) MarshalText() ([]byte, error) {
|
|
if pk == (EncryptingPublicKey{}) {
|
|
return []byte(""), nil
|
|
}
|
|
return encodeWithPrefix(encPubKeyPrefix, pk.Bytes()), nil
|
|
}
|
|
|
|
// Bytes returns the raw bytes of the EncryptingPublicKey, or nil if it is the
|
|
// zero value.
|
|
func (k EncryptingPublicKey) Bytes() []byte {
|
|
if k == (EncryptingPublicKey{}) {
|
|
return nil
|
|
}
|
|
return k.inner.Bytes()
|
|
}
|
|
|
|
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
|
func (pk *EncryptingPublicKey) UnmarshalText(b []byte) error {
|
|
if len(b) == 0 {
|
|
*pk = EncryptingPublicKey{}
|
|
return nil
|
|
}
|
|
|
|
b, err := decodeWithPrefix(encPubKeyPrefix, b)
|
|
if err != nil {
|
|
return fmt.Errorf("unmarshaling encrypting public key: %w", err)
|
|
}
|
|
|
|
if pk.inner, err = x25519.NewPublicKey(b); err != nil {
|
|
return fmt.Errorf("converting bytes to public key: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// UnmarshalNebulaPEM unmarshals the EncryptingPublicKey as a nebula host public
|
|
// key PEM.
|
|
func (pk *EncryptingPublicKey) UnmarshalNebulaPEM(b []byte) error {
|
|
b, _, err := cert.UnmarshalX25519PublicKey(b)
|
|
if err != nil {
|
|
return fmt.Errorf("unmarshaling nebula PEM as encrypting public key: %w", err)
|
|
}
|
|
|
|
if pk.inner, err = x25519.NewPublicKey(b); err != nil {
|
|
return fmt.Errorf("converting bytes to public key: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (pk EncryptingPublicKey) String() string {
|
|
b, err := pk.MarshalText()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
// EncryptingPrivateKey wraps an X25519-based ECDH private key to provide
|
|
// convenient text (un)marshaling methods.
|
|
type EncryptingPrivateKey struct{ inner *ecdh.PrivateKey }
|
|
|
|
// NewEncryptingPrivateKey generates and returns a fresh EncryptingPrivateKey.
|
|
func NewEncryptingPrivateKey() EncryptingPrivateKey {
|
|
k, err := x25519.GenerateKey(rand.Reader)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return EncryptingPrivateKey{k}
|
|
}
|
|
|
|
// PublicKey returns the public key which corresponds with this private key.
|
|
func (k EncryptingPrivateKey) PublicKey() EncryptingPublicKey {
|
|
return EncryptingPublicKey{k.inner.PublicKey()}
|
|
}
|
|
|
|
// MarshalText implements the encoding.TextMarshaler interface.
|
|
func (k EncryptingPrivateKey) MarshalText() ([]byte, error) {
|
|
if k == (EncryptingPrivateKey{}) {
|
|
return []byte(""), nil
|
|
}
|
|
return encodeWithPrefix(encPrivKeyPrefix, k.Bytes()), nil
|
|
}
|
|
|
|
// Bytes returns the raw bytes of the EncryptingPrivateKey, or nil if it is the
|
|
// zero value.
|
|
func (k EncryptingPrivateKey) Bytes() []byte {
|
|
if k == (EncryptingPrivateKey{}) {
|
|
return nil
|
|
}
|
|
return k.inner.Bytes()
|
|
}
|
|
|
|
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
|
func (k *EncryptingPrivateKey) UnmarshalText(b []byte) error {
|
|
if len(b) == 0 {
|
|
*k = EncryptingPrivateKey{}
|
|
return nil
|
|
}
|
|
|
|
b, err := decodeWithPrefix(encPrivKeyPrefix, b)
|
|
if err != nil {
|
|
return fmt.Errorf("unmarshaling encrypting private key: %w", err)
|
|
}
|
|
|
|
if k.inner, err = x25519.NewPrivateKey(b); err != nil {
|
|
return fmt.Errorf("converting bytes to private key: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (k EncryptingPrivateKey) String() string {
|
|
b, err := k.MarshalText()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return string(b)
|
|
}
|