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.

Issues
  • 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
  • Calibrate with fixed r

    Calibrate with fixed r

    [edit by @elithrar]: Addresses https://github.com/elithrar/simple-scrypt/issues/12

    bug enhancement needs-review 
    opened by LouisChrist 5
  • 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
  • Add GenerateFromPasswordWithLimit and Calibrate.

    Add GenerateFromPasswordWithLimit and Calibrate.

    Time and memory limit the derivation, and allow calibration - no cgo needed.

    opened by tgulacsi 2
  • 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
  • Migrate to CircleCI

    Migrate to CircleCI

    • [x] Remove TravisCI
    • [x] Use Go Modules
    • [x] Add CircleCI config
    • [x] Update README

    This also removes testing for Go versions prior to 1.7.

    build 
    opened by elithrar 2
  • [ci] Update .travis.yml to build Go 1.6

    [ci] Update .travis.yml to build Go 1.6

    enhancement 
    opened by elithrar 1
  • [build] use golang/dep

    [build] use golang/dep

    build 
    opened by elithrar 1
  • deps: define as a Go Module

    deps: define as a Go Module

    build 
    opened by elithrar 0
  • build: add GitHub Actions

    build: add GitHub Actions

    Test GitHub Actions per https://github.com/mvdan/github-actions-golang

    • [ ] Lint on latest
    • [ ] gofmt on latest
    • [ ] Run on tip
    build 
    opened by elithrar 0
  • CircleCI: Create config.yml

    CircleCI: Create config.yml

    build 
    opened by elithrar 1
  • 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
: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 253 Sep 28, 2021
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 14 Sep 14, 2021
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 28 Oct 13, 2021
Container Signing

cosign Container Signing, Verification and Storage in an OCI registry. Cosign aims to make signatures invisible infrastructure. Info Cosign is develop

sigstore 1.1k Oct 24, 2021
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 297 Oct 4, 2021
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 May 30, 2021
A rest application to update firewalld rules on a linux server

Firewalld-rest A REST application to dynamically update firewalld rules on a linux server. Firewalld is a firewall management tool for Linux operating

Prashant Gupta 310 Sep 23, 2021
A Go Module to interact with Passbolt, a Open source Password Manager for Teams

go-passbolt A Go Module to interact with Passbolt, a Open source Password Manager for Teams This Module tries to Support the Latest Passbolt Community

Samuel Lorch 3 Sep 23, 2021
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 24 Oct 11, 2021
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 32 Oct 19, 2021
Create strong passwords using words that are easy for you to remember

Grasp Create strong passwords using words that are easy for you to remember A way to circumvent password complexity rules and restrictions while only

Luca Sepe 17 Apr 5, 2021
An easy-to-use SHA-1 hash-cracker written in Golang.

wrench - An easy-to-use SHA-1 hash-cracker. Wrench is an SHA-1 hash-cracker that relies on wordlists for comparing hashes, and cracking them. Before W

null 4 Aug 30, 2021
SourcePoint is a C2 profile generator for Cobalt Strike command and control servers designed to ensure evasion.

SourcePoint SourcePoint is a polymorphic C2 profile generator for Cobalt Strike C2s, written in Go. SourcePoint allows unique C2 profiles to be genera

Tylous 429 Oct 17, 2021
How to systematically secure anything: a repository about security engineering

How to Secure Anything Security engineering is the discipline of building secure systems. Its lessons are not just applicable to computer security. In

Veeral Patel 6.4k Oct 17, 2021
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 87 Sep 16, 2021
Ah shhgit! Find secrets in your code. Secrets detection for your GitHub, GitLab and Bitbucket repositories: www.shhgit.com

shhgit helps secure forward-thinking development, operations, and security teams by finding secrets across their code before it leads to a security br

Paul 3.3k Oct 25, 2021
Cossack Labs 807 Oct 15, 2021