OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / golang.org / x / crypto / nacl / secretbox / secretbox.go
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: https://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 }