• Stars
    star
    141
  • Rank 259,971 (Top 6 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 8 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Pure JavaScript implementation of the scrypt password-based key derivation function.

scrypt

The scrypt password-base key derivation function (pbkdf) is an algorithm designed to be brute-force resistant that converts human readable passwords into fixed length arrays of bytes, which can then be used as a key for symmetric block ciphers, private keys, et cetera.

Features:

  • Non-blocking - Gives other events in the event loop opportunities to run (asynchronous)
  • Cancellable - If the key is no longer required, the computation can be cancelled
  • Progress Callback - Provides the current progress of key derivation as a percentage complete

Tuning

The scrypt algorithm is, by design, expensive to execute, which increases the amount of time an attacker requires in order to brute force guess a password, adjustable by several parameters which can be tuned:

  • N - The CPU/memory cost; increasing this increases the overall difficulty
  • r - The block size; increasing this increases the dependency on memory latency and bandwidth
  • p - The parallelization cost; increasing this increases the dependency on multi-processing

Installing

node.js

If you do not require the progress callback or cancellable features, and your application is specific to node.js, you should likely use the built-in crypto package.

Otherwise, to install in node.js, use:

npm install scrypt-js

browser

<script src="https://raw.githubusercontent.com/ricmoo/scrypt-js/master/scrypt.js" type="text/javascript"></script>

API

scrypt . scrypt ( password , salt , N , r , p , dkLen [ , progressCallback ] ) => Promise

Compute the scrypt PBKDF asynchronously using a Promise. If progressCallback is provided, it is periodically called with a single parameter, a number between 0 and 1 (inclusive) indicating the completion progress; it will always emit 0 at the beginning and 1 at the end, and numbers between may repeat.

scrypt . syncScrypt ( password , salt , N , r , p , dkLen ) => Uint8Array

Compute the scrypt PBKDF synchronously. Keep in mind this may stall UI and other tasks and the asynchronous version is highly preferred.

Example

<html>
  <body>
    <div><span id="progress"></span>% complete...</div>
    <!-- These two libraries are highly recommended for encoding password/salt -->
    <script src="libs/buffer.js" type="text/javascript"></script>

    <!-- This shim library greatly improves performance of the scrypt algorithm -->
    <script src="libs/setImmediate.js" type="text/javascript"></script>

    <script src="index.js" type="text/javascript"></script>
    <script type="text/javascript">

      // See the section below: "Encoding Notes"
      const password = new buffer.SlowBuffer("anyPassword".normalize('NFKC'));
      const salt = new buffer.SlowBuffer("someSalt".normalize('NFKC'));

      const N = 1024, r = 8, p = 1;
      const dkLen = 32;

      function updateInterface(progress) {
          document.getElementById("progress").textContent = Math.trunc(100 * progress);
      }

      // Async
      const keyPromise = scrypt.scrypt(password, salt, N, r, p, dkLen, updateInterface);

      keyPromise.then(function(key) {
          console.log("Derived Key (async): ", key);
      });

      // Sync
      const key = scrypt.syncScrypt(password, salt, N, r, p, dkLen);
      console.log("Derived Key (sync): ", key);
    </script>
  </body>
</html>

Encoding Notes

TL;DR - either only allow ASCII characters in passwords, or use
        String.prototype.normalize('NFKC') on any password

It is HIGHLY recommended that you do NOT pass strings into this (or any password-base key derivation function) library without careful consideration; you should convert your strings to a canonical format that you will use consistently across all platforms.

When encoding passwords with UTF-8, it is important to realize that there may be multiple UTF-8 representations of a given string. Since the key generated by a password-base key derivation function is dependent on the specific bytes, this matters a great deal.

Composed vs. Decomposed

Certain UTF-8 code points can be combined with other characters to create composed characters. For example, the letter a with the umlaut diacritic mark (two dots over it) can be expressed two ways; as its composed form, U+00FC; or its decomposed form, which is the letter "u" followed by U+0308 (which basically means modify the previous character by adding an umlaut to it).

// In the following two cases, a "u" with an umlaut would be seen
> '\u00fc'
> 'u\u0308'


// In its composed form, it is 2 bytes long
> new Buffer('u\u0308'.normalize('NFKC'))
<Buffer c3 bc>
> new Buffer('\u00fc')
<Buffer c3 bc>

// Whereas the decomposed form is 3 bytes, the letter u followed by U+0308
> new Buffer('\u00fc'.normalize('NFKD'))
<Buffer 75 cc 88>
> new Buffer('u\u0308')
<Buffer 75 cc 88>

Compatibility equivalence mode

Certain strings are often displayed the same, even though they may have different semantic means. For example, UTF-8 provides a code point for the roman number for one, which appears as the letter I, in most fonts identically. Compatibility equivalence will fold these two cases into simply the capital letter I.

> '\u2160'
'I'
> 'I'
'I'
> '\u2160' === 'I'
false
> '\u2160'.normalize('NFKC') === 'I'
true

Normalizing

The normalize() method of a string can be used to convert a string to a specific form. Without going into too much detail, I generally recommend NFKC, however if you wish to dive deeper into this, a nice short summary can be found in Pythons unicodedata module's documentation.

For browsers without normalize() support, the npm unorm module can be used to polyfill strings.

Another example of encoding woes

One quick story I will share is a project which used the SHA256(encodeURI(password)) as a key, which (ignoring rainbow table attacks) had an unfortunate consequence of old web browsers replacing spaces with + while on new web browsers, replacing it with a %20, causing issues for anyone who used spaces in their password.

Suggestions

  • While it may be inconvenient to many international users, one option is to restrict passwords to a safe subset of ASCII, for example: /^[A-Za-z0-9!@#$%^&*()]+$/.
  • My personal recommendation is to normalize to the NFKC form, however, one could imagine setting their password to a Chinese phrase on one computer, and then one day using a computer that does not have Chinese input capabilities and therefore be unable to log in.

See: Unicode Equivalence

Tests

The test cases from the scrypt whitepaper are included in test/test-vectors.json and can be run using:

npm test

Special Thanks

I would like to thank @dchest for his scrypt-async library and for his assistance providing feedback and optimization suggestions.

License

MIT license.

References

Donations

Obviously, it's all licensed under the MIT license, so use it as you wish; but if you'd like to buy me a coffee, I won't complain. =)

  • Ethereum - ricmoo.eth

More Repositories

1

aes-js

A pure JavaScript implementation of the AES block cipher and all common modes of operation for node.js or web browsers.
JavaScript
1,451
star
2

QRCode

QR code generation library in C, optimized for low-power devices, such as Arduino.
C++
649
star
3

pyaes

Pure-Python implementation of AES block-cipher and common modes of operation.
Python
456
star
4

nightminer

Simple Python CryptoCurrency mining client
Python
198
star
5

GMEllipticCurveCrypto

Elliptic Curve Cryptography library for iOS (ECDSA and ECDH)
Objective-C
122
star
6

pycoind

Pure-Python full node and libraries for bitcoind-based crypto-currencies (eg. bitcoin, litecoin, etc)
Python
121
star
7

ethers-airdrop

A simple tool and library to deploy and manage a Merkle Air-Drop.
JavaScript
93
star
8

lurch

Lurch is an Ethereum VM para-virtualization (ish) written in EVM bytecode.
Assembly
83
star
9

pyscrypt

Pure-Python implementation of Scrypt PBKDF and scrypt file format library.
Python
82
star
10

ethers-meow

A simple command-line interface and library for CryptoKitties using ethers.js.
JavaScript
73
star
11

Takoyaki

ENS the fun and easy way; like a box of cereal, there is a toy at the bottom.
TypeScript
37
star
12

will-o-the-wisp

Intentionally self-destructive Ethereal on-chain-ish Wallet. (Proof-of-Concept bootstrap technique with CREATE2)
JavaScript
35
star
13

meeseeks-app

Safely load verified IPFS content on its own domain with browser Cross-Origin Policy protection.
HTML
28
star
14

multicall

A simple multicall contract and library wrapper to aggregate Ethereum calls.
TypeScript
24
star
15

flatworm

A very simple documentation generation tool.
JavaScript
18
star
16

gas-ticker

Oracle for tracking effective gas prices.
JavaScript
17
star
17

gremlins

A simple and easy-to-use language and compiler for querying blockchain data.
TypeScript
11
star
18

account-scanner

A simple example of a multi-call contract for token scanning.
JavaScript
11
star
19

BLECast

A custom protocol and library for iOS to send messages to Arduino over BLE advertising data.
C
10
star
20

sprinkles

NFTHack 2021 project: Sprinkles
C
8
star
21

GMClipper

An Objective-C wrapper for the Clipper polygon clipping and offsetting library.
C++
7
star
22

distinguished-format-strings

Deprecated. This idea has been obsoleted in favour of described data (see link).
JavaScript
5
star
23

waxlit

The WaxLit experimental blogging libraries and front-end
HTML
5
star
24

ethers-studio

Initial experimental project for Ethers Studio.
TypeScript
5
star
25

reticulate

Package manger for the ethers monorepo and ancillary packages.
TypeScript
4
star
26

coindjs

JavaScript implementation of Bitcoin (Namecoin, etc) full node and libraries for node.js.
JavaScript
4
star
27

vanity-contract

Miner for generating Vanity Contract Addresses.
C
3
star
28

hatch

Hatches ENS-controlled long-lived Wisp-like Proxies.
Solidity
3
star
29

ethdenver2024

ETHDenver 2024 Hackathon Project
1
star
30

promise-rationing

Promise-like interface to limit how many concurrent promises are executed.
JavaScript
1
star
31

sandbox

Random little things here and there, that I don't know where else to put.
JavaScript
1
star
32

USCC-2017

My entry for the Under-Handed Solidity Coding Competition 2017 (2nd place)
JavaScript
1
star