package configfile import ( "log" "math" "golang.org/x/crypto/scrypt" "../../gocryptfs_internal/cryptocore" ) const ( // ScryptDefaultLogN is the default scrypt logN configuration parameter. // logN=16 (N=2^16) uses 64MB of memory and takes 4 seconds on my Atom Z3735F // netbook. ScryptDefaultLogN = 16 // From RFC7914, section 2: // At the current time, r=8 and p=1 appears to yield good // results, but as memory latency and CPU parallelism increase, it is // likely that the optimum values for both r and p will increase. // We reject all lower values that we might get through modified config files. scryptMinR = 8 scryptMinP = 1 // logN=10 takes 6ms on a Pentium G630. This should be fast enough for all // purposes. We reject lower values. scryptMinLogN = 10 // We always generate 32-byte salts. Anything smaller than that is rejected. scryptMinSaltLen = 32 ) // ScryptKDF is an instance of the scrypt key deriviation function. type ScryptKDF struct { // Salt is the random salt that is passed to scrypt Salt []byte // N: scrypt CPU/Memory cost parameter N int // R: scrypt block size parameter R int // P: scrypt parallelization parameter P int // KeyLen is the output data length KeyLen int } // NewScryptKDF returns a new instance of ScryptKDF. func NewScryptKDF(logN int) ScryptKDF { var s ScryptKDF s.Salt = cryptocore.RandBytes(cryptocore.KeyLen) if logN <= 0 { s.N = 1 << ScryptDefaultLogN } else { s.N = 1 << uint32(logN) } s.R = 8 // Always 8 s.P = 1 // Always 1 s.KeyLen = cryptocore.KeyLen return s } // DeriveKey returns a new key from a supplied password. func (s *ScryptKDF) DeriveKey(pw []byte) []byte { if s.validateParams() { k, err := scrypt.Key(pw, s.Salt, s.N, s.R, s.P, s.KeyLen) if err != nil { log.Panicf("DeriveKey failed: %v", err) } return k } else { return nil } } // LogN - N is saved as 2^LogN, but LogN is much easier to work with. // This function gives you LogN = Log2(N). func (s *ScryptKDF) LogN() int { return int(math.Log2(float64(s.N)) + 0.5) } // validateParams checks that all parameters are at or above hardcoded limits. // If not, it exists with an error message. // This makes sure we do not get weak parameters passed through a // rougue gocryptfs.conf. func (s *ScryptKDF) validateParams() bool { minN := 1 << scryptMinLogN if s.N < minN { return false//os.Exit(exitcodes.ScryptParams) } if s.R < scryptMinR { return false//os.Exit(exitcodes.ScryptParams) } if s.P < scryptMinP { return false//os.Exit(exitcodes.ScryptParams) } if len(s.Salt) < scryptMinSaltLen { return false//os.Exit(exitcodes.ScryptParams) } if s.KeyLen < cryptocore.KeyLen { return false//os.Exit(exitcodes.ScryptParams) } return true }