1// Copyright 2012 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5/*
6Package box authenticates and encrypts small messages using public-key cryptography.
7
8Box uses Curve25519, XSalsa20 and Poly1305 to encrypt and authenticate
9messages. The length of messages is not hidden.
10
11It is the caller's responsibility to ensure the uniqueness of nonces—for
12example, by using nonce 1 for the first message, nonce 2 for the second
13message, etc. Nonces are long enough that randomly generated nonces have
14negligible risk of collision.
15
16Messages should be small because:
17
181. The whole message needs to be held in memory to be processed.
19
202. Using large messages pressures implementations on small machines to decrypt
21and process plaintext before authenticating it. This is very dangerous, and
22this API does not allow it, but a protocol that uses excessive message sizes
23might present some implementations with no other choice.
24
253. Fixed overheads will be sufficiently amortised by messages as small as 8KB.
26
274. Performance may be improved by working with messages that fit into data caches.
28
29Thus large amounts of data should be chunked so that each message is small.
30(Each message still needs a unique nonce.) If in doubt, 16KB is a reasonable
31chunk size.
32
33This package is interoperable with NaCl: https://nacl.cr.yp.to/box.html.
34Anonymous sealing/opening is an extension of NaCl defined by and interoperable
35with libsodium:
36https://libsodium.gitbook.io/doc/public-key_cryptography/sealed_boxes.
37*/
38package box // import "golang.org/x/crypto/nacl/box"
39
40import (
41	cryptorand "crypto/rand"
42	"io"
43
44	"golang.org/x/crypto/blake2b"
45	"golang.org/x/crypto/curve25519"
46	"golang.org/x/crypto/nacl/secretbox"
47	"golang.org/x/crypto/salsa20/salsa"
48)
49
50const (
51	// Overhead is the number of bytes of overhead when boxing a message.
52	Overhead = secretbox.Overhead
53
54	// AnonymousOverhead is the number of bytes of overhead when using anonymous
55	// sealed boxes.
56	AnonymousOverhead = Overhead + 32
57)
58
59// GenerateKey generates a new public/private key pair suitable for use with
60// Seal and Open.
61func GenerateKey(rand io.Reader) (publicKey, privateKey *[32]byte, err error) {
62	publicKey = new([32]byte)
63	privateKey = new([32]byte)
64	_, err = io.ReadFull(rand, privateKey[:])
65	if err != nil {
66		publicKey = nil
67		privateKey = nil
68		return
69	}
70
71	curve25519.ScalarBaseMult(publicKey, privateKey)
72	return
73}
74
75var zeros [16]byte
76
77// Precompute calculates the shared key between peersPublicKey and privateKey
78// and writes it to sharedKey. The shared key can be used with
79// OpenAfterPrecomputation and SealAfterPrecomputation to speed up processing
80// when using the same pair of keys repeatedly.
81func Precompute(sharedKey, peersPublicKey, privateKey *[32]byte) {
82	curve25519.ScalarMult(sharedKey, privateKey, peersPublicKey)
83	salsa.HSalsa20(sharedKey, &zeros, sharedKey, &salsa.Sigma)
84}
85
86// Seal appends an encrypted and authenticated copy of message to out, which
87// will be Overhead bytes longer than the original and must not overlap it. The
88// nonce must be unique for each distinct message for a given pair of keys.
89func Seal(out, message []byte, nonce *[24]byte, peersPublicKey, privateKey *[32]byte) []byte {
90	var sharedKey [32]byte
91	Precompute(&sharedKey, peersPublicKey, privateKey)
92	return secretbox.Seal(out, message, nonce, &sharedKey)
93}
94
95// SealAfterPrecomputation performs the same actions as Seal, but takes a
96// shared key as generated by Precompute.
97func SealAfterPrecomputation(out, message []byte, nonce *[24]byte, sharedKey *[32]byte) []byte {
98	return secretbox.Seal(out, message, nonce, sharedKey)
99}
100
101// Open authenticates and decrypts a box produced by Seal and appends the
102// message to out, which must not overlap box. The output will be Overhead
103// bytes smaller than box.
104func Open(out, box []byte, nonce *[24]byte, peersPublicKey, privateKey *[32]byte) ([]byte, bool) {
105	var sharedKey [32]byte
106	Precompute(&sharedKey, peersPublicKey, privateKey)
107	return secretbox.Open(out, box, nonce, &sharedKey)
108}
109
110// OpenAfterPrecomputation performs the same actions as Open, but takes a
111// shared key as generated by Precompute.
112func OpenAfterPrecomputation(out, box []byte, nonce *[24]byte, sharedKey *[32]byte) ([]byte, bool) {
113	return secretbox.Open(out, box, nonce, sharedKey)
114}
115
116// SealAnonymous appends an encrypted and authenticated copy of message to out,
117// which will be AnonymousOverhead bytes longer than the original and must not
118// overlap it. This differs from Seal in that the sender is not required to
119// provide a private key.
120func SealAnonymous(out, message []byte, recipient *[32]byte, rand io.Reader) ([]byte, error) {
121	if rand == nil {
122		rand = cryptorand.Reader
123	}
124	ephemeralPub, ephemeralPriv, err := GenerateKey(rand)
125	if err != nil {
126		return nil, err
127	}
128
129	var nonce [24]byte
130	if err := sealNonce(ephemeralPub, recipient, &nonce); err != nil {
131		return nil, err
132	}
133
134	if total := len(out) + AnonymousOverhead + len(message); cap(out) < total {
135		original := out
136		out = make([]byte, 0, total)
137		out = append(out, original...)
138	}
139	out = append(out, ephemeralPub[:]...)
140
141	return Seal(out, message, &nonce, recipient, ephemeralPriv), nil
142}
143
144// OpenAnonymous authenticates and decrypts a box produced by SealAnonymous and
145// appends the message to out, which must not overlap box. The output will be
146// AnonymousOverhead bytes smaller than box.
147func OpenAnonymous(out, box []byte, publicKey, privateKey *[32]byte) (message []byte, ok bool) {
148	if len(box) < AnonymousOverhead {
149		return nil, false
150	}
151
152	var ephemeralPub [32]byte
153	copy(ephemeralPub[:], box[:32])
154
155	var nonce [24]byte
156	if err := sealNonce(&ephemeralPub, publicKey, &nonce); err != nil {
157		return nil, false
158	}
159
160	return Open(out, box[32:], &nonce, &ephemeralPub, privateKey)
161}
162
163// sealNonce generates a 24 byte nonce that is a blake2b digest of the
164// ephemeral public key and the receiver's public key.
165func sealNonce(ephemeralPub, peersPublicKey *[32]byte, nonce *[24]byte) error {
166	h, err := blake2b.New(24, nil)
167	if err != nil {
168		return err
169	}
170
171	if _, err = h.Write(ephemeralPub[:]); err != nil {
172		return err
173	}
174
175	if _, err = h.Write(peersPublicKey[:]); err != nil {
176		return err
177	}
178
179	h.Sum(nonce[:0])
180
181	return nil
182}
183