A convenience library for generating, comparing and inspecting password hashes using the scrypt KDF in Go 🔑

simple-scrypt

GoDoc Build Status

simple-scrypt provides a convenience wrapper around Go's existing 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 library in an effort to make it easy to migrate—and because it's an easy to grok API.

Installation

With a working Go toolchain:

go get -u github.com/elithrar/simple-scrypt

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:

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:

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
    }
}

Automatically Determining Parameters

Thanks to the work by tgulacsi, you can have simple-scrypt automatically determine the optimal parameters for you (time vs. memory). You should run this once on program startup, as calibrating parameters can be an expensive operation.

var params scrypt.Params

func main() {
    var err error
    // 500ms, 64MB of RAM per hash.
    params, err = scrypt.Calibrate(500*time.Millisecond, 64, Params{})
    if err != nil {
        return nil, err
    }

    ...
}

func RegisterUserHandler(w http.ResponseWriter, r *http.Request) {
    err := r.ParseForm()
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    // Make sure you validate: not empty, not too long, etc.
    email := r.PostFormValue("email")
    pass := r.PostFormValue("password")

    // Use our calibrated parameters
    hash, err := scrypt.GenerateFromPassword([]byte(pass), params)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    // Save to DB, etc.
}

Be aware that increasing these, whilst making it harder to brute-force the resulting hash, also increases the risk of a denial-of-service attack against your server. A surge in authenticate attempts (even if legitimate!) could consume all available resources.

License

MIT Licensed. See LICENSE file for details.

Owner
Matt Silverlock
Maintainer of the @gorilla web toolkit for Go. I care a lot about securing the web, making things fast for users, and good documentation.
Matt Silverlock
Comments
  • Tests and calibration fails on Linux/i386

    Tests and calibration fails on Linux/i386

    Hi,

    First: thanks for writing simple-scrypt! I'm using it for restic, a secure and fast backup program.

    A few days ago a user reported (https://github.com/restic/restic/issues/676) that restic fails with a mysterious error message:

    create key in backend at /tmp/foo failed: Calibrate: scrypt.Calibrate: scrypt: the parameters provided are invalid
    

    Building a 32 bit binary for restic and running it indeed produces invalid parameters, e.g. on my machine (rather recent Intel i5 CPU on a Thinkpad t460) Calibrate() returns the following values:

    {N:1073741824 R:8 P:1 SaltLen:16 DKLen:32}
    

    These parameters are (obviously) considered invalid.

    In addition I've discovered that the tests fail on 386: `` $ GOARCH=386 go test -v

    github.com/elithrar/simple-scrypt

    ./scrypt_test.go:26: constant 2147483648 overflows int ./scrypt_test.go:30: constant 2147483648 overflows int FAIL github.com/elithrar/simple-scrypt [build failed]

    Thanks!
  • TestCalibrate fails sometimes

    TestCalibrate fails sometimes

    TestCalibrate seems to fail with "0. GenerateFromPassword was too fast" sometimes:

    https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=851723 https://people.debian.org/~sanvila/build-logs/golang-github-elithrar-simple-scrypt/

  • Do not calibrate r

    Do not calibrate r

    r is not a memory parameter, it's a cache parameter. Scaling r scales both memory and CPU, just like N.

    So halving r has the exact same effect as halving N, except it makes scrypt less cache efficient on general purpose processors, artificially increasing is CPU requirements. ASICs would probably not pay that tax, though.

    I recommend just fixing r to 8, as cache line size is the same now as it was when the scrypt paper came out. If you want to increase CPU time without increasing memory, use p, as the Go implementation acts sequentially.

  • Travis: Build and run tests for current Go versions

    Travis: Build and run tests for current Go versions

    The build error seen in PR #4 is caused by the race detector, which simply uses too much RAM. On my machine with 12GiB I was unable to complete the test TestGenerateFromPassword with race detector enabled, the OOM killer took care of the process.

    The commit in here updates the Go version used for Travis up to Go 1.7.

    Closes #4

  • Please tag a new release

    Please tag a new release

    Hi,

    we've recently switched to using dep and I've discovered that the last released version ("v1.1") is really old already and does not include my fix for i386 (#6).

    Can you please tag a new release? Would you mind switching to semantic versioning for that? I.e. tag the next release as 1.2.0?

    Thanks!

  • Update LICENSE file to reflect Google employee contributions.

    Update LICENSE file to reflect Google employee contributions.

    As per https://opensource.google.com/docs/patching/#common-rules -

    If project authors are listed in a LICENSE, COPYING, AUTHORS or similar file, please add Google LLC. if it’s not already there. If Google Inc. is already listed then there is no need to change it to Google LLC. This step only applies if the project authors are listed somewhere.

    Updating this to reflect a few boxes I need to tick.

  • Go test fails on s390x arch

    Go test fails on s390x arch

    Any ideas?

    • go test -buildmode pie -compiler gc -ldflags '-extldflags '''-Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld '''' --- FAIL: TestCalibrate (22.60s) scrypt_test.go:140: GenerateFromPassword with scrypt.Params{N:32768, R:8, P:1, SaltLen:16, DKLen:32} took 390.533325ms () scrypt_test.go:140: GenerateFromPassword with scrypt.Params{N:65536, R:8, P:1, SaltLen:16, DKLen:32} took 566.445332ms () scrypt_test.go:140: GenerateFromPassword with scrypt.Params{N:32768, R:8, P:1, SaltLen:16, DKLen:32} took 224.123283ms () scrypt_test.go:145: 2. GenerateFromPassword was too fast (expected between 250ms and 750ms, got 224.123283ms) with scrypt.Params{N:32768, R:8, P:1, SaltLen:16, DKLen:32}. scrypt_test.go:140: GenerateFromPassword with scrypt.Params{N:32768, R:8, P:2, SaltLen:16, DKLen:32} took 501.654331ms () scrypt_test.go:140: GenerateFromPassword with scrypt.Params{N:16384, R:8, P:3, SaltLen:16, DKLen:32} took 437.232135ms () scrypt_test.go:140: GenerateFromPassword with scrypt.Params{N:8192, R:8, P:8, SaltLen:16, DKLen:32} took 484.281555ms () scrypt_test.go:140: GenerateFromPassword with scrypt.Params{N:4096, R:8, P:16, SaltLen:16, DKLen:32} took 424.747882ms () scrypt_test.go:140: GenerateFromPassword with scrypt.Params{N:512, R:8, P:146, SaltLen:16, DKLen:32} took 532.689005ms () FAIL exit status 1
Chrome-Password-Dumper - Chrome password dumper written in Go for Linux and Windows

Chrome-Password-Dumper Chrome password dumper written in Go for Linux and Window

Dec 19, 2022
A Go library to create hashes with a builtin expiration

ExpiringLink This is a simple library for creating unique strings that have a built in expiration. The target use case is web links for password reset

Mar 3, 2022
Converts Eth2 EIP-2335 scrypt keystores to pbkdf2 keystores (and vice-versa).

eth2-keystore-converter Converts Eth2 EIP-2335 scrypt keystores to pbkdf2 keystores (and vice-versa). Usage Converting a scrypt keystore to pbkdf2 usi

May 13, 2022
Convert any EIP-2335 keystores to scrypt or pbkdf2

eth2-keystore-converter Converts Eth2 EIP-2335 scrypt keystores to pbkdf2 keysto

May 13, 2022
CircleHash is a family of fast hashes that pass SMHasher, are faster than XXH64, SipHash, etc. and are easy to audit

CircleHash CircleHash is a family of non-cryptographic hash functions that pass every test in SMHasher (both rurban/smhasher and demerphq/smhasher). T

Sep 18, 2022
:key: Idiotproof golang password validation library inspired by Python's passlib

passlib for go 100% modules-free. Python's passlib is quite an amazing library. I'm not sure there's a password library in existence with more thought

Dec 19, 2022
Golang libraries for generating QR codes for Smart Health Cards representing COVID-19 Immunizations
Golang libraries for generating QR codes for Smart Health Cards representing COVID-19 Immunizations

go-smarthealthcards Golang libraries for generating QR codes for Smart Health Cards representing COVID-19 Immunizations. Usage Individual Libraries Yo

Dec 5, 2021
A simple and lightweight encrypted password manager written in Go.
A simple and lightweight encrypted password manager written in Go.

Osiris Password Manager A simple and lightweight encrypted password manager written in Go

Jun 16, 2022
Secret - Encrypt anything with a password
 Secret - Encrypt anything with a password

Secret - Encrypt anything with a password Ever wanted to hide a file? Now you can do it really easily! Usage secret {-e/--encrypt | -d/--decrypt} <sou

Aug 10, 2022
 🚀 cpwd is create password tool
 🚀 cpwd is create password tool

cpwd ?? cpwd is create password tool Install source code git clone https://github.com/songqii/cpwd_code.git cd $GOPATH/src/cpwd_code go build brew br

Dec 29, 2021
Use the HashPassword function to generate a hashed value for the provided password

hasher Use the 'HashPassword' function to generate a hashed value for the provided password. h, err := hasher.HashPassword("password") // h == XohImNo

Nov 1, 2021
Blooming Password

Blooming Password A program that implements the NIST 800-63-3b Banned Password Check using a bloom filter built from the Have I been pwned SHA1 passwo

Oct 13, 2022
eval the strength of a password

mpasswordeval eval the strength of a password 校验密码的安全性 包含以下几点校验 常规规则校验 密码长度 (必须指定) 是否包含数字 是否包含大写字母 是否包含小写字母 是否包含特殊符号 是否通过zxcvbn 是否通过pwned 是否在常用弱密码 使用示

Nov 22, 2022
profane password? generator

profaneword profane password generator (probably insecure), as suggested by u/gatestone. This is still missing some requirements: special characters e

Apr 21, 2022
A tiny secure-random password generator
A tiny secure-random password generator

go-psw A tiny golang tool for generating a crypto-random password in a terminal. Installation go install github.com/hedhyw/go-psw/cmd/psw@latest Usage

Jun 23, 2022
Berylbit PoW chain using Ethash, EPI-Burn and geth. The chain will be using bot congestion flashbot bundles through nodes

Berylbit PoW chain using Ethash, EPI-Burn and geth. The chain will be using bot congestion flashbot bundles through nodes. Soon, We will work towards

Jun 30, 2022
Ethermint is a scalable and interoperable Ethereum library, built on Proof-of-Stake with fast-finality using the Cosmos SDK.
Ethermint is a scalable and interoperable Ethereum library, built on Proof-of-Stake with fast-finality using the Cosmos SDK.

Ethermint Ethermint is a scalable and interoperable Ethereum library, built on Proof-of-Stake with fast-finality using the Cosmos SDK which runs on to

Jan 3, 2023
Jan 7, 2023
OmniFlix Hub is a blockchain built using Cosmos SDK and Tendermint and created with Starport.

OmniFlix Hub is the root chain of the OmniFlix Network. Sovereign chains and DAOs connect to the OmniFlix Hub to manage their web2 & web3 media operations (mint, manage, distribute & monetize) as well as community interactions.

Nov 10, 2022