cloudflare/cloudflared

Public

mirrored from https://github.com/cloudflare/cloudflaredAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2019.11.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

cmd/cloudflared/encrypter/encrypt.go

176lines · modecode

1// Package encrypter is suitable for encrypting messages you would like to securely share between two points.
2// Useful for providing end to end encryption (E2EE). It uses Box (NaCl) for encrypting the messages.
3// tldr is it uses Elliptic Curves (Curve25519) for the keys, XSalsa20 and Poly1305 for encryption.
4// You can read more here https://godoc.org/golang.org/x/crypto/nacl/box.
5//
6// msg := []byte("super safe message.")
7// alice, err := New("alice_priv_key.pem", "alice_pub_key.pem")
8// if err != nil {
9// log.Fatal(err)
10// }
11//
12// bob, err := New("bob_priv_key.pem", "bob_pub_key.pem")
13// if err != nil {
14// log.Fatal(err)
15// }
16// encrypted, err := alice.Encrypt(msg, bob.PublicKey())
17// if err != nil {
18// log.Fatal(err)
19// }
20//
21// data, err := bob.Decrypt(encrypted, alice.PublicKey())
22// if err != nil {
23// log.Fatal(err)
24// }
25// fmt.Println(string(data))
26package encrypter
27
28import (
29 "bytes"
30 "crypto/rand"
31 "encoding/base64"
32 "encoding/pem"
33 "errors"
34 "io"
35 "os"
36
37 "golang.org/x/crypto/nacl/box"
38)
39
40// Encrypter represents a keypair value with auxiliary functions to make
41// doing encryption and decryption easier
42type Encrypter struct {
43 privateKey *[32]byte
44 publicKey *[32]byte
45}
46
47// New returns a new encrypter with initialized keypair
48func New(privateKey, publicKey string) (*Encrypter, error) {
49 e := &Encrypter{}
50 pubKey, key, err := e.fetchOrGenerateKeys(privateKey, publicKey)
51 if err != nil {
52 return nil, err
53 }
54 e.privateKey, e.publicKey = key, pubKey
55 return e, nil
56}
57
58// PublicKey returns a base64 encoded public key. Useful for transport (like in HTTP requests)
59func (e *Encrypter) PublicKey() string {
60 return base64.URLEncoding.EncodeToString(e.publicKey[:])
61}
62
63// Decrypt data that was encrypted using our publicKey. It will use our privateKey and the sender's publicKey to decrypt
64// data is an encrypted buffer of data, mostly like from the Encrypt function. Messages contain the nonce data on the front
65// of the message.
66// senderPublicKey is a base64 encoded version of the sender's public key (most likely from the PublicKey function).
67// The return value is the decrypted buffer or an error.
68func (e *Encrypter) Decrypt(data []byte, senderPublicKey string) ([]byte, error) {
69 var decryptNonce [24]byte
70 copy(decryptNonce[:], data[:24]) // we pull the nonce from the front of the actual message.
71 pubKey, err := e.decodePublicKey(senderPublicKey)
72 if err != nil {
73 return nil, err
74 }
75 decrypted, ok := box.Open(nil, data[24:], &decryptNonce, pubKey, e.privateKey)
76 if !ok {
77 return nil, errors.New("failed to decrypt message")
78 }
79 return decrypted, nil
80}
81
82// Encrypt data using our privateKey and the recipient publicKey
83// data is a buffer of data that we would like to encrypt. Messages will have the nonce added to front
84// as they have to unique for each message shared.
85// recipientPublicKey is a base64 encoded version of the sender's public key (most likely from the PublicKey function).
86// The return value is the encrypted buffer or an error.
87func (e *Encrypter) Encrypt(data []byte, recipientPublicKey string) ([]byte, error) {
88 var nonce [24]byte
89 if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
90 return nil, err
91 }
92
93 pubKey, err := e.decodePublicKey(recipientPublicKey)
94 if err != nil {
95 return nil, err
96 }
97 // This encrypts msg and adds the nonce to the front of the message, since the nonce has to be
98 // the same for encrypting and decrypting
99 return box.Seal(nonce[:], data, &nonce, pubKey, e.privateKey), nil
100}
101
102// WriteKeys keys will take the currently initialized keypair and write them to provided filenames
103func (e *Encrypter) WriteKeys(privateKey, publicKey string) error {
104 if err := e.writeKey(e.privateKey[:], "BOX PRIVATE KEY", privateKey); err != nil {
105 return err
106 }
107 return e.writeKey(e.publicKey[:], "PUBLIC KEY", publicKey)
108}
109
110// fetchOrGenerateKeys will either load or create a keypair if it doesn't exist
111func (e *Encrypter) fetchOrGenerateKeys(privateKey, publicKey string) (*[32]byte, *[32]byte, error) {
112 key, err := e.fetchKey(privateKey)
113 if os.IsNotExist(err) {
114 return box.GenerateKey(rand.Reader)
115 } else if err != nil {
116 return nil, nil, err
117 }
118
119 pub, err := e.fetchKey(publicKey)
120 if os.IsNotExist(err) {
121 return box.GenerateKey(rand.Reader)
122 } else if err != nil {
123 return nil, nil, err
124 }
125 return pub, key, nil
126}
127
128// writeKey will write a key to disk in DER format (it's a standard pem key)
129func (e *Encrypter) writeKey(key []byte, pemType, filename string) error {
130 data := pem.EncodeToMemory(&pem.Block{
131 Type: pemType,
132 Bytes: key,
133 })
134
135 f, err := os.Create(filename)
136 if err != nil {
137 return err
138 }
139
140 _, err = f.Write(data)
141 if err != nil {
142 return err
143 }
144
145 return nil
146}
147
148// fetchKey will load a a DER formatted key from disk
149func (e *Encrypter) fetchKey(filename string) (*[32]byte, error) {
150 f, err := os.Open(filename)
151 if err != nil {
152 return nil, err
153 }
154 buf := new(bytes.Buffer)
155 io.Copy(buf, f)
156
157 p, _ := pem.Decode(buf.Bytes())
158 if p == nil {
159 return nil, errors.New("Failed to decode key")
160 }
161 var newKey [32]byte
162 copy(newKey[:], p.Bytes)
163
164 return &newKey, nil
165}
166
167// decodePublicKey will base64 decode the provided key to the box representation
168func (e *Encrypter) decodePublicKey(key string) (*[32]byte, error) {
169 pub, err := base64.URLEncoding.DecodeString(key)
170 if err != nil {
171 return nil, err
172 }
173 var newKey [32]byte
174 copy(newKey[:], pub)
175 return &newKey, nil
176}
177