2017-07-23 12:24:45 +00:00
|
|
|
// Copyright 2012 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
/*
|
2017-09-13 12:09:48 +00:00
|
|
|
Package box authenticates and encrypts small messages using public-key cryptography.
|
2017-07-23 12:24:45 +00:00
|
|
|
|
|
|
|
Box uses Curve25519, XSalsa20 and Poly1305 to encrypt and authenticate
|
|
|
|
messages. The length of messages is not hidden.
|
|
|
|
|
|
|
|
It is the caller's responsibility to ensure the uniqueness of nonces—for
|
|
|
|
example, by using nonce 1 for the first message, nonce 2 for the second
|
|
|
|
message, etc. Nonces are long enough that randomly generated nonces have
|
|
|
|
negligible risk of collision.
|
|
|
|
|
2017-09-13 12:09:48 +00:00
|
|
|
Messages should be small because:
|
|
|
|
|
|
|
|
1. The whole message needs to be held in memory to be processed.
|
|
|
|
|
|
|
|
2. Using large messages pressures implementations on small machines to decrypt
|
|
|
|
and process plaintext before authenticating it. This is very dangerous, and
|
|
|
|
this API does not allow it, but a protocol that uses excessive message sizes
|
|
|
|
might present some implementations with no other choice.
|
|
|
|
|
|
|
|
3. Fixed overheads will be sufficiently amortised by messages as small as 8KB.
|
|
|
|
|
|
|
|
4. Performance may be improved by working with messages that fit into data caches.
|
|
|
|
|
|
|
|
Thus large amounts of data should be chunked so that each message is small.
|
|
|
|
(Each message still needs a unique nonce.) If in doubt, 16KB is a reasonable
|
|
|
|
chunk size.
|
|
|
|
|
2017-07-23 12:24:45 +00:00
|
|
|
This package is interoperable with NaCl: https://nacl.cr.yp.to/box.html.
|
|
|
|
*/
|
|
|
|
package box // import "golang.org/x/crypto/nacl/box"
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io"
|
|
|
|
|
|
|
|
"golang.org/x/crypto/curve25519"
|
|
|
|
"golang.org/x/crypto/nacl/secretbox"
|
|
|
|
"golang.org/x/crypto/salsa20/salsa"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Overhead is the number of bytes of overhead when boxing a message.
|
|
|
|
const Overhead = secretbox.Overhead
|
|
|
|
|
|
|
|
// GenerateKey generates a new public/private key pair suitable for use with
|
|
|
|
// Seal and Open.
|
|
|
|
func GenerateKey(rand io.Reader) (publicKey, privateKey *[32]byte, err error) {
|
|
|
|
publicKey = new([32]byte)
|
|
|
|
privateKey = new([32]byte)
|
|
|
|
_, err = io.ReadFull(rand, privateKey[:])
|
|
|
|
if err != nil {
|
|
|
|
publicKey = nil
|
|
|
|
privateKey = nil
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
curve25519.ScalarBaseMult(publicKey, privateKey)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var zeros [16]byte
|
|
|
|
|
|
|
|
// Precompute calculates the shared key between peersPublicKey and privateKey
|
|
|
|
// and writes it to sharedKey. The shared key can be used with
|
|
|
|
// OpenAfterPrecomputation and SealAfterPrecomputation to speed up processing
|
|
|
|
// when using the same pair of keys repeatedly.
|
|
|
|
func Precompute(sharedKey, peersPublicKey, privateKey *[32]byte) {
|
|
|
|
curve25519.ScalarMult(sharedKey, privateKey, peersPublicKey)
|
|
|
|
salsa.HSalsa20(sharedKey, &zeros, sharedKey, &salsa.Sigma)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Seal appends an encrypted and authenticated copy of message to out, which
|
2017-09-13 12:09:48 +00:00
|
|
|
// will be Overhead bytes longer than the original and must not overlap it. The
|
2017-07-23 12:24:45 +00:00
|
|
|
// nonce must be unique for each distinct message for a given pair of keys.
|
|
|
|
func Seal(out, message []byte, nonce *[24]byte, peersPublicKey, privateKey *[32]byte) []byte {
|
|
|
|
var sharedKey [32]byte
|
|
|
|
Precompute(&sharedKey, peersPublicKey, privateKey)
|
|
|
|
return secretbox.Seal(out, message, nonce, &sharedKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SealAfterPrecomputation performs the same actions as Seal, but takes a
|
|
|
|
// shared key as generated by Precompute.
|
|
|
|
func SealAfterPrecomputation(out, message []byte, nonce *[24]byte, sharedKey *[32]byte) []byte {
|
|
|
|
return secretbox.Seal(out, message, nonce, sharedKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open authenticates and decrypts a box produced by Seal and appends the
|
|
|
|
// message to out, which must not overlap box. The output will be Overhead
|
|
|
|
// bytes smaller than box.
|
|
|
|
func Open(out, box []byte, nonce *[24]byte, peersPublicKey, privateKey *[32]byte) ([]byte, bool) {
|
|
|
|
var sharedKey [32]byte
|
|
|
|
Precompute(&sharedKey, peersPublicKey, privateKey)
|
|
|
|
return secretbox.Open(out, box, nonce, &sharedKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
// OpenAfterPrecomputation performs the same actions as Open, but takes a
|
|
|
|
// shared key as generated by Precompute.
|
|
|
|
func OpenAfterPrecomputation(out, box []byte, nonce *[24]byte, sharedKey *[32]byte) ([]byte, bool) {
|
|
|
|
return secretbox.Open(out, box, nonce, sharedKey)
|
|
|
|
}
|