diff --git a/Gopkg.lock b/Gopkg.lock index 25a3b8bed..49e3a8518 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -52,8 +52,8 @@ [[projects]] name = "github.com/elithrar/simple-scrypt" packages = ["."] - revision = "2325946f714c95de4a6088202c402fbdfa64163b" - version = "v1.2.0" + revision = "d150773194090feb6c897805a7bcea8d49544e2c" + version = "v1.3.0" [[projects]] name = "github.com/go-ini/ini" @@ -184,7 +184,7 @@ [[projects]] branch = "master" name = "golang.org/x/net" - packages = ["context","context/ctxhttp","idna","lex/httplex"] + packages = ["context","context/ctxhttp","http2","http2/hpack","idna","lex/httplex"] revision = "6078986fec03a1dcc236c34816c71b0e05018fda" [[projects]] diff --git a/vendor/github.com/elithrar/simple-scrypt/scrypt.go b/vendor/github.com/elithrar/simple-scrypt/scrypt.go index 4e3570ccb..2742ea02a 100644 --- a/vendor/github.com/elithrar/simple-scrypt/scrypt.go +++ b/vendor/github.com/elithrar/simple-scrypt/scrypt.go @@ -214,8 +214,7 @@ func Cost(hash []byte) (Params, error) { return params, err } -// Calibrate returns the hardest parameters (not weaker than the given params), -// allowed by the given limits. +// Calibrate returns the hardest parameters, allowed by the given limits. // The returned params will not use more memory than the given (MiB); // will not take more time than the given timeout, but more than timeout/2. // @@ -242,54 +241,69 @@ func Calibrate(timeout time.Duration, memMiBytes int, params Params) (Params, er } password := []byte("weakpassword") - // First, we calculate the minimal required time. + // r is fixed to 8 and should not be used to tune the memory usage + // if the cache lines of future processors are bigger, then r should be increased + // see: https://blog.filippo.io/the-scrypt-parameters/ + p.R = 8 + + // Scrypt runs p independent mixing functions with a memory requirement of roughly + // 128 * r * N. Depending on the implementation these can be run sequentially or parallel. + // The go implementation runs them sequentially, therefore p can be used to adjust the execution time of scrypt. + + // we start with p=1 and only increase it if we have to + p.P = 1 + + // Memory usage is at least 128 * r * N, see + // http://blog.ircmaxell.com/2014/03/why-i-dont-recommend-scrypt.html + // or https://drupal.org/comment/4675994#comment-4675994 + + // calculate N based on the desired memory usage + memBytes := memMiBytes << 20 + p.N = 1 + for 128*int64(p.R)*int64(p.N) < int64(memBytes) { + p.N <<= 1 + } + p.N >>= 1 + + // calculate the current execution time start := time.Now() if _, err := scrypt.Key(password, salt, p.N, p.R, p.P, p.DKLen); err != nil { return p, err } dur := time.Since(start) - for dur < timeout && p.N < maxInt>>1 { - p.N <<= 1 - } + // reduce N if scrypt takes to long + for dur > timeout { + p.N >>= 1 - // Memory usage is at least 128 * r * N, see - // http://blog.ircmaxell.com/2014/03/why-i-dont-recommend-scrypt.html - // or https://drupal.org/comment/4675994#comment-4675994 - - var again bool - memBytes := memMiBytes << 20 - // If we'd use more memory then the allowed, we can tune the memory usage - for 128*int64(p.R)*int64(p.N) > int64(memBytes) { - if p.R > 1 { - // by lowering r - p.R-- - } else if p.N > 16 { - again = true - p.N >>= 1 - } else { - break - } - } - if !again { - return p, p.Check() - } - - // We have to compensate the lowering of N, by increasing p. - for i := 0; i < 10 && p.P > 0; i++ { - start := time.Now() + start = time.Now() if _, err := scrypt.Key(password, salt, p.N, p.R, p.P, p.DKLen); err != nil { return p, err } - dur := time.Since(start) - if dur < timeout/2 { - p.P = int(float64(p.P)*float64(timeout/dur) + 1) - } else if dur > timeout && p.P > 1 { - p.P-- - } else { - break - } + dur = time.Since(start) } + // try to reach desired timeout by increasing p + // the further away we are from timeout the bigger the steps should be + for dur < timeout { + // the theoretical optimal p; can not be used because of inaccurate measuring + optimalP := int(int64(timeout) / (int64(dur) / int64(p.P))) + + if optimalP > p.P+1 { + // use average between optimal p and current p + p.P = (p.P + optimalP) / 2 + } else { + p.P++ + } + + start = time.Now() + if _, err := scrypt.Key(password, salt, p.N, p.R, p.P, p.DKLen); err != nil { + return p, err + } + dur = time.Since(start) + } + // lower by one to get shorter duration than timeout + p.P-- + return p, p.Check() } diff --git a/vendor/github.com/elithrar/simple-scrypt/scrypt_test.go b/vendor/github.com/elithrar/simple-scrypt/scrypt_test.go index dbb9bdb28..4eeea1377 100644 --- a/vendor/github.com/elithrar/simple-scrypt/scrypt_test.go +++ b/vendor/github.com/elithrar/simple-scrypt/scrypt_test.go @@ -114,6 +114,9 @@ func TestCalibrate(t *testing.T) { for testNum, tc := range []struct { MemMiB int }{ + {512}, + {256}, + {128}, {64}, {32}, {16}, @@ -139,9 +142,9 @@ func TestCalibrate(t *testing.T) { t.Fatalf("%d. GenerateFromPassword with %#v: %v", testNum, p, err) } if dur < timeout/2 { - t.Errorf("%d. GenerateFromPassword was too fast (wanted around %s, got %s) with %#v.", testNum, timeout, dur, p) - } else if timeout*2 < dur { - t.Errorf("%d. GenerateFromPassword took too long (wanted around %s, got %s) with %#v.", testNum, timeout, dur, p) + t.Errorf("%d. GenerateFromPassword was too fast (expected between %s and %s, got %s) with %#v.", testNum, timeout/2, timeout+timeout/2, dur, p) + } else if timeout+timeout/2 < dur { + t.Errorf("%d. GenerateFromPassword took too long (expected between %s and %s, got %s) with %#v.", testNum, timeout/2, timeout+timeout/2, dur, p) } } }