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