mirror of
https://github.com/restic/restic.git
synced 2024-08-28 20:56:03 +02:00
111 lines
4 KiB
Markdown
111 lines
4 KiB
Markdown
![]() |
# simple-scrypt
|
||
|
[![GoDoc](https://godoc.org/github.com/elithrar/simple-scrypt?status.svg)](https://godoc.org/github.com/elithrar/simple-scrypt) [![Build Status](https://travis-ci.org/elithrar/simple-scrypt.svg?branch=master)](https://travis-ci.org/elithrar/simple-scrypt)
|
||
|
|
||
|
simple-scrypt provides a convenience wrapper around Go's existing
|
||
|
[scrypt](http://golang.org/x/crypto/scrypt) package that makes it easier to
|
||
|
securely derive strong keys ("hash user passwords"). This library allows you to:
|
||
|
|
||
|
* Generate a scrypt derived key with a crytographically secure salt and sane
|
||
|
default parameters for N, r and p.
|
||
|
* Upgrade the parameters used to generate keys as hardware improves by storing
|
||
|
them with the derived key (the scrypt spec. doesn't allow for this by
|
||
|
default).
|
||
|
* Provide your own parameters (if you wish to).
|
||
|
|
||
|
The API closely mirrors Go's [bcrypt](https://golang.org/x/crypto/bcrypt)
|
||
|
library in an effort to make it easy to migrate—and because it's an easy to grok
|
||
|
API.
|
||
|
|
||
|
## Example
|
||
|
|
||
|
simple-scrypt doesn't try to re-invent the wheel or do anything "special". It
|
||
|
wraps the `scrypt.Key` function as thinly as possible, generates a
|
||
|
crytographically secure salt for you using Go's `crypto/rand` package, and
|
||
|
returns the derived key with the parameters prepended:
|
||
|
|
||
|
```go
|
||
|
package main
|
||
|
|
||
|
import(
|
||
|
"fmt"
|
||
|
"log"
|
||
|
|
||
|
"github.com/elithrar/simple-scrypt"
|
||
|
)
|
||
|
|
||
|
func main() {
|
||
|
// e.g. r.PostFormValue("password")
|
||
|
passwordFromForm := "prew8fid9hick6c"
|
||
|
|
||
|
// Generates a derived key of the form "N$r$p$salt$dk" where N, r and p are defined as per
|
||
|
// Colin Percival's scrypt paper: http://www.tarsnap.com/scrypt/scrypt.pdf
|
||
|
// scrypt.Defaults (N=16384, r=8, p=1) makes it easy to provide these parameters, and
|
||
|
// (should you wish) provide your own values via the scrypt.Params type.
|
||
|
hash, err := scrypt.GenerateFromPassword([]byte(passwordFromForm), scrypt.DefaultParams)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
|
||
|
// Print the derived key with its parameters prepended.
|
||
|
fmt.Printf("%s\n", hash)
|
||
|
|
||
|
// Uses the parameters from the existing derived key. Return an error if they don't match.
|
||
|
err := scrypt.CompareHashAndPassword(hash, []byte(passwordFromForm))
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
## Upgrading Parameters
|
||
|
|
||
|
Upgrading derived keys from a set of parameters to a "stronger" set of parameters
|
||
|
as hardware improves, or as you scale (and move your auth process to separate
|
||
|
hardware), can be pretty useful. Here's how to do it with simple-scrypt:
|
||
|
|
||
|
```go
|
||
|
func main() {
|
||
|
// SCENE: We've successfully authenticated a user, compared their submitted
|
||
|
// (cleartext) password against the derived key stored in our database, and
|
||
|
// now want to upgrade the parameters (more rounds, more parallelism) to
|
||
|
// reflect some shiny new hardware we just purchased. As the user is logging
|
||
|
// in, we can retrieve the parameters used to generate their key, and if
|
||
|
// they don't match our "new" parameters, we can re-generate the key while
|
||
|
// we still have the cleartext password in memory
|
||
|
// (e.g. before the HTTP request ends).
|
||
|
current, err := scrypt.Cost(hash)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
|
||
|
// Now to check them against our own Params struct (e.g. using reflect.DeepEquals)
|
||
|
// and determine whether we want to generate a new key with our "upgraded" parameters.
|
||
|
slower := scrypt.Params{
|
||
|
N: 32768,
|
||
|
R: 8,
|
||
|
P: 2,
|
||
|
SaltLen: 16,
|
||
|
DKLen: 32,
|
||
|
}
|
||
|
|
||
|
if !reflect.DeepEqual(current, slower) {
|
||
|
// Re-generate the key with the slower parameters
|
||
|
// here using scrypt.GenerateFromPassword
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
## TO-DO:
|
||
|
|
||
|
The following features are planned. PRs are welcome.
|
||
|
|
||
|
- [x] Tag a release build.
|
||
|
- [x] Automatically calculate "optimal" values for N, r, p similar [to the Ruby scrypt library](https://github.com/pbhogan/scrypt/blob/master/lib/scrypt.rb#L97-L146)
|
||
|
e.g. `func Calibrate(duration int, mem int, fallback Params) (Params, error)`
|
||
|
- contributed thanks to @tgulacsi.
|
||
|
|
||
|
## License
|
||
|
|
||
|
MIT Licensed. See LICENSE file for details.
|
||
|
|