github.com/decred/dcrlnd@v0.7.6/internal/snacl/snacl.go (about) 1 // Copyright (c) 2014-2015 The btcsuite developers 2 // Copyright (c) 2019 The Decred developers 3 // Use of this source code is governed by an ISC 4 // license that can be found in the LICENSE file. 5 6 package snacl 7 8 import ( 9 "crypto/rand" 10 "crypto/sha256" 11 "crypto/subtle" 12 "encoding/binary" 13 "errors" 14 "io" 15 "runtime/debug" 16 17 "golang.org/x/crypto/nacl/secretbox" 18 "golang.org/x/crypto/scrypt" 19 20 "github.com/decred/dcrlnd/internal/zero" 21 ) 22 23 var ( 24 prng = rand.Reader 25 ) 26 27 // Error types and messages. 28 var ( 29 ErrInvalidPassword = errors.New("invalid password") 30 ErrMalformed = errors.New("malformed data") 31 ErrDecryptFailed = errors.New("unable to decrypt") 32 ) 33 34 // Various constants needed for encryption scheme. 35 const ( 36 // Expose secretbox's Overhead const here for convenience. 37 Overhead = secretbox.Overhead 38 KeySize = 32 39 NonceSize = 24 40 DefaultN = 16384 // 2^14 41 DefaultR = 8 42 DefaultP = 1 43 ) 44 45 // CryptoKey represents a secret key which can be used to encrypt and decrypt 46 // data. 47 type CryptoKey [KeySize]byte 48 49 // Encrypt encrypts the passed data. 50 func (ck *CryptoKey) Encrypt(in []byte) ([]byte, error) { 51 var nonce [NonceSize]byte 52 _, err := io.ReadFull(prng, nonce[:]) 53 if err != nil { 54 return nil, err 55 } 56 blob := secretbox.Seal(nil, in, &nonce, (*[KeySize]byte)(ck)) 57 return append(nonce[:], blob...), nil 58 } 59 60 // Decrypt decrypts the passed data. The must be the output of the Encrypt 61 // function. 62 func (ck *CryptoKey) Decrypt(in []byte) ([]byte, error) { 63 if len(in) < NonceSize { 64 return nil, ErrMalformed 65 } 66 67 var nonce [NonceSize]byte 68 copy(nonce[:], in[:NonceSize]) 69 blob := in[NonceSize:] 70 71 opened, ok := secretbox.Open(nil, blob, &nonce, (*[KeySize]byte)(ck)) 72 if !ok { 73 return nil, ErrDecryptFailed 74 } 75 76 return opened, nil 77 } 78 79 // Zero clears the key by manually zeroing all memory. This is for security 80 // conscience application which wish to zero the memory after they've used it 81 // rather than waiting until it's reclaimed by the garbage collector. The 82 // key is no longer usable after this call. 83 func (ck *CryptoKey) Zero() { 84 zero.Bytea32((*[KeySize]byte)(ck)) 85 } 86 87 // GenerateCryptoKey generates a new crypotgraphically random key. 88 func GenerateCryptoKey() (*CryptoKey, error) { 89 var key CryptoKey 90 _, err := io.ReadFull(prng, key[:]) 91 if err != nil { 92 return nil, err 93 } 94 95 return &key, nil 96 } 97 98 // Parameters are not secret and can be stored in plain text. 99 type Parameters struct { 100 Salt [KeySize]byte 101 Digest [sha256.Size]byte 102 N int 103 R int 104 P int 105 } 106 107 // SecretKey houses a crypto key and the parameters needed to derive it from a 108 // passphrase. It should only be used in memory. 109 type SecretKey struct { 110 Key *CryptoKey 111 Parameters Parameters 112 } 113 114 // deriveKey fills out the Key field. 115 func (sk *SecretKey) deriveKey(password *[]byte) error { 116 key, err := scrypt.Key(*password, sk.Parameters.Salt[:], 117 sk.Parameters.N, 118 sk.Parameters.R, 119 sk.Parameters.P, 120 len(sk.Key)) 121 if err != nil { 122 return err 123 } 124 copy(sk.Key[:], key) 125 zero.Bytes(key) 126 127 // I'm not a fan of forced garbage collections, but scrypt allocates a 128 // ton of memory and calling it back to back without a GC cycle in 129 // between means you end up needing twice the amount of memory. For 130 // example, if your scrypt parameters are such that you require 1GB and 131 // you call it twice in a row, without this you end up allocating 2GB 132 // since the first GB probably hasn't been released yet. 133 debug.FreeOSMemory() 134 135 return nil 136 } 137 138 // Marshal returns the Parameters field marshalled into a format suitable for 139 // storage. This result of this can be stored in clear text. 140 func (sk *SecretKey) Marshal() []byte { 141 params := &sk.Parameters 142 143 // The marshalled format for the the params is as follows: 144 // <salt><digest><N><R><P> 145 // 146 // KeySize + sha256.Size + N (8 bytes) + R (8 bytes) + P (8 bytes) 147 marshalled := make([]byte, KeySize+sha256.Size+24) 148 149 b := marshalled 150 copy(b[:KeySize], params.Salt[:]) 151 b = b[KeySize:] 152 copy(b[:sha256.Size], params.Digest[:]) 153 b = b[sha256.Size:] 154 binary.LittleEndian.PutUint64(b[:8], uint64(params.N)) 155 b = b[8:] 156 binary.LittleEndian.PutUint64(b[:8], uint64(params.R)) 157 b = b[8:] 158 binary.LittleEndian.PutUint64(b[:8], uint64(params.P)) 159 160 return marshalled 161 } 162 163 // Unmarshal unmarshalls the parameters needed to derive the secret key from a 164 // passphrase into sk. 165 func (sk *SecretKey) Unmarshal(marshalled []byte) error { 166 if sk.Key == nil { 167 sk.Key = (*CryptoKey)(&[KeySize]byte{}) 168 } 169 170 // The marshalled format for the the params is as follows: 171 // <salt><digest><N><R><P> 172 // 173 // KeySize + sha256.Size + N (8 bytes) + R (8 bytes) + P (8 bytes) 174 if len(marshalled) != KeySize+sha256.Size+24 { 175 return ErrMalformed 176 } 177 178 params := &sk.Parameters 179 copy(params.Salt[:], marshalled[:KeySize]) 180 marshalled = marshalled[KeySize:] 181 copy(params.Digest[:], marshalled[:sha256.Size]) 182 marshalled = marshalled[sha256.Size:] 183 params.N = int(binary.LittleEndian.Uint64(marshalled[:8])) 184 marshalled = marshalled[8:] 185 params.R = int(binary.LittleEndian.Uint64(marshalled[:8])) 186 marshalled = marshalled[8:] 187 params.P = int(binary.LittleEndian.Uint64(marshalled[:8])) 188 189 return nil 190 } 191 192 // Zero zeroes the underlying secret key while leaving the parameters intact. 193 // This effectively makes the key unusable until it is derived again via the 194 // DeriveKey function. 195 func (sk *SecretKey) Zero() { 196 sk.Key.Zero() 197 } 198 199 // DeriveKey derives the underlying secret key and ensures it matches the 200 // expected digest. This should only be called after previously calling the 201 // Zero function or on an initial Unmarshal. 202 func (sk *SecretKey) DeriveKey(password *[]byte) error { 203 if err := sk.deriveKey(password); err != nil { 204 return err 205 } 206 207 // verify password 208 digest := sha256.Sum256(sk.Key[:]) 209 if subtle.ConstantTimeCompare(digest[:], sk.Parameters.Digest[:]) != 1 { 210 return ErrInvalidPassword 211 } 212 213 return nil 214 } 215 216 // Encrypt encrypts in bytes and returns a JSON blob. 217 func (sk *SecretKey) Encrypt(in []byte) ([]byte, error) { 218 return sk.Key.Encrypt(in) 219 } 220 221 // Decrypt takes in a JSON blob and returns it's decrypted form. 222 func (sk *SecretKey) Decrypt(in []byte) ([]byte, error) { 223 return sk.Key.Decrypt(in) 224 } 225 226 // NewSecretKey returns a SecretKey structure based on the passed parameters. 227 func NewSecretKey(password *[]byte, n, r, p int) (*SecretKey, error) { 228 sk := SecretKey{ 229 Key: (*CryptoKey)(&[KeySize]byte{}), 230 } 231 // setup parameters 232 sk.Parameters.N = n 233 sk.Parameters.R = r 234 sk.Parameters.P = p 235 _, err := io.ReadFull(prng, sk.Parameters.Salt[:]) 236 if err != nil { 237 return nil, err 238 } 239 240 // derive key 241 err = sk.deriveKey(password) 242 if err != nil { 243 return nil, err 244 } 245 246 // store digest 247 sk.Parameters.Digest = sha256.Sum256(sk.Key[:]) 248 249 return &sk, nil 250 }