...

Source file src/golang.org/x/crypto/nacl/box/box.go

Documentation: golang.org/x/crypto/nacl/box

     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  /*
     6  Package box authenticates and encrypts small messages using public-key cryptography.
     7  
     8  Box uses Curve25519, XSalsa20 and Poly1305 to encrypt and authenticate
     9  messages. The length of messages is not hidden.
    10  
    11  It is the caller's responsibility to ensure the uniqueness of nonces—for
    12  example, by using nonce 1 for the first message, nonce 2 for the second
    13  message, etc. Nonces are long enough that randomly generated nonces have
    14  negligible risk of collision.
    15  
    16  Messages should be small because:
    17  
    18  1. The whole message needs to be held in memory to be processed.
    19  
    20  2. Using large messages pressures implementations on small machines to decrypt
    21  and process plaintext before authenticating it. This is very dangerous, and
    22  this API does not allow it, but a protocol that uses excessive message sizes
    23  might present some implementations with no other choice.
    24  
    25  3. Fixed overheads will be sufficiently amortised by messages as small as 8KB.
    26  
    27  4. Performance may be improved by working with messages that fit into data caches.
    28  
    29  Thus 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
    31  chunk size.
    32  
    33  This package is interoperable with NaCl: https://nacl.cr.yp.to/box.html.
    34  Anonymous sealing/opening is an extension of NaCl defined by and interoperable
    35  with libsodium:
    36  https://libsodium.gitbook.io/doc/public-key_cryptography/sealed_boxes.
    37  */
    38  package box // import "golang.org/x/crypto/nacl/box"
    39  
    40  import (
    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  
    50  const (
    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.
    61  func 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  
    75  var 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.
    81  func 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.
    89  func 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.
    97  func 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.
   104  func 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.
   112  func 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.
   120  func 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.
   147  func 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.
   165  func 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  

View as plain text