-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathnacl.go
164 lines (146 loc) · 5.67 KB
/
nacl.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Package nacl is a pure Go implementation of the NaCL cryptography library.
//
// Compared with the implementation in golang.org/x/crypto/nacl, this library
// offers all of the API's present in NaCL, as well as some utilities for
// generating and loading keys and nonces, and encrypting messages.
//
// NaCl's goal is to provide all of the core operations needed to build
// higher-level cryptographic tools, as well as to demonstrate how to implement
// these tools in Go.
//
// Compared with the equivalent packages in the Go standard library and x/crypto
// package, we replace some function calls with their equivalents in this
// package, and make more use of return values (versus writing to a byte array
// specified at stdin). Most functions should be compatible with their C/C++
// counterparts in the library here: https://nacl.cr.yp.to/. In many cases the
// tests are ported directly to this library.
package nacl
import (
"crypto/sha512"
"crypto/subtle"
"encoding/hex"
"fmt"
"github.com/kevinburke/nacl/randombytes"
"golang.org/x/crypto/salsa20/salsa"
)
// The software version.
const Version = "0.7"
// Size of a public or private key in bytes.
const KeySize = 32
// Size of a nonce in bytes.
const NonceSize = 24
// Key represents a private or public key for use in encryption or
// authentication. A key should be random bytes and *not* simply 32 characters
// in the visible ASCII set.
type Key *[KeySize]byte
// Nonce is an arbitrary value that should be used only once per (sender,
// receiver) pair. For example, the lexicographically smaller public key can
// use nonce 1 for its first message to the other key, nonce 3 for its second
// message, nonce 5 for its third message, etc., while the lexicographically
// larger public key uses nonce 2 for its first message to the other key, nonce
// 4 for its second message, nonce 6 for its third message, etc. Nonces are long
// enough that randomly generated nonces have negligible risk of collision.
type Nonce *[NonceSize]byte
// Load decodes a 64-byte hex string into a Key. A hex key is suitable for
// representation in a configuration file. You can generate one by running
// "openssl rand -hex 32".
func Load(hexkey string) (Key, error) {
if len(hexkey) != 64 {
return nil, fmt.Errorf("nacl: incorrect hex key length: %d, should be 64", len(hexkey))
}
keyBytes, err := hex.DecodeString(hexkey)
if err != nil {
return nil, err
}
if len(keyBytes) != KeySize {
return nil, fmt.Errorf("nacl: incorrect key length: %d", len(keyBytes))
}
key := new([KeySize]byte)
copy(key[:], keyBytes)
return key, nil
}
// Load decodes a 128-byte hex string into a Key. A hex key is suitable for
// representation in a configuration file. You can generate one by running
// nacl/sign.GenerateKey(nil).
func Load64(hexkey string) (*[64]byte, error) {
if len(hexkey) != 128 {
return nil, fmt.Errorf("nacl: incorrect hex key length: %d, should be 64", len(hexkey))
}
keyBytes, err := hex.DecodeString(hexkey)
if err != nil {
return nil, err
}
if len(keyBytes) != 64 {
return nil, fmt.Errorf("nacl: incorrect key length: %d", len(keyBytes))
}
key := new([64]byte)
copy(key[:], keyBytes)
return key, nil
}
// NewKey returns a new Key with cryptographically random data. NewKey panics if
// we could not read the correct amount of random data into key.
func NewKey() Key {
key := new([KeySize]byte)
randombytes.MustRead(key[:])
return key
}
// NewNonce returns a new Nonce with cryptographically random data. It panics if
// we could not read the correct amount of random data into nonce.
func NewNonce() Nonce {
nonce := new([NonceSize]byte)
randombytes.MustRead(nonce[:])
return nonce
}
// Verify returns true if and only if a and b have equal contents. The time
// taken is a function of the length of the slices and is independent of the
// contents. If an attacker controls the length of a, they may be able to
// determine the length of b (and vice versa).
func Verify(a, b []byte) bool {
return subtle.ConstantTimeCompare(a, b) == 1
}
// Verify16 returns true if and only if a and b have equal contents, without
// leaking timing information.
func Verify16(a, b *[16]byte) bool {
if a == nil || b == nil {
panic("nacl: nil input")
}
return subtle.ConstantTimeCompare(a[:], b[:]) == 1
}
// Verify32 returns true if and only if a and b have equal contents, without
// leaking timing information.
func Verify32(a, b *[KeySize]byte) bool {
if a == nil || b == nil {
panic("nacl: nil input")
}
return subtle.ConstantTimeCompare(a[:], b[:]) == 1
}
// HashSize is the size, in bytes, of the result of calling Hash.
const HashSize = sha512.Size
// Hash hashes a message m.
//
// The crypto_hash function is designed to be usable as a strong component of
// DSA, RSA-PSS, key derivation, hash-based message-authentication codes,
// hash-based ciphers, and various other common applications. "Strong" means
// that the security of these applications, when instantiated with crypto_hash,
// is the same as the security of the applications against generic attacks.
// In particular, the crypto_hash function is designed to make finding
// collisions difficult.
//
// Hash is currently an implementation of SHA-512.
func Hash(m []byte) *[HashSize]byte {
out := sha512.Sum512(m)
return &out
}
// Setup produces a sub-key and Salsa20 counter given a nonce and key.
func Setup(nonce Nonce, key Key) (Key, *[16]byte) {
// We use XSalsa20 for encryption so first we need to generate a
// key and nonce with HSalsa20.
var hNonce [16]byte
copy(hNonce[:], nonce[:])
var subKey [32]byte
salsa.HSalsa20(&subKey, &hNonce, key, &salsa.Sigma)
// The final 8 bytes of the original nonce form the new nonce.
var counter [16]byte
copy(counter[:], nonce[16:])
return &subKey, &counter
}