forked from TrueCloudLab/restic
parent
03193e6d92
commit
92f516b1d4
3 changed files with 62 additions and 45 deletions
6
Gopkg.lock
generated
6
Gopkg.lock
generated
|
@ -52,8 +52,8 @@
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/elithrar/simple-scrypt"
|
name = "github.com/elithrar/simple-scrypt"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "2325946f714c95de4a6088202c402fbdfa64163b"
|
revision = "d150773194090feb6c897805a7bcea8d49544e2c"
|
||||||
version = "v1.2.0"
|
version = "v1.3.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/go-ini/ini"
|
name = "github.com/go-ini/ini"
|
||||||
|
@ -184,7 +184,7 @@
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "golang.org/x/net"
|
name = "golang.org/x/net"
|
||||||
packages = ["context","context/ctxhttp","idna","lex/httplex"]
|
packages = ["context","context/ctxhttp","http2","http2/hpack","idna","lex/httplex"]
|
||||||
revision = "6078986fec03a1dcc236c34816c71b0e05018fda"
|
revision = "6078986fec03a1dcc236c34816c71b0e05018fda"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
|
80
vendor/github.com/elithrar/simple-scrypt/scrypt.go
generated
vendored
80
vendor/github.com/elithrar/simple-scrypt/scrypt.go
generated
vendored
|
@ -214,8 +214,7 @@ func Cost(hash []byte) (Params, error) {
|
||||||
return params, err
|
return params, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calibrate returns the hardest parameters (not weaker than the given params),
|
// Calibrate returns the hardest parameters, allowed by the given limits.
|
||||||
// allowed by the given limits.
|
|
||||||
// The returned params will not use more memory than the given (MiB);
|
// 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.
|
// 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")
|
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
|
||||||
start := time.Now()
|
// if the cache lines of future processors are bigger, then r should be increased
|
||||||
if _, err := scrypt.Key(password, salt, p.N, p.R, p.P, p.DKLen); err != nil {
|
// see: https://blog.filippo.io/the-scrypt-parameters/
|
||||||
return p, err
|
p.R = 8
|
||||||
}
|
|
||||||
dur := time.Since(start)
|
|
||||||
|
|
||||||
for dur < timeout && p.N < maxInt>>1 {
|
// Scrypt runs p independent mixing functions with a memory requirement of roughly
|
||||||
p.N <<= 1
|
// 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
|
// Memory usage is at least 128 * r * N, see
|
||||||
// http://blog.ircmaxell.com/2014/03/why-i-dont-recommend-scrypt.html
|
// http://blog.ircmaxell.com/2014/03/why-i-dont-recommend-scrypt.html
|
||||||
// or https://drupal.org/comment/4675994#comment-4675994
|
// or https://drupal.org/comment/4675994#comment-4675994
|
||||||
|
|
||||||
var again bool
|
// calculate N based on the desired memory usage
|
||||||
memBytes := memMiBytes << 20
|
memBytes := memMiBytes << 20
|
||||||
// If we'd use more memory then the allowed, we can tune the memory usage
|
p.N = 1
|
||||||
for 128*int64(p.R)*int64(p.N) > int64(memBytes) {
|
for 128*int64(p.R)*int64(p.N) < int64(memBytes) {
|
||||||
if p.R > 1 {
|
p.N <<= 1
|
||||||
// by lowering r
|
}
|
||||||
p.R--
|
|
||||||
} else if p.N > 16 {
|
|
||||||
again = true
|
|
||||||
p.N >>= 1
|
p.N >>= 1
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !again {
|
|
||||||
return p, p.Check()
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have to compensate the lowering of N, by increasing p.
|
// calculate the current execution time
|
||||||
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 {
|
if _, err := scrypt.Key(password, salt, p.N, p.R, p.P, p.DKLen); err != nil {
|
||||||
return p, err
|
return p, err
|
||||||
}
|
}
|
||||||
dur := time.Since(start)
|
dur := time.Since(start)
|
||||||
if dur < timeout/2 {
|
|
||||||
p.P = int(float64(p.P)*float64(timeout/dur) + 1)
|
// reduce N if scrypt takes to long
|
||||||
} else if dur > timeout && p.P > 1 {
|
for dur > timeout {
|
||||||
p.P--
|
p.N >>= 1
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
} else {
|
||||||
break
|
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()
|
return p, p.Check()
|
||||||
}
|
}
|
||||||
|
|
9
vendor/github.com/elithrar/simple-scrypt/scrypt_test.go
generated
vendored
9
vendor/github.com/elithrar/simple-scrypt/scrypt_test.go
generated
vendored
|
@ -114,6 +114,9 @@ func TestCalibrate(t *testing.T) {
|
||||||
for testNum, tc := range []struct {
|
for testNum, tc := range []struct {
|
||||||
MemMiB int
|
MemMiB int
|
||||||
}{
|
}{
|
||||||
|
{512},
|
||||||
|
{256},
|
||||||
|
{128},
|
||||||
{64},
|
{64},
|
||||||
{32},
|
{32},
|
||||||
{16},
|
{16},
|
||||||
|
@ -139,9 +142,9 @@ func TestCalibrate(t *testing.T) {
|
||||||
t.Fatalf("%d. GenerateFromPassword with %#v: %v", testNum, p, err)
|
t.Fatalf("%d. GenerateFromPassword with %#v: %v", testNum, p, err)
|
||||||
}
|
}
|
||||||
if dur < timeout/2 {
|
if dur < timeout/2 {
|
||||||
t.Errorf("%d. GenerateFromPassword was too fast (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*2 < dur {
|
} else if timeout+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 took too long (expected between %s and %s, got %s) with %#v.", testNum, timeout/2, timeout+timeout/2, dur, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue