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

Overview

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.

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!
    bug 
    opened by fd0 10
  • 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/

    help-wanted 
    opened by legrostdg 7
  • 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.

    opened by FiloSottile 4
  • 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

    opened by fd0 3
  • 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!

    build documentation 
    opened by fd0 2
  • 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.

    opened by elithrar 0
  • 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
    build 
    opened by copart 1
Releases(v1.3.0)
  • v1.3.0(Apr 2, 2018)

    A bug in Calibrate was fixed. This bug was based on a misinterpretation of the role of the "r" parameter in scrypt, which is tied to CPU cache lines as opposed to general memory. r is now fixed at a value of 8.

    CHANGELOG

    d150773 [bugfix] Calibrate with fixed r (#13)

    Source code(tar.gz)
    Source code(zip)
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
A light package for generating and comparing password hashing with argon2 in Go

argon2-hashing argon2-hashing provides a light wrapper around Go's argon2 package. Argon2 was the winner of the Password Hashing Competition that make

Andrey Skurlatov 19 Sep 27, 2022
Hashing algorithms simplified (supports Argon2, Bcrypt, Scrypt, PBKDF2, Chacha20poly1305 and more in the future)

PHC Crypto Inspired by Upash, also implementing PHC string format Usage Currently there are two options of using this package: Import all Import speci

Reinaldy Rafli 23 Nov 27, 2022
Convenience of containers, security of virtual machines

Convenience of containers, security of virtual machines With firebuild, you can build and deploy secure VMs directly from Dockerfiles and Docker image

null 59 Oct 16, 2022
Scans files for .jars potentially vulnerable to Log4Shell (CVE-2021-44228) by inspecting the class paths inside the .jar.

log4shelldetect Scans a file or folder recursively for jar files that may be vulnerable to Log4Shell (CVE-2021-44228) by inspecting the class paths in

Jason Chu 43 Nov 5, 2022
Implementation of io/fs.FS that appends SHA256 hashes to filenames to allow for aggressive HTTP caching.

hashfs Implementation of io/fs.FS that appends SHA256 hashes to filenames to allow for aggressive HTTP caching.

Ben Johnson 220 Nov 16, 2022
Not Yet Another Password Manager written in Go using libsodium

secrets Secure and simple passwords manager written in Go. It aims to be NYAPM (Not Yet Another Password Manager), but tries to be different from othe

Jarmo Pertman 28 May 30, 2022
password manager using age for encryption

page ====== password manager using age (https://age-encryption.org/) for encryption. encrypted secrets are files in the $PAGE_SECRETS/ directory that

null 5 May 30, 2022
Custom GPG pinentry program for macOS that allows using Touch ID for fetching the password from the macOS keychain.

pinentry-touchid Custom GPG pinentry program for macOS that allows using Touch ID for fetching the password from the macOS keychain. Macbook Pro devic

Jorge Luis Betancourt 285 Nov 10, 2022
A Go Library For Generating Random, Rule Based Passwords. Many Random, Much Secure.

Can Haz Password? A Go library for generating random, rule based passwords. Many random, much secure. Features Randomized password length (bounded). T

null 7 Dec 6, 2021
:key: Idiotproof golang password validation library inspired by Python's passlib

passlib for go Python's passlib is quite an amazing library. I'm not sure there's a password library in existence with more thought put into it, or wi

Hugo Landau 273 Nov 10, 2022
Secure Remote Password library for Go

go-srp NOTE: This is a port of node-srp to Go. I recommend reading their README for general information about the use of SRP. Installation go get gith

Kong 38 Aug 8, 2022
User enumeration and password bruteforce on Azure, ADFS, OWA, O365 and gather emails on Linkedin

goEnumBruteSpray Description Summary The recommended module is o365 for user enumeration and passwords bruteforce / spray . Additional information can

null 316 Nov 19, 2022
An opinionated helper for generating tls certificates

Certificates helper This is an opinionated helper for generating tls certificates. It outputs only in PEM format but this enables you easily generate

Martijn van Maasakkers 24 Sep 27, 2022
EarlyBird is a sensitive data detection tool capable of scanning source code repositories for clear text password violations, PII, outdated cryptography methods, key files and more.

EarlyBird is a sensitive data detection tool capable of scanning source code repositories for clear text password violations, PII, outdated cryptograp

American Express 515 Nov 17, 2022
Argon2 password hashing package for go with constant time hash comparison

argon2pw Argon2 password hashing package with constant time hash comparison Preface: Argon2 was selected as the winner of the Password Hashing Competi

Raja Bhatia 89 Sep 27, 2022
Password generator written in Go

go-generate-password Password generator written in Go. Use as a library or as a CLI. Usage CLI go-generate-password can be used on the cli, just insta

Miles Croxford 47 Oct 28, 2022
Validate the Strength of a Password in Go

go-password-validator Simple password validator using raw entropy values. Hit the project with a star if you find it useful ⭐ Supported by Qvault This

Lane Wagner 365 Nov 20, 2022
A simple Go script to brute force or parse a password-protected PKCS#12 (PFX/P12) file.

A simple Go script to brute force or parse a password-protected PKCS#12 (PFX/P12) file.

Evi1cg 34 Oct 14, 2022