...

Source file src/edge-infra.dev/pkg/lib/crypto/wireguard.go

Documentation: edge-infra.dev/pkg/lib/crypto

     1  package crypto
     2  
     3  import (
     4  	"crypto/rand"
     5  	"encoding/base64"
     6  	"fmt"
     7  
     8  	"golang.org/x/crypto/curve25519"
     9  )
    10  
    11  // Expected key length for a WireGuard key.
    12  const wireguardKeyLen = 32
    13  
    14  type wireguardKeyPair struct {
    15  	publicKey  string
    16  	privateKey string
    17  }
    18  
    19  // Generate an asymmetric key pair using Curve25519, as per Wireguard protocol: https://wireguard.com/protocol.
    20  func GenerateWireguardKeyPair() (AsymmetricKeyPair, error) {
    21  	privateKey, err := generateWireguardPrivateKey()
    22  	if err != nil {
    23  		return nil, err
    24  	}
    25  	publicKey := privateKey.PublicKey()
    26  
    27  	return &wireguardKeyPair{
    28  		publicKey:  publicKey.String(),
    29  		privateKey: privateKey.String(),
    30  	}, nil
    31  }
    32  
    33  func (wgKeyPair *wireguardKeyPair) PublicKey() string {
    34  	return wgKeyPair.publicKey
    35  }
    36  
    37  func (wgKeyPair *wireguardKeyPair) PrivateKey() string {
    38  	return wgKeyPair.privateKey
    39  }
    40  
    41  // A wireguardKey is a public, private, or pre-shared secret key. The wireguardKey constructor
    42  // functions in this package can be used to create Keys suitable for each of
    43  // these applications.
    44  type wireguardKey [wireguardKeyLen]byte
    45  
    46  // newWireguardKey creates a wireguardKey from an existing byte slice. The byte slice must be
    47  // exactly 32 bytes in length.
    48  func newWireguardKey(bytes []byte) (wireguardKey, error) {
    49  	if len(bytes) != wireguardKeyLen {
    50  		return wireguardKey{}, fmt.Errorf("incorrect key size: %d", len(bytes))
    51  	}
    52  
    53  	var wgKey wireguardKey
    54  	copy(wgKey[:], bytes)
    55  
    56  	return wgKey, nil
    57  }
    58  
    59  // PublicKey computes a public key from the private key k.
    60  // PublicKey should only be called when k is a private key.
    61  func (wgKey wireguardKey) PublicKey() wireguardKey {
    62  	var (
    63  		publicKey  [wireguardKeyLen]byte
    64  		privateKey = [wireguardKeyLen]byte(wgKey)
    65  	)
    66  
    67  	// ScalarBaseMult uses the correct base value per https://cr.yp.to/ecdh.html,
    68  	// so no need to specify it.
    69  	curve25519.ScalarBaseMult(&publicKey, &privateKey)
    70  
    71  	return wireguardKey(publicKey)
    72  }
    73  
    74  // String returns the base64-encoded string representation of a Key.
    75  func (wgKey wireguardKey) String() string {
    76  	return base64.StdEncoding.EncodeToString(wgKey[:])
    77  }
    78  
    79  // generateWireguardPrivateKey generates a wireguardKey suitable for use as a private key from a
    80  // cryptographically safe source.
    81  func generateWireguardPrivateKey() (wireguardKey, error) {
    82  	wgKey, err := generateWireguardKey()
    83  	if err != nil {
    84  		return wireguardKey{}, err
    85  	}
    86  
    87  	// Modify random bytes using algorithm described at:
    88  	// https://cr.yp.to/ecdh.html.
    89  	wgKey[0] &= 248
    90  	wgKey[31] &= 127
    91  	wgKey[31] |= 64
    92  
    93  	return wgKey, nil
    94  }
    95  
    96  // generateWireguardKey generates a wireguardKey suitable for use as a pre-shared secret key from
    97  // a cryptographically safe source.
    98  //
    99  // The output wireguardKey should not be used as a private key; use generateWireguardPrivateKey
   100  // instead.
   101  func generateWireguardKey() (wireguardKey, error) {
   102  	bytes := make([]byte, wireguardKeyLen)
   103  	if _, err := rand.Read(bytes); err != nil {
   104  		return wireguardKey{}, fmt.Errorf("failed to read random bytes: %v", err)
   105  	}
   106  
   107  	return newWireguardKey(bytes)
   108  }
   109  

View as plain text