{ "name": "elithrar/simple-scrypt", "version": "0.1.4", "libraries": { "xv": "^1.1.25" }, "title": "simple-scrypt", "branch": "", "style": { "name": "Williamsburg", "componentSet": { "nav": "nav/BasicNav", "header": "header/LightBannerHeader", "article": "article/ReaderArticle", "footer": "footer/BasicFooter" }, "fontFamily": "Montserrat, sans-serif", "heading": { "fontWeight": 600, "letterSpacing": "0.1em" }, "colors": { "text": "#666666", "background": "#fff", "primary": "#0099e0", "secondary": "#ab61ff", "highlight": "#f7b", "muted": "#2b2d70", "border": "#ccd" } }, "content": [ { "component": "nav", "links": [ { "href": "https://github.com/elithrar/simple-scrypt", "text": "GitHub" } ] }, { "component": "header", "heading": "simple-scrypt", "subhead": "A convenience library for generating, comparing and inspecting password hashes using the scrypt KDF in Go.", "children": [ { "component": "ui/TweetButton", "text": "simple-scrypt: A convenience library for generating, comparing and inspecting password hashes using the scrypt KDF in Go.", "url": null }, { "component": "ui/GithubButton", "user": "elithrar", "repo": "simple-scrypt" } ] }, { "component": "article", "metadata": { "source": "github.readme" }, "html": "\n
\nsimple-scrypt provides a convenience wrapper around Go's existing\nscrypt package that makes it easier to\nsecurely derive strong keys ("hash user passwords"). This library allows you to:
\nThe API closely mirrors Go's bcrypt\nlibrary in an effort to make it easy to migrate—and because it's an easy to grok\nAPI.
\nWith a working Go toolchain:
\ngo get -u github.com/elithrar/simple-scrypt
simple-scrypt doesn't try to re-invent the wheel or do anything "special". It\nwraps the scrypt.Key
function as thinly as possible, generates a\ncrytographically secure salt for you using Go's crypto/rand
package, and\nreturns the derived key with the parameters prepended:
package main\n\nimport(\n "fmt"\n "log"\n\n "github.com/elithrar/simple-scrypt"\n)\n\nfunc main() {\n // e.g. r.PostFormValue("password")\n passwordFromForm := "prew8fid9hick6c"\n\n // Generates a derived key of the form "N$r$p$salt$dk" where N, r and p are defined as per\n // Colin Percival's scrypt paper: http://www.tarsnap.com/scrypt/scrypt.pdf\n // scrypt.Defaults (N=16384, r=8, p=1) makes it easy to provide these parameters, and\n // (should you wish) provide your own values via the scrypt.Params type.\n hash, err := scrypt.GenerateFromPassword([]byte(passwordFromForm), scrypt.DefaultParams)\n if err != nil {\n log.Fatal(err)\n }\n\n // Print the derived key with its parameters prepended.\n fmt.Printf("%s\\n", hash)\n\n // Uses the parameters from the existing derived key. Return an error if they don't match.\n err := scrypt.CompareHashAndPassword(hash, []byte(passwordFromForm))\n if err != nil {\n log.Fatal(err)\n }\n}
Upgrading derived keys from a set of parameters to a "stronger" set of parameters\nas hardware improves, or as you scale (and move your auth process to separate\nhardware), can be pretty useful. Here's how to do it with simple-scrypt:
\nfunc main() {\n // SCENE: We've successfully authenticated a user, compared their submitted\n // (cleartext) password against the derived key stored in our database, and\n // now want to upgrade the parameters (more rounds, more parallelism) to\n // reflect some shiny new hardware we just purchased. As the user is logging\n // in, we can retrieve the parameters used to generate their key, and if\n // they don't match our "new" parameters, we can re-generate the key while\n // we still have the cleartext password in memory\n // (e.g. before the HTTP request ends).\n current, err := scrypt.Cost(hash)\n if err != nil {\n log.Fatal(err)\n }\n\n // Now to check them against our own Params struct (e.g. using reflect.DeepEquals)\n // and determine whether we want to generate a new key with our "upgraded" parameters.\n slower := scrypt.Params{\n N: 32768,\n R: 8,\n P: 2,\n SaltLen: 16,\n DKLen: 32,\n }\n\n if !reflect.DeepEqual(current, slower) {\n // Re-generate the key with the slower parameters\n // here using scrypt.GenerateFromPassword\n }\n}
Thanks to the work by tgulacsi, you can have simple-scrypt\nautomatically determine the optimal parameters for you (time vs. memory). You should run this once\non program startup, as calibrating parameters can be an expensive operation.
\nvar params scrypt.Params\n\nfunc main() {\n var err error\n // 500ms, 64MB of RAM per hash.\n params, err = scrypt.Calibrate(500*time.Millisecond, 64, Params{})\n if err != nil {\n return nil, err\n }\n\n ...\n}\n\nfunc RegisterUserHandler(w http.ResponseWriter, r *http.Request) {\n err := r.ParseForm()\n if err != nil {\n http.Error(w, err.Error(), http.StatusBadRequest)\n return\n }\n\n // Make sure you validate: not empty, not too long, etc.\n email := r.PostFormValue("email")\n pass := r.PostFormValue("password")\n\n // Use our calibrated parameters\n hash, err := scrypt.GenerateFromPassword([]byte(pass), params)\n if err != nil {\n http.Error(w, err.Error(), http.StatusBadRequest)\n return\n }\n\n // Save to DB, etc.\n}
Be aware that increasing these, whilst making it harder to brute-force the resulting hash, also\nincreases the risk of a denial-of-service attack against your server. A surge in authenticate\nattempts (even if legitimate!) could consume all available resources.
\nMIT Licensed. See LICENSE file for details.
\n" }, { "component": "footer", "links": [ { "href": "https://github.com/elithrar/simple-scrypt", "text": "GitHub" }, { "href": "https://github.com/elithrar", "text": "elithrar" } ] } ] }