github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/crypto/nacl/secretbox/secretbox.go (about) 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 secretbox encrypts and authenticates small messages. 7 8 Secretbox uses XSalsa20 and Poly1305 to encrypt and authenticate messages with 9 secret-key cryptography. 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 This package is interoperable with NaCl: http://nacl.cr.yp.to/secretbox.html. 17 */ 18 package secretbox // import "golang.org/x/crypto/nacl/secretbox" 19 20 import ( 21 "golang.org/x/crypto/poly1305" 22 "golang.org/x/crypto/salsa20/salsa" 23 ) 24 25 // Overhead is the number of bytes of overhead when boxing a message. 26 const Overhead = poly1305.TagSize 27 28 // setup produces a sub-key and Salsa20 counter given a nonce and key. 29 func setup(subKey *[32]byte, counter *[16]byte, nonce *[24]byte, key *[32]byte) { 30 // We use XSalsa20 for encryption so first we need to generate a 31 // key and nonce with HSalsa20. 32 var hNonce [16]byte 33 copy(hNonce[:], nonce[:]) 34 salsa.HSalsa20(subKey, &hNonce, key, &salsa.Sigma) 35 36 // The final 8 bytes of the original nonce form the new nonce. 37 copy(counter[:], nonce[16:]) 38 } 39 40 // sliceForAppend takes a slice and a requested number of bytes. It returns a 41 // slice with the contents of the given slice followed by that many bytes and a 42 // second slice that aliases into it and contains only the extra bytes. If the 43 // original slice has sufficient capacity then no allocation is performed. 44 func sliceForAppend(in []byte, n int) (head, tail []byte) { 45 if total := len(in) + n; cap(in) >= total { 46 head = in[:total] 47 } else { 48 head = make([]byte, total) 49 copy(head, in) 50 } 51 tail = head[len(in):] 52 return 53 } 54 55 // Seal appends an encrypted and authenticated copy of message to out, which 56 // must not overlap message. The key and nonce pair must be unique for each 57 // distinct message and the output will be Overhead bytes longer than message. 58 func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte { 59 var subKey [32]byte 60 var counter [16]byte 61 setup(&subKey, &counter, nonce, key) 62 63 // The Poly1305 key is generated by encrypting 32 bytes of zeros. Since 64 // Salsa20 works with 64-byte blocks, we also generate 32 bytes of 65 // keystream as a side effect. 66 var firstBlock [64]byte 67 salsa.XORKeyStream(firstBlock[:], firstBlock[:], &counter, &subKey) 68 69 var poly1305Key [32]byte 70 copy(poly1305Key[:], firstBlock[:]) 71 72 ret, out := sliceForAppend(out, len(message)+poly1305.TagSize) 73 74 // We XOR up to 32 bytes of message with the keystream generated from 75 // the first block. 76 firstMessageBlock := message 77 if len(firstMessageBlock) > 32 { 78 firstMessageBlock = firstMessageBlock[:32] 79 } 80 81 tagOut := out 82 out = out[poly1305.TagSize:] 83 for i, x := range firstMessageBlock { 84 out[i] = firstBlock[32+i] ^ x 85 } 86 message = message[len(firstMessageBlock):] 87 ciphertext := out 88 out = out[len(firstMessageBlock):] 89 90 // Now encrypt the rest. 91 counter[8] = 1 92 salsa.XORKeyStream(out, message, &counter, &subKey) 93 94 var tag [poly1305.TagSize]byte 95 poly1305.Sum(&tag, ciphertext, &poly1305Key) 96 copy(tagOut, tag[:]) 97 98 return ret 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 []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) { 105 if len(box) < Overhead { 106 return nil, false 107 } 108 109 var subKey [32]byte 110 var counter [16]byte 111 setup(&subKey, &counter, nonce, key) 112 113 // The Poly1305 key is generated by encrypting 32 bytes of zeros. Since 114 // Salsa20 works with 64-byte blocks, we also generate 32 bytes of 115 // keystream as a side effect. 116 var firstBlock [64]byte 117 salsa.XORKeyStream(firstBlock[:], firstBlock[:], &counter, &subKey) 118 119 var poly1305Key [32]byte 120 copy(poly1305Key[:], firstBlock[:]) 121 var tag [poly1305.TagSize]byte 122 copy(tag[:], box) 123 124 if !poly1305.Verify(&tag, box[poly1305.TagSize:], &poly1305Key) { 125 return nil, false 126 } 127 128 ret, out := sliceForAppend(out, len(box)-Overhead) 129 130 // We XOR up to 32 bytes of box with the keystream generated from 131 // the first block. 132 box = box[Overhead:] 133 firstMessageBlock := box 134 if len(firstMessageBlock) > 32 { 135 firstMessageBlock = firstMessageBlock[:32] 136 } 137 for i, x := range firstMessageBlock { 138 out[i] = firstBlock[32+i] ^ x 139 } 140 141 box = box[len(firstMessageBlock):] 142 out = out[len(firstMessageBlock):] 143 144 // Now decrypt the rest. 145 counter[8] = 1 146 salsa.XORKeyStream(out, box, &counter, &subKey) 147 148 return ret, true 149 }