├── .gitignore ├── .npmignore ├── .travis.yml ├── Gruntfile.js ├── LICENSE ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── scrypt-async.js ├── scrypt-async.min.js └── test ├── unittests.html └── unittests.js /.gitignore: -------------------------------------------------------------------------------- 1 | coverage 2 | node_modules 3 | test/lib 4 | .vscode -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .travis.yml 3 | Gruntfile.js 4 | bower.json 5 | coverage 6 | demo.html 7 | test 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "stable" 5 | env: 6 | global: 7 | - secure: "Q/2G3euxBPi7m89kk4qDrHsaKEqbwtbPQvxMBBLb1o3UrvFB4Py6BworZBZp3qOrTZKxtkYHN+UhngXtwQQKOs3IfFSrxILNgB3ryO0YxkfvvRz5C9UBEJYgyQl4Jz83zD9Wl83WFgwWFQFwUTXTMu0E8nZ/k1qFqWIMw6dJioY=" 8 | - secure: "bEIJZp5mgvYs5Ko6TipP307n0B2/UDS4voXTnsYYs7J5ck6up8KIGFyKBz2BQo/v4N4RN4hxpP3XAeXY+n9w3EyALR9ZE3XLhw+3cor1DefEGlUxGBzkAQlEtIokWJ0afmaTlLTggJ6bTBuv6W/h5/yGPyfNlyVpowhBslT0JR4=" 9 | cache: 10 | directories: 11 | - node_modules 12 | before_script: 13 | - npm install -g grunt-cli 14 | script: 15 | - grunt build 16 | - grunt test_and_coveralls 17 | - travis_wait grunt saucelabs || true 18 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | grunt.initConfig({ 4 | browserify: { 5 | unittests: { 6 | files: { 7 | 'test/lib/unittests-bundle.js': [ './test/unittests.js' ] 8 | } 9 | } 10 | }, 11 | connect: { 12 | server: { 13 | options: { 14 | port: 3000, 15 | base: './test' 16 | } 17 | } 18 | }, 19 | copy: { 20 | test: { 21 | expand: true, 22 | flatten: true, 23 | cwd: 'node_modules/', 24 | src: ['mocha/mocha.css', 'mocha/mocha.js'], 25 | dest: 'test/lib/' 26 | } 27 | }, 28 | mocha_istanbul: { 29 | coveralls: { 30 | src: ['test'], 31 | options: { 32 | coverage:true, 33 | timeout: 6000, 34 | reportFormats: ['cobertura','lcovonly'] 35 | } 36 | } 37 | }, 38 | 'saucelabs-mocha': { 39 | all: { 40 | options: { 41 | username: process.env.SAUCE_USERNAME, 42 | key: function() { return process.env.SAUCE_ACCESS_KEY; }, 43 | urls: ['http://127.0.0.1:3000/unittests.html'], 44 | build: process.env.TRAVIS_JOB_ID, 45 | testname: 'Sauce Unit Test for scrypt-async-js', 46 | browsers: [ 47 | { 48 | browserName: "safari", 49 | platform: "OS X 10.10" 50 | }, 51 | { 52 | browserName: "chrome", 53 | platform: "OS X 10.10", 54 | version: "48" 55 | }, 56 | { 57 | browserName: "firefox", 58 | platform: "OS X 10.10", 59 | version: "44" 60 | }, 61 | { 62 | browserName: "microsoftedge", 63 | version: "13.10586", 64 | platform: "Windows 10" 65 | }, 66 | { 67 | browserName: "internet explorer", 68 | version: "11", 69 | platform: "Windows 8.1" 70 | }, 71 | { 72 | browserName: "internet explorer", 73 | version: "10", 74 | platform: "Windows 8" 75 | }, 76 | { 77 | browserName: "internet explorer", 78 | version: "9", 79 | platform: "Windows 7" 80 | }, 81 | { 82 | browserName: "internet explorer", 83 | version: "8", 84 | platform: "Windows 7" 85 | }, 86 | { 87 | browserName: "chrome", 88 | platform: "Windows 8.1", 89 | version: "beta" 90 | }, 91 | { 92 | browserName: "firefox", 93 | platform: "Windows 8.1", 94 | version: "beta" 95 | }, 96 | { 97 | browserName: "iphone", 98 | platform: "OS X 10.10", 99 | version: "8.2" 100 | }, 101 | { 102 | browserName: "chrome", 103 | platform: "Linux", 104 | version: "37" 105 | }, 106 | { 107 | browserName: "firefox", 108 | platform: "Linux", 109 | version: "34" 110 | }, 111 | { 112 | browserName: "android", 113 | platform: "Linux", 114 | version: "5.1" 115 | }, 116 | { 117 | browserName: "android", 118 | platform: "Linux", 119 | version: "4.4" 120 | }, 121 | { 122 | browserName: "iphone", 123 | platform: "OS X 10.10", 124 | version: "7.1" 125 | }, 126 | { 127 | browserName: "iphone", 128 | platform: "OS X 10.10", 129 | version: "9.2" 130 | } 131 | ], 132 | public: "public", 133 | maxRetries: 3, 134 | throttled: 2, 135 | pollInterval: 4000, 136 | statusCheckAttempts: 200 137 | } 138 | }, 139 | }, 140 | uglify: { 141 | scrypt: { 142 | options: { 143 | ie8: true, 144 | preserveComments: function(node, comment) { 145 | return comment && comment.value && comment.value.length && 146 | comment.value[0] === "!"; 147 | } 148 | }, 149 | files: { 150 | 'scrypt-async.min.js' : [ 'scrypt-async.js' ] 151 | } 152 | } 153 | } 154 | }); 155 | 156 | grunt.loadNpmTasks('grunt-browserify'); 157 | grunt.loadNpmTasks('grunt-contrib-connect'); 158 | grunt.loadNpmTasks('grunt-contrib-copy'); 159 | grunt.loadNpmTasks('grunt-contrib-uglify'); 160 | grunt.loadNpmTasks('grunt-mocha-istanbul') 161 | grunt.loadNpmTasks('grunt-saucelabs'); 162 | 163 | grunt.event.on('coverage', function(lcov, done){ 164 | require('coveralls').handleInput(lcov, function(err){ 165 | if (err) { 166 | return done(err); 167 | } 168 | done(); 169 | }); 170 | }); 171 | 172 | grunt.registerTask('build', ['uglify']); 173 | grunt.registerTask('test', ['browserify', 'copy:test', 'mocha_istanbul']); 174 | grunt.registerTask('test_and_coveralls', ['browserify', 'copy:test', 'mocha_istanbul:coveralls']); 175 | grunt.registerTask('saucelabs', ['connect', 'saucelabs-mocha']); 176 | }; 177 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2016 Dmitry Chestnykh. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | scrypt-async 2 | ============ 3 | 4 | [![Build Status](https://travis-ci.org/dchest/scrypt-async-js.svg?branch=master)](https://travis-ci.org/dchest/scrypt-async-js) 5 | [![Coverage Status](https://coveralls.io/repos/dchest/scrypt-async-js/badge.svg)](https://coveralls.io/r/dchest/scrypt-async-js) 6 | 7 | [![Saucelabs Test Status](https://saucelabs.com/browser-matrix/scrypt.svg)](https://saucelabs.com/u/scrypt) 8 | 9 | Fast "async" scrypt implementation in JavaScript. 10 | 11 | Works in browsers without throwing "kill slow script" warnings due to 12 | configurable interruptStep, which yields from calculation. Compatible even with 13 | old versions of IE. Also works with Node.js (but you should really use the C 14 | implementation for that). 15 | 16 | 17 | Installation 18 | ------------ 19 | 20 | You can install it via a package manager: 21 | 22 | [NPM](https://www.npmjs.org/): 23 | 24 | $ npm install scrypt-async 25 | 26 | [Yarn](https://yarnpkg.com/): 27 | 28 | $ yarn add scrypt-async 29 | 30 | or [download source code](https://github.com/dchest/scrypt-async-js/releases). 31 | 32 | To improve performance with small interruptStep values, use `setImmediate` shim, 33 | such as . 34 | 35 | 36 | Usage 37 | ----- 38 | 39 | ### Modern API 40 | 41 | #### scrypt(password, salt, options, callback) 42 | 43 | Derives a key from password and salt and calls callback 44 | with derived key as the only argument. 45 | 46 | If interruptStep is set, calculations are interrupted with setImmediate (or 47 | zero setTimeout) at the given interruptSteps to avoid freezing the browser. 48 | If it's not set or set to zero, the callback is called immediately after the 49 | calculation, avoiding setImmediate. 50 | 51 | #### Arguments: 52 | 53 | * *password* — password (`string` or `Array` of bytes or `Uint8Array`) 54 | * *salt* — salt (`string` or `Array` of bytes or `Uint8Array`) 55 | * *options* — object with key derivation options 56 | * *callback* — callback function receiving result (`function (Array|Uint8Array|string)`) 57 | 58 | ##### Options: 59 | 60 | * `N` — CPU/memory cost parameter (must be power of two; 61 | alternatively, you can specify `logN` where *N = 2^logN*). 62 | * `r` — block size parameter 63 | * `p` — parallelization parameter (default is 1) 64 | * `dkLen` — derived key length (default is 32) 65 | * `interruptStep` — (optional) the amount of loop cycles to execute before the next setImmediate/setTimeout (defaults to 0) 66 | * `encoding` — (optional) result encoding `'base64'` or `'hex'` (result will be a `string`), `'binary'` (result will be a `Uint8Array`) or undefined (result will be an `Array` of bytes). 67 | 68 | #### Example: 69 | 70 | ```javascript 71 | scrypt('mypassword', 'saltysalt', { 72 | N: 16384, 73 | r: 8, 74 | p: 1, 75 | dkLen: 16, 76 | encoding: 'hex' 77 | }, function(derivedKey) { 78 | console.log(derivedKey); // "5012b74fca8ec8a4a0a62ffdeeee959d" 79 | }); 80 | ``` 81 | 82 | ### Legacy API (deprecated) 83 | 84 | #### scrypt(password, salt, logN, r, dkLen, [interruptStep], callback, [encoding]) 85 | 86 | Legacy API doesn't support parallelization parameter greater than 1. 87 | 88 | ##### Arguments: 89 | 90 | * *password* — password (`string` or `Array` of bytes or `Uint8Array`) 91 | * *salt* — salt (`string` or `Array` of bytes or `Uint8Array`) 92 | * *logN* — CPU/memory cost parameter (1 to 31) 93 | * *r* — block size parameter 94 | * *dkLen* — length of derived key 95 | * *interruptStep* — (optional) the amount of loop cycles to execute before the next setImmediate/setTimeout (defaults to 1000) 96 | * *callback* — callback function receiving result (`function (Array|Uint8Array|string)`) 97 | * *encoding* — (optional) result encoding (`'base64'`, `'hex'`, `'binary'` or undefined). 98 | 99 | When encoding is not set, the result is an `Array` of bytes. 100 | 101 | 102 | License 103 | ------- 104 | 105 | BSD-like, see LICENSE file or MIT license at your choice. 106 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | scrypt-async-js demo 7 | 30 | 31 | 32 | 33 |

scrypt-async-js demo

34 |
35 |

36 | 37 | 38 |

39 |

40 | 41 | 42 |

43 |

44 | 45 | 46 |

47 |

48 | 49 | 52 | 53 |

54 |

55 | 56 | 57 |

58 |

59 | 60 | 61 |

62 |

63 | 64 | 69 |

70 | 71 |
72 |
73 | 74 | 75 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scrypt-async", 3 | "version": "2.0.1", 4 | "description": "Fast \"async\" scrypt implementation in JavaScript.", 5 | "main": "scrypt-async.js", 6 | "scripts": { 7 | "test": "grunt test", 8 | "build": "grunt build" 9 | }, 10 | "devDependencies": { 11 | "coveralls": "3.0.2", 12 | "grunt": "1.0.3", 13 | "grunt-browserify": "5.3.0", 14 | "grunt-contrib-connect": "1.0.2", 15 | "grunt-contrib-copy": "1.0.0", 16 | "grunt-contrib-uglify": "4.0.0", 17 | "grunt-mocha-istanbul": "5.0.2", 18 | "grunt-saucelabs": "9.0.0", 19 | "istanbul": "0.4.5", 20 | "mocha": "5.2.0" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/dchest/scrypt-async-js.git" 25 | }, 26 | "keywords": [ 27 | "crypto", 28 | "cryptography", 29 | "scrypt", 30 | "password" 31 | ], 32 | "author": "Dmitry Chestnykh", 33 | "license": "BSD", 34 | "bugs": { 35 | "url": "https://github.com/dchest/scrypt-async-js/issues" 36 | }, 37 | "homepage": "https://github.com/dchest/scrypt-async-js" 38 | } 39 | -------------------------------------------------------------------------------- /scrypt-async.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Fast "async" scrypt implementation in JavaScript. 3 | * Copyright (c) 2013-2016 Dmitry Chestnykh | BSD License 4 | * https://github.com/dchest/scrypt-async-js 5 | */ 6 | 7 | /** 8 | * scrypt(password, salt, options, callback) 9 | * 10 | * where 11 | * 12 | * password and salt are strings or arrays of bytes (Array of Uint8Array) 13 | * options is 14 | * 15 | * { 16 | * N: // CPU/memory cost parameter, must be power of two 17 | * // (alternatively, you can specify logN) 18 | * r: // block size 19 | * p: // parallelization parameter 20 | * dkLen: // length of derived key, default = 32 21 | * encoding: // optional encoding: 22 | * "base64" - standard Base64 encoding 23 | * "hex" — hex encoding, 24 | * "binary" — Uint8Array, 25 | * undefined/null - Array of bytes 26 | * interruptStep: // optional, steps to split calculations (default is 0) 27 | * } 28 | * 29 | * Derives a key from password and salt and calls callback 30 | * with derived key as the only argument. 31 | * 32 | * Calculations are interrupted with setImmediate (or zero setTimeout) at the 33 | * given interruptSteps to avoid freezing the browser. If it's undefined or zero, 34 | * the callback is called immediately after the calculation, avoiding setImmediate. 35 | * 36 | * Legacy way (only supports p = 1) to call this function is: 37 | * 38 | * scrypt(password, salt, logN, r, dkLen, [interruptStep], callback, [encoding]) 39 | * 40 | * In legacy API, if interruptStep is not given, it defaults to 1000. 41 | * Pass 0 to have callback called immediately. 42 | * 43 | */ 44 | function scrypt(password, salt, logN, r, dkLen, interruptStep, callback, encoding) { 45 | 'use strict'; 46 | 47 | function SHA256(m) { 48 | /** @const */ var K = [ 49 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 50 | 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 51 | 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 52 | 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 53 | 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 54 | 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 55 | 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 56 | 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 57 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 58 | 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 59 | 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 60 | 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 61 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 62 | ]; 63 | 64 | var h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372, h3 = 0xa54ff53a, 65 | h4 = 0x510e527f, h5 = 0x9b05688c, h6 = 0x1f83d9ab, h7 = 0x5be0cd19, 66 | w = new Array(64); 67 | 68 | function blocks(p) { 69 | var off = 0, len = p.length; 70 | while (len >= 64) { 71 | var a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7, 72 | u, i, j, t1, t2; 73 | 74 | for (i = 0; i < 16; i++) { 75 | j = off + i*4; 76 | w[i] = ((p[j] & 0xff)<<24) | ((p[j+1] & 0xff)<<16) | 77 | ((p[j+2] & 0xff)<<8) | (p[j+3] & 0xff); 78 | } 79 | 80 | for (i = 16; i < 64; i++) { 81 | u = w[i-2]; 82 | t1 = ((u>>>17) | (u<<(32-17))) ^ ((u>>>19) | (u<<(32-19))) ^ (u>>>10); 83 | 84 | u = w[i-15]; 85 | t2 = ((u>>>7) | (u<<(32-7))) ^ ((u>>>18) | (u<<(32-18))) ^ (u>>>3); 86 | 87 | w[i] = (((t1 + w[i-7]) | 0) + ((t2 + w[i-16]) | 0)) | 0; 88 | } 89 | 90 | for (i = 0; i < 64; i++) { 91 | t1 = ((((((e>>>6) | (e<<(32-6))) ^ ((e>>>11) | (e<<(32-11))) ^ 92 | ((e>>>25) | (e<<(32-25)))) + ((e & f) ^ (~e & g))) | 0) + 93 | ((h + ((K[i] + w[i]) | 0)) | 0)) | 0; 94 | 95 | t2 = ((((a>>>2) | (a<<(32-2))) ^ ((a>>>13) | (a<<(32-13))) ^ 96 | ((a>>>22) | (a<<(32-22)))) + ((a & b) ^ (a & c) ^ (b & c))) | 0; 97 | 98 | h = g; 99 | g = f; 100 | f = e; 101 | e = (d + t1) | 0; 102 | d = c; 103 | c = b; 104 | b = a; 105 | a = (t1 + t2) | 0; 106 | } 107 | 108 | h0 = (h0 + a) | 0; 109 | h1 = (h1 + b) | 0; 110 | h2 = (h2 + c) | 0; 111 | h3 = (h3 + d) | 0; 112 | h4 = (h4 + e) | 0; 113 | h5 = (h5 + f) | 0; 114 | h6 = (h6 + g) | 0; 115 | h7 = (h7 + h) | 0; 116 | 117 | off += 64; 118 | len -= 64; 119 | } 120 | } 121 | 122 | blocks(m); 123 | 124 | var i, bytesLeft = m.length % 64, 125 | bitLenHi = (m.length / 0x20000000) | 0, 126 | bitLenLo = m.length << 3, 127 | numZeros = (bytesLeft < 56) ? 56 : 120, 128 | p = m.slice(m.length - bytesLeft, m.length); 129 | 130 | p.push(0x80); 131 | for (i = bytesLeft + 1; i < numZeros; i++) p.push(0); 132 | p.push((bitLenHi>>>24) & 0xff); 133 | p.push((bitLenHi>>>16) & 0xff); 134 | p.push((bitLenHi>>>8) & 0xff); 135 | p.push((bitLenHi>>>0) & 0xff); 136 | p.push((bitLenLo>>>24) & 0xff); 137 | p.push((bitLenLo>>>16) & 0xff); 138 | p.push((bitLenLo>>>8) & 0xff); 139 | p.push((bitLenLo>>>0) & 0xff); 140 | 141 | blocks(p); 142 | 143 | return [ 144 | (h0>>>24) & 0xff, (h0>>>16) & 0xff, (h0>>>8) & 0xff, (h0>>>0) & 0xff, 145 | (h1>>>24) & 0xff, (h1>>>16) & 0xff, (h1>>>8) & 0xff, (h1>>>0) & 0xff, 146 | (h2>>>24) & 0xff, (h2>>>16) & 0xff, (h2>>>8) & 0xff, (h2>>>0) & 0xff, 147 | (h3>>>24) & 0xff, (h3>>>16) & 0xff, (h3>>>8) & 0xff, (h3>>>0) & 0xff, 148 | (h4>>>24) & 0xff, (h4>>>16) & 0xff, (h4>>>8) & 0xff, (h4>>>0) & 0xff, 149 | (h5>>>24) & 0xff, (h5>>>16) & 0xff, (h5>>>8) & 0xff, (h5>>>0) & 0xff, 150 | (h6>>>24) & 0xff, (h6>>>16) & 0xff, (h6>>>8) & 0xff, (h6>>>0) & 0xff, 151 | (h7>>>24) & 0xff, (h7>>>16) & 0xff, (h7>>>8) & 0xff, (h7>>>0) & 0xff 152 | ]; 153 | } 154 | 155 | function PBKDF2_HMAC_SHA256_OneIter(password, salt, dkLen) { 156 | // compress password if it's longer than hash block length 157 | if(password.length > 64) { 158 | // SHA256 expects password to be an Array. If it's not 159 | // (i.e. it doesn't have .push method), convert it to one. 160 | password = SHA256(password.push ? password : Array.prototype.slice.call(password, 0)); 161 | } 162 | 163 | var i, innerLen = 64 + salt.length + 4, 164 | inner = new Array(innerLen), 165 | outerKey = new Array(64), 166 | dk = []; 167 | 168 | // inner = (password ^ ipad) || salt || counter 169 | for (i = 0; i < 64; i++) inner[i] = 0x36; 170 | for (i = 0; i < password.length; i++) inner[i] ^= password[i]; 171 | for (i = 0; i < salt.length; i++) inner[64+i] = salt[i]; 172 | for (i = innerLen - 4; i < innerLen; i++) inner[i] = 0; 173 | 174 | // outerKey = password ^ opad 175 | for (i = 0; i < 64; i++) outerKey[i] = 0x5c; 176 | for (i = 0; i < password.length; i++) outerKey[i] ^= password[i]; 177 | 178 | // increments counter inside inner 179 | function incrementCounter() { 180 | for (var i = innerLen-1; i >= innerLen-4; i--) { 181 | inner[i]++; 182 | if (inner[i] <= 0xff) return; 183 | inner[i] = 0; 184 | } 185 | } 186 | 187 | // output blocks = SHA256(outerKey || SHA256(inner)) ... 188 | while (dkLen >= 32) { 189 | incrementCounter(); 190 | dk = dk.concat(SHA256(outerKey.concat(SHA256(inner)))); 191 | dkLen -= 32; 192 | } 193 | if (dkLen > 0) { 194 | incrementCounter(); 195 | dk = dk.concat(SHA256(outerKey.concat(SHA256(inner))).slice(0, dkLen)); 196 | } 197 | return dk; 198 | } 199 | 200 | function salsaXOR(tmp, B, bin, bout) { 201 | var j0 = tmp[0] ^ B[bin++], 202 | j1 = tmp[1] ^ B[bin++], 203 | j2 = tmp[2] ^ B[bin++], 204 | j3 = tmp[3] ^ B[bin++], 205 | j4 = tmp[4] ^ B[bin++], 206 | j5 = tmp[5] ^ B[bin++], 207 | j6 = tmp[6] ^ B[bin++], 208 | j7 = tmp[7] ^ B[bin++], 209 | j8 = tmp[8] ^ B[bin++], 210 | j9 = tmp[9] ^ B[bin++], 211 | j10 = tmp[10] ^ B[bin++], 212 | j11 = tmp[11] ^ B[bin++], 213 | j12 = tmp[12] ^ B[bin++], 214 | j13 = tmp[13] ^ B[bin++], 215 | j14 = tmp[14] ^ B[bin++], 216 | j15 = tmp[15] ^ B[bin++], 217 | u, i; 218 | 219 | var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, 220 | x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, 221 | x15 = j15; 222 | 223 | for (i = 0; i < 8; i += 2) { 224 | u = x0 + x12; x4 ^= u<<7 | u>>>(32-7); 225 | u = x4 + x0; x8 ^= u<<9 | u>>>(32-9); 226 | u = x8 + x4; x12 ^= u<<13 | u>>>(32-13); 227 | u = x12 + x8; x0 ^= u<<18 | u>>>(32-18); 228 | 229 | u = x5 + x1; x9 ^= u<<7 | u>>>(32-7); 230 | u = x9 + x5; x13 ^= u<<9 | u>>>(32-9); 231 | u = x13 + x9; x1 ^= u<<13 | u>>>(32-13); 232 | u = x1 + x13; x5 ^= u<<18 | u>>>(32-18); 233 | 234 | u = x10 + x6; x14 ^= u<<7 | u>>>(32-7); 235 | u = x14 + x10; x2 ^= u<<9 | u>>>(32-9); 236 | u = x2 + x14; x6 ^= u<<13 | u>>>(32-13); 237 | u = x6 + x2; x10 ^= u<<18 | u>>>(32-18); 238 | 239 | u = x15 + x11; x3 ^= u<<7 | u>>>(32-7); 240 | u = x3 + x15; x7 ^= u<<9 | u>>>(32-9); 241 | u = x7 + x3; x11 ^= u<<13 | u>>>(32-13); 242 | u = x11 + x7; x15 ^= u<<18 | u>>>(32-18); 243 | 244 | u = x0 + x3; x1 ^= u<<7 | u>>>(32-7); 245 | u = x1 + x0; x2 ^= u<<9 | u>>>(32-9); 246 | u = x2 + x1; x3 ^= u<<13 | u>>>(32-13); 247 | u = x3 + x2; x0 ^= u<<18 | u>>>(32-18); 248 | 249 | u = x5 + x4; x6 ^= u<<7 | u>>>(32-7); 250 | u = x6 + x5; x7 ^= u<<9 | u>>>(32-9); 251 | u = x7 + x6; x4 ^= u<<13 | u>>>(32-13); 252 | u = x4 + x7; x5 ^= u<<18 | u>>>(32-18); 253 | 254 | u = x10 + x9; x11 ^= u<<7 | u>>>(32-7); 255 | u = x11 + x10; x8 ^= u<<9 | u>>>(32-9); 256 | u = x8 + x11; x9 ^= u<<13 | u>>>(32-13); 257 | u = x9 + x8; x10 ^= u<<18 | u>>>(32-18); 258 | 259 | u = x15 + x14; x12 ^= u<<7 | u>>>(32-7); 260 | u = x12 + x15; x13 ^= u<<9 | u>>>(32-9); 261 | u = x13 + x12; x14 ^= u<<13 | u>>>(32-13); 262 | u = x14 + x13; x15 ^= u<<18 | u>>>(32-18); 263 | } 264 | 265 | B[bout++] = tmp[0] = (x0 + j0) | 0; 266 | B[bout++] = tmp[1] = (x1 + j1) | 0; 267 | B[bout++] = tmp[2] = (x2 + j2) | 0; 268 | B[bout++] = tmp[3] = (x3 + j3) | 0; 269 | B[bout++] = tmp[4] = (x4 + j4) | 0; 270 | B[bout++] = tmp[5] = (x5 + j5) | 0; 271 | B[bout++] = tmp[6] = (x6 + j6) | 0; 272 | B[bout++] = tmp[7] = (x7 + j7) | 0; 273 | B[bout++] = tmp[8] = (x8 + j8) | 0; 274 | B[bout++] = tmp[9] = (x9 + j9) | 0; 275 | B[bout++] = tmp[10] = (x10 + j10) | 0; 276 | B[bout++] = tmp[11] = (x11 + j11) | 0; 277 | B[bout++] = tmp[12] = (x12 + j12) | 0; 278 | B[bout++] = tmp[13] = (x13 + j13) | 0; 279 | B[bout++] = tmp[14] = (x14 + j14) | 0; 280 | B[bout++] = tmp[15] = (x15 + j15) | 0; 281 | } 282 | 283 | function blockCopy(dst, di, src, si, len) { 284 | while (len--) dst[di++] = src[si++]; 285 | } 286 | 287 | function blockXOR(dst, di, src, si, len) { 288 | while (len--) dst[di++] ^= src[si++]; 289 | } 290 | 291 | function blockMix(tmp, B, bin, bout, r) { 292 | blockCopy(tmp, 0, B, bin + (2*r-1)*16, 16); 293 | for (var i = 0; i < 2*r; i += 2) { 294 | salsaXOR(tmp, B, bin + i*16, bout + i*8); 295 | salsaXOR(tmp, B, bin + i*16 + 16, bout + i*8 + r*16); 296 | } 297 | } 298 | 299 | function integerify(B, bi, r) { 300 | return B[bi+(2*r-1)*16]; 301 | } 302 | 303 | function stringToUTF8Bytes(s) { 304 | var arr = []; 305 | for (var i = 0; i < s.length; i++) { 306 | var c = s.charCodeAt(i); 307 | if (c < 0x80) { 308 | arr.push(c); 309 | } else if (c < 0x800) { 310 | arr.push(0xc0 | c >> 6); 311 | arr.push(0x80 | c & 0x3f); 312 | } else if (c < 0xd800) { 313 | arr.push(0xe0 | c >> 12); 314 | arr.push(0x80 | (c >> 6) & 0x3f); 315 | arr.push(0x80 | c & 0x3f); 316 | } else { 317 | if (i >= s.length - 1) { 318 | throw new Error('invalid string'); 319 | } 320 | i++; // get one more character 321 | c = (c & 0x3ff) << 10; 322 | c |= s.charCodeAt(i) & 0x3ff; 323 | c += 0x10000; 324 | 325 | arr.push(0xf0 | c >> 18); 326 | arr.push(0x80 | (c >> 12) & 0x3f); 327 | arr.push(0x80 | (c >> 6) & 0x3f); 328 | arr.push(0x80 | c & 0x3f); 329 | } 330 | } 331 | return arr; 332 | } 333 | 334 | function bytesToHex(p) { 335 | /** @const */ 336 | var enc = '0123456789abcdef'.split(''); 337 | 338 | var len = p.length, 339 | arr = [], 340 | i = 0; 341 | 342 | for (; i < len; i++) { 343 | arr.push(enc[(p[i]>>>4) & 15]); 344 | arr.push(enc[(p[i]>>>0) & 15]); 345 | } 346 | return arr.join(''); 347 | } 348 | 349 | function bytesToBase64(p) { 350 | /** @const */ 351 | var enc = ('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' + 352 | '0123456789+/').split(''); 353 | 354 | var len = p.length, 355 | arr = [], 356 | i = 0, 357 | a, b, c, t; 358 | 359 | while (i < len) { 360 | a = i < len ? p[i++] : 0; 361 | b = i < len ? p[i++] : 0; 362 | c = i < len ? p[i++] : 0; 363 | t = (a << 16) + (b << 8) + c; 364 | arr.push(enc[(t >>> 3 * 6) & 63]); 365 | arr.push(enc[(t >>> 2 * 6) & 63]); 366 | arr.push(enc[(t >>> 1 * 6) & 63]); 367 | arr.push(enc[(t >>> 0 * 6) & 63]); 368 | } 369 | if (len % 3 > 0) { 370 | arr[arr.length-1] = '='; 371 | if (len % 3 === 1) arr[arr.length-2] = '='; 372 | } 373 | return arr.join(''); 374 | } 375 | 376 | 377 | // Generate key. 378 | 379 | var MAX_UINT = (-1)>>>0, 380 | p = 1; 381 | 382 | if (typeof logN === "object") { 383 | // Called as: scrypt(password, salt, opts, callback) 384 | if (arguments.length > 4) { 385 | throw new Error('scrypt: incorrect number of arguments'); 386 | } 387 | 388 | var opts = logN; 389 | 390 | callback = r; 391 | logN = opts.logN; 392 | if (typeof logN === 'undefined') { 393 | if (typeof opts.N !== 'undefined') { 394 | if (opts.N < 2 || opts.N > MAX_UINT) 395 | throw new Error('scrypt: N is out of range'); 396 | 397 | if ((opts.N & (opts.N - 1)) !== 0) 398 | throw new Error('scrypt: N is not a power of 2'); 399 | 400 | logN = Math.log(opts.N) / Math.LN2; 401 | } else { 402 | throw new Error('scrypt: missing N parameter'); 403 | } 404 | } 405 | 406 | // XXX: If opts.p or opts.dkLen is 0, it will be set to the default value 407 | // instead of throwing due to incorrect value. To avoid breaking 408 | // compatibility, this will only be changed in the next major version. 409 | p = opts.p || 1; 410 | r = opts.r; 411 | dkLen = opts.dkLen || 32; 412 | interruptStep = opts.interruptStep || 0; 413 | encoding = opts.encoding; 414 | } 415 | 416 | if (p < 1) 417 | throw new Error('scrypt: invalid p'); 418 | 419 | if (r <= 0) 420 | throw new Error('scrypt: invalid r'); 421 | 422 | if (logN < 1 || logN > 31) 423 | throw new Error('scrypt: logN must be between 1 and 31'); 424 | 425 | 426 | var N = (1<>>0, 427 | XY, V, B, tmp; 428 | 429 | if (r*p >= 1<<30 || r > MAX_UINT/128/p || r > MAX_UINT/256 || N > MAX_UINT/128/r) 430 | throw new Error('scrypt: parameters are too large'); 431 | 432 | // Decode strings. 433 | if (typeof password === 'string') 434 | password = stringToUTF8Bytes(password); 435 | if (typeof salt === 'string') 436 | salt = stringToUTF8Bytes(salt); 437 | 438 | if (typeof Int32Array !== 'undefined') { 439 | //XXX We can use Uint32Array, but Int32Array is faster in Safari. 440 | XY = new Int32Array(64*r); 441 | V = new Int32Array(32*N*r); 442 | tmp = new Int32Array(16); 443 | } else { 444 | XY = []; 445 | V = []; 446 | tmp = new Array(16); 447 | } 448 | B = PBKDF2_HMAC_SHA256_OneIter(password, salt, p*128*r); 449 | 450 | var xi = 0, yi = 32 * r; 451 | 452 | function smixStart(pos) { 453 | for (var i = 0; i < 32*r; i++) { 454 | var j = pos + i*4; 455 | XY[xi+i] = ((B[j+3] & 0xff)<<24) | ((B[j+2] & 0xff)<<16) | 456 | ((B[j+1] & 0xff)<<8) | ((B[j+0] & 0xff)<<0); 457 | } 458 | } 459 | 460 | function smixStep1(start, end) { 461 | for (var i = start; i < end; i += 2) { 462 | blockCopy(V, i*(32*r), XY, xi, 32*r); 463 | blockMix(tmp, XY, xi, yi, r); 464 | 465 | blockCopy(V, (i+1)*(32*r), XY, yi, 32*r); 466 | blockMix(tmp, XY, yi, xi, r); 467 | } 468 | } 469 | 470 | function smixStep2(start, end) { 471 | for (var i = start; i < end; i += 2) { 472 | var j = integerify(XY, xi, r) & (N-1); 473 | blockXOR(XY, xi, V, j*(32*r), 32*r); 474 | blockMix(tmp, XY, xi, yi, r); 475 | 476 | j = integerify(XY, yi, r) & (N-1); 477 | blockXOR(XY, yi, V, j*(32*r), 32*r); 478 | blockMix(tmp, XY, yi, xi, r); 479 | } 480 | } 481 | 482 | function smixFinish(pos) { 483 | for (var i = 0; i < 32*r; i++) { 484 | var j = XY[xi+i]; 485 | B[pos + i*4 + 0] = (j>>>0) & 0xff; 486 | B[pos + i*4 + 1] = (j>>>8) & 0xff; 487 | B[pos + i*4 + 2] = (j>>>16) & 0xff; 488 | B[pos + i*4 + 3] = (j>>>24) & 0xff; 489 | } 490 | } 491 | 492 | var nextTick = (typeof setImmediate !== 'undefined') ? setImmediate : setTimeout; 493 | 494 | function interruptedFor(start, end, step, fn, donefn) { 495 | (function performStep() { 496 | nextTick(function() { 497 | fn(start, start + step < end ? start + step : end); 498 | start += step; 499 | if (start < end) 500 | performStep(); 501 | else 502 | donefn(); 503 | }); 504 | })(); 505 | } 506 | 507 | function getResult(enc) { 508 | var result = PBKDF2_HMAC_SHA256_OneIter(password, B, dkLen); 509 | if (enc === 'base64') 510 | return bytesToBase64(result); 511 | else if (enc === 'hex') 512 | return bytesToHex(result); 513 | else if (enc === 'binary') 514 | return new Uint8Array(result); 515 | else 516 | return result; 517 | } 518 | 519 | // Blocking variant. 520 | function calculateSync() { 521 | for (var i = 0; i < p; i++) { 522 | smixStart(i*128*r); 523 | smixStep1(0, N); 524 | smixStep2(0, N); 525 | smixFinish(i*128*r); 526 | } 527 | callback(getResult(encoding)); 528 | } 529 | 530 | // Async variant. 531 | function calculateAsync(i) { 532 | smixStart(i*128*r); 533 | interruptedFor(0, N, interruptStep*2, smixStep1, function() { 534 | interruptedFor(0, N, interruptStep*2, smixStep2, function () { 535 | smixFinish(i*128*r); 536 | if (i + 1 < p) { 537 | nextTick(function() { calculateAsync(i + 1); }); 538 | } else { 539 | callback(getResult(encoding)); 540 | } 541 | }); 542 | }); 543 | } 544 | 545 | if (typeof interruptStep === 'function') { 546 | // Called as: scrypt(..., callback, [encoding]) 547 | // shifting: scrypt(..., interruptStep, callback, [encoding]) 548 | encoding = callback; 549 | callback = interruptStep; 550 | interruptStep = 1000; 551 | } 552 | 553 | if (interruptStep <= 0) { 554 | calculateSync(); 555 | } else { 556 | calculateAsync(0); 557 | } 558 | } 559 | 560 | if (typeof module !== 'undefined') module.exports = scrypt; 561 | -------------------------------------------------------------------------------- /scrypt-async.min.js: -------------------------------------------------------------------------------- 1 | function scrypt(t,r,n,o,e,f,i,u){"use strict";function s(r){var g=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],w=1779033703,d=3144134277,m=1013904242,A=2773480762,N=1359893119,E=2600822924,b=528734635,I=1541459225,j=new Array(64);function n(r){for(var n=0,t=r.length;64<=t;){var e,o,f,i,u,a=w,s=d,h=m,c=A,p=N,l=E,v=b,y=I;for(o=0;o<16;o++)f=n+4*o,j[o]=(255&r[f])<<24|(255&r[f+1])<<16|(255&r[f+2])<<8|255&r[f+3];for(o=16;o<64;o++)i=((e=j[o-2])>>>17|e<<15)^(e>>>19|e<<13)^e>>>10,u=((e=j[o-15])>>>7|e<<25)^(e>>>18|e<<14)^e>>>3,j[o]=(i+j[o-7]|0)+(u+j[o-16]|0)|0;for(o=0;o<64;o++)i=(((p>>>6|p<<26)^(p>>>11|p<<21)^(p>>>25|p<<7))+(p&l^~p&v)|0)+(y+(g[o]+j[o]|0)|0)|0,u=((a>>>2|a<<30)^(a>>>13|a<<19)^(a>>>22|a<<10))+(a&s^a&h^s&h)|0,y=v,v=l,l=p,p=c+i|0,c=h,h=s,s=a,a=i+u|0;w=w+a|0,d=d+s|0,m=m+h|0,A=A+c|0,N=N+p|0,E=E+l|0,b=b+v|0,I=I+y|0,n+=64,t-=64}}n(r);var t,e=r.length%64,o=r.length/536870912|0,f=r.length<<3,i=e<56?56:120,u=r.slice(r.length-e,r.length);for(u.push(128),t=e+1;t>>24&255),u.push(o>>>16&255),u.push(o>>>8&255),u.push(o>>>0&255),u.push(f>>>24&255),u.push(f>>>16&255),u.push(f>>>8&255),u.push(f>>>0&255),n(u),[w>>>24&255,w>>>16&255,w>>>8&255,w>>>0&255,d>>>24&255,d>>>16&255,d>>>8&255,d>>>0&255,m>>>24&255,m>>>16&255,m>>>8&255,m>>>0&255,A>>>24&255,A>>>16&255,A>>>8&255,A>>>0&255,N>>>24&255,N>>>16&255,N>>>8&255,N>>>0&255,E>>>24&255,E>>>16&255,E>>>8&255,E>>>0&255,b>>>24&255,b>>>16&255,b>>>8&255,b>>>0&255,I>>>24&255,I>>>16&255,I>>>8&255,I>>>0&255]}function a(r,n,t){64>>25)+E)<<9|o>>>23)+x)<<13|o>>>19)+k)<<18|o>>>14,C^=(o=(b^=(o=(z^=(o=(S^=(o=C+b)<<7|o>>>25)+C)<<9|o>>>23)+S)<<13|o>>>19)+z)<<18|o>>>14,T^=(o=(L^=(o=(I^=(o=(B^=(o=T+L)<<7|o>>>25)+T)<<9|o>>>23)+B)<<13|o>>>19)+I)<<18|o>>>14,D^=(o=(U^=(o=(M^=(o=(j^=(o=D+U)<<7|o>>>25)+D)<<9|o>>>23)+j)<<13|o>>>19)+M)<<18|o>>>14,E^=(o=(j^=(o=(I^=(o=(b^=(o=E+j)<<7|o>>>25)+E)<<9|o>>>23)+b)<<13|o>>>19)+I)<<18|o>>>14,C^=(o=(x^=(o=(M^=(o=(L^=(o=C+x)<<7|o>>>25)+C)<<9|o>>>23)+L)<<13|o>>>19)+M)<<18|o>>>14,T^=(o=(S^=(o=(k^=(o=(U^=(o=T+S)<<7|o>>>25)+T)<<9|o>>>23)+U)<<13|o>>>19)+k)<<18|o>>>14,D^=(o=(B^=(o=(z^=(o=(q^=(o=D+B)<<7|o>>>25)+D)<<9|o>>>23)+q)<<13|o>>>19)+z)<<18|o>>>14;n[e++]=r[0]=E+i|0,n[e++]=r[1]=b+u|0,n[e++]=r[2]=I+a|0,n[e++]=r[3]=j+s|0,n[e++]=r[4]=x+h|0,n[e++]=r[5]=C+c|0,n[e++]=r[6]=L+p|0,n[e++]=r[7]=M+l|0,n[e++]=r[8]=k+v|0,n[e++]=r[9]=S+y|0,n[e++]=r[10]=T+g|0,n[e++]=r[11]=U+w|0,n[e++]=r[12]=q+d|0,n[e++]=r[13]=z+m|0,n[e++]=r[14]=B+A|0,n[e++]=r[15]=D+N|0}function c(r,n,t,e,o){for(;o--;)r[n++]=t[e++]}function p(r,n,t,e,o){for(;o--;)r[n++]^=t[e++]}function l(r,n,t,e,o){c(r,0,n,t+16*(2*o-1),16);for(var f=0;f<2*o;f+=2)h(r,n,t+16*f,e+8*f),h(r,n,t+16*f+16,e+8*f+16*o)}function v(r,n,t){return r[n+16*(2*t-1)]}function y(r){for(var n=[],t=0;t>6),n.push(128|63&e);else if(e<55296)n.push(224|e>>12),n.push(128|e>>6&63),n.push(128|63&e);else{if(t>=r.length-1)throw new Error("invalid string");t++,e=(1023&e)<<10,e|=1023&r.charCodeAt(t),e+=65536,n.push(240|e>>18),n.push(128|e>>12&63),n.push(128|e>>6&63),n.push(128|63&e)}}return n}var g=-1>>>0,w=1;if("object"==typeof n){if(4g)throw new Error("scrypt: N is out of range");if(0!=(d.N&d.N-1))throw new Error("scrypt: N is not a power of 2");n=Math.log(d.N)/Math.LN2}w=d.p||1,o=d.r,e=d.dkLen||32,f=d.interruptStep||0,u=d.encoding}if(w<1)throw new Error("scrypt: invalid p");if(o<=0)throw new Error("scrypt: invalid r");if(n<1||31>>0;if(1<<30<=o*w||g/128/w>>0&255,N[r+4*n+1]=t>>>8&255,N[r+4*n+2]=t>>>16&255,N[r+4*n+3]=t>>>24&255}}var k="undefined"!=typeof setImmediate?setImmediate:setTimeout;function S(r,n,t,e,o){!function f(){k(function(){e(r,r+t>>18&63]),o.push(t[n>>>12&63]),o.push(t[n>>>6&63]),o.push(t[n>>>0&63]);return 0>>4&15]),e.push(n[r[o]>>>0&15]);return e.join("")}(n):"binary"===r?new Uint8Array(n):n}"function"==typeof f&&(u=i,i=f,f=1e3),f<=0?function U(){for(var r=0;r 2 | 3 | 4 | 5 | scrypt-async Unit Tests 6 | 7 | 8 | 9 |
10 | 11 | 15 | 16 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /test/unittests.js: -------------------------------------------------------------------------------- 1 | var scrypt = require('../scrypt-async.js'); 2 | var assert = require("assert"); 3 | 4 | var inputs = [ 5 | { 6 | password: 'p', 7 | salt: 's', 8 | logN: 1, 9 | r: 1, 10 | dkLen: 256, 11 | encoding: 'hex', 12 | result: '48b0d2a8a3272611984c50ebd630af52e187db3433930c3b74d0889935944cf3c0c3e055b9388c227467e5d8ad4d4512f3231387514af27bc7d06efda2fcd14154fdde66bef90471324762405572831660175a0fcc3e2d7922caafc962dede1cb3eafbf7043aa3cc0442ff331cd462bca60a2ac5b2952b835d4ee430d1eb796afa5a0bc5a71061fe11210568a39deacb6d831a3a508b323534535dda0ba62f47adfd4b7dca6b13016f85568bc0d99dbec585fa357ff0d1a7764e45d9f128779049cc6212b9c03409ccdc6b6bb501b9000860bbe91acef050cef3d44dd11d9bb0f379e64c3e51e3e30c3a4f2dac935fcbffde07a87669ca90c345aac2812e1979' 13 | }, 14 | { 15 | password: 'p', 16 | salt: 's', 17 | logN: 1, 18 | r: 1, 19 | dkLen: 256, 20 | encoding: 'base64', 21 | result: 'SLDSqKMnJhGYTFDr1jCvUuGH2zQzkww7dNCImTWUTPPAw+BVuTiMInRn5ditTUUS8yMTh1FK8nvH0G79ovzRQVT93ma++QRxMkdiQFVygxZgF1oPzD4teSLKr8li3t4cs+r79wQ6o8wEQv8zHNRivKYKKsWylSuDXU7kMNHreWr6WgvFpxBh/hEhBWijnerLbYMaOlCLMjU0U13aC6YvR639S33KaxMBb4VWi8DZnb7Fhfo1f/DRp3ZORdnxKHeQScxiErnANAnM3GtrtQG5AAhgu+kazvBQzvPUTdEdm7DzeeZMPlHj4ww6Ty2sk1/L/94HqHZpypDDRarCgS4ZeQ==' 22 | }, 23 | { 24 | password: '', 25 | salt: '', 26 | logN: 4, 27 | r: 1, 28 | dkLen: 256, 29 | encoding: 'hex', 30 | result: '77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906ce73206656cf8c1ead7f4f6630d0adae1fd8878b77c3b469db919f01597f613ac2f78aec5a5c67c255833119eb3e66b6977e6e7e32e0857b796dfbbc27e3e076e575c55f661563432d4452427d8a21a4bfc0f4f79532181d011ecbd9f210e301b925e82cadbaec015d2da4b1122f51eb2d79f22e28b7e1204a15e741febf9b94526d57e7277d7aa12e9ac8a58fd4c42f6922470156cbd279ec1619c574d45c4177286322803c6046d8b14c1f6c56b6e2e22d077e0a3174ba9d765a84f52b11cd' 31 | }, 32 | { 33 | password: '', 34 | salt: '', 35 | logN: 4, 36 | r: 1, 37 | dkLen: 256, 38 | encoding: 'base64', 39 | result: 'd9ZXYjhleyA7GcpCwYoEl/FrSETjB0ro39/6P+3iFEL80Aad7QlI+DJqdToPyB8X6NPg+y4NNijPNeIMONGJBs5zIGZWz4werX9PZjDQra4f2IeLd8O0aduRnwFZf2E6wveK7FpcZ8JVgzEZ6z5mtpd+bn4y4IV7eW37vCfj4HbldcVfZhVjQy1EUkJ9iiGkv8D095UyGB0BHsvZ8hDjAbkl6CytuuwBXS2ksRIvUestefIuKLfhIEoV50H+v5uUUm1X5yd9eqEumsilj9TEL2kiRwFWy9J57BYZxXTUXEF3KGMigDxgRtixTB9sVrbi4i0HfgoxdLqddlqE9SsRzQ==' 40 | }, 41 | { 42 | password: 'пароль', 43 | salt: 'соль', 44 | logN: 4, 45 | r: 8, 46 | dkLen: 32, 47 | encoding: 'hex', 48 | result: '1385c1eecf16becb6114369c199298d10145df3082d6993966f2609901b509e4' 49 | }, 50 | { 51 | password: '密码', 52 | salt: '盐', 53 | logN: 5, 54 | r: 8, 55 | dkLen: 16, 56 | encoding: 'base64', 57 | result: 'FYjFuH0fb+qfG0Q0n5WFVQ==' 58 | }, 59 | { 60 | password: '☺☻☹ abc 𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡', 61 | salt: [1, 2, 3], 62 | logN: 10, 63 | r: 8, 64 | dkLen: 10, 65 | encoding: 'hex', 66 | result: 'd64f593e6c4e7a39913d' 67 | }, 68 | { 69 | password: [104, 101, 108, 108, 111], // "hello" 70 | salt: [208, 188, 208, 184, 209, 128], // "мир" 71 | logN: 4, 72 | r: 4, 73 | dkLen: 8193, 74 | encoding: 'base64', 75 | result: 'uimV3p4s/wwh/D5tj05ZTKGfEguL8b9IPvlO2Q46ekstUchMqYgY7NoPJOdIJAE7Y0KCjSHOcYPzvDK'+ 76 | 'Tsk5fwOLMT4zDSypSDftB3xgcym2y0LL8mgloDHzcYdJTUa8AVKkRQR8XWZLzg49RP8LxbRa+5P2oaNm'+ 77 | 'ocM2wc5Iafj3CiYuFI9Z1dX0jFtCSUHJ+0nrKl4ocjl37jJDe2F8ttfAYxnMB6DEolP31ATEBiEaIYoY'+ 78 | 'd3BZJMBSbBaYn4XuRtdRzpGuPlOwfNfFeUljDHAAMo0cW6VapttzWdLvt+Hb5F3Qw86KFMsD+wSPC4BW'+ 79 | 'CeWduPb775kYCk6yQO8QvMQBWbXuxd/a9kz0xjWRmXBLmhDfq/PQLU9XeWGroncYtTO0YPszSKONFLQ6'+ 80 | 'jkrjzWUmavS3t1KdpEBGymeLgWZ4AKQA3nKd+4bd0x96BW1W9grWhE2pmnP8euCfNbA4e2mRl+MSMwqG'+ 81 | 'vXeRq91HTKzgaWLDBOQlNdP/D3tN7TtydP5YrJCkWdEgbf8V64WoTDn7ukhNMacS6hjNxV1JpR50OLzC'+ 82 | 'lcIRqLctd9isoL7ayWWuRBEOEPi9ddJast1gOZ7QT7AeKSW/bBZ81P99WQ/NM0VG0tBJJHFPQK+Bqgpg'+ 83 | 'QvoGHzz6BH2J67dvXfLr5K8rslTrniI5ZuhYVMeLyJXQIBpDavrdY9gHJYRyHT5fmAzIiL5lOru8c4l1'+ 84 | 'zWp70QrEOcaFOH4mW+h4FUpr3kfr6St1o2P1iLwQ9dwUYYMUQkOtTidF5oR8X82+Bnwv/hf7W1B9wO7x'+ 85 | 'C22+FQf5Allj1Om7MRzetXhbmSMHK+0wORPT3Tb7gmJkl8J4Shq95No4Vwg2FpceIzkJ9g5H3dQ1THo2'+ 86 | '1BH21fWSm622eZAEJQkm4glDLmq31x2vreZ0v+5RfYQKUgOEiVc/BOGxypSjdYonLifkDoX15xd0V/ch'+ 87 | '36tt6+5KohjMUUlmW5qEbxiIoJ3ShIB9iMijQGeR2N5uqPgyYxqxd4vhwVEBxwCtwKBltKuixvjomhft'+ 88 | 'OhGDZwtp+Xz6WSLL94bI3whHvA9F757LOW9RQWmMH00QM+8oRJANUqI8izUc7it65nrzTOZ3pnIWAN8Z'+ 89 | 'dvKUbcLYi+8Q57Q+sQDAAB9npRiyNSuUTUqndelJ4NF0Rn75vLPaT9I3EBRcHuiISCkF2McaSihgYPNh'+ 90 | 'lYrboQ4bAk6EH5QALLTCUHdDCQWFqL+ySLc/i/CA4SEcFcfK5fQRec9IKUN2WXxm6y+TgKaNaNKJMPAD'+ 91 | '3YtcoJa4Ql59UKpJKsfTrue6FdSjPmWcR/zOozkMUjkDISjkXm3FFti5CEYHSHoi1ZeXTLbP4ovXed1w'+ 92 | 'ev2lYZIKyL0h+j0hG9RS3EMcKvUERvrCHrVyyxqQQGK4gleEQHPs7tl/oZqZzx82rDa1teAty6HlbNX5'+ 93 | 'lN+uG6B1QJ5CXv9JEeDwcER5sLH9bZ1iCPirlMPUGnZ9iwKxgrFIWRG+Dc/4kl4Xsc6RWcPJCNtTYKrD'+ 94 | 'w3uRxcB8Q5IX+3jDPyiMXuTprMBA0/8yExcnG/zEzeCiwkgeGWyKL7QCMn291hklFxDU76Vw+wgkr5f5'+ 95 | 'tXfyr4jjjT4DS6NxVWFF4UEQsrii1J2dzcmOOg4slZhwfU39ewl4KsYHBqhSXSLyy0JHRb7OGGkCR10T'+ 96 | 'sg3/7rz9THHydoL0i3aVPrAeswNhM8nTKTLifLUdee2TqXVf1Pq09537sqxNd+Y8MTJisPUs8j/BSEiW'+ 97 | 'nxGaKCBz3drkgiGFo1wviSDE41MUDTmbF3HNTu7zgDgt5ZH4Q1ThzbMxwEvjdr+OsH/twnMnitUJ4eFT'+ 98 | '4H1E7PxgbHR6m6MdJJfmvQ3gLEAEc18csdrysS6R/nL68Z5UFBI8b0Iz7nyXr/f3TuQlrQtU8DxmTLDY'+ 99 | 'HFHsdMPEgGHvUaLzOpiwkRHJT6ERc3eiVQ0vh7BY35qbponzM3TNoR5aQoW7bMX4AMhy+h+6uWYJrVkX'+ 100 | 'EH5aeAyoZye57wOJNqyvDrrTEHD6jrye3HOkr1Hd0EP1WCpYLmvpV1kFGElPRGpCeBjoWFidQaKZEp11'+ 101 | 'oRkyIb1rJu/V1Besql7N5SKAC6DMrOm4UPg2gBJLYy0O856NWx9L0WBqPgFI++bXu24rMQPDJz3/deWx'+ 102 | '0Drfe4llOS1hQW+9/j21n5bR41+nd3+VoXKnUti+dirwuqMR36b1CQ+zHU68XcSWinoiYwTEatBIURQP'+ 103 | 'UeccY0U0eoGHuRSEKTHWstDX8L3TXHt+LMoKmDQVmLwYitWd9nq6I0OTHth0LbSDE2exGQI+cMWeqUH0'+ 104 | '6tp3AdJIKjnRU6BGcOqF0sPiPAvVpVykpoJskCs/zj0+T/TxRPJeFJZNGpbr7hyL9+cLDwD4LeV6dRtE'+ 105 | 'MB2EEoVS3VxOA7hMY/w0Z8JkLMqKT8+pvAGmw0HKE3uHfV9xFVkAfoJFVui54tsJkneVOuvmd9MRIGqr'+ 106 | 'DxOgQ6IDIUyKaneCNE8iWzE8BvBIHgB1pHdCApCMBcXkXGM/eSScYP2zrZ6sziofN1hAJscQAQFtvt28'+ 107 | 'WLbty+jBB2qBrcZbuBt48jYnj9AhzjnNnRRE79AV9pvUagWV+GuMRel29+SbY1pMiD1Gxajex4O6C3Jb'+ 108 | 'u4hUYLaojPJQi3KOJ7/j4Av2yV0Wc5H3O7lfzkLSz034mV0+uT8wgzHO0Z/w4Llaf5NylJSNhZm/NkXW'+ 109 | 'nwaxdDXUOkjKlj93/34c2D+uKPMMuNzPBEATsG00k8gahzzfrM6pqaqf1J5jRm4mA7pKc9Ljza0tNo/9'+ 110 | '1Qn9acMIipPY4/InohnbXRPkO68Rmfa5XTG/qCsb94clFk1AZHwi8veCBNwTLAaX6xx/QCMZEhfM7fjf'+ 111 | 'FBxLZ22iW92LBKM2ImFao10AKTjWbXdRjuUWYFbwFi0mvcwbBpv0jhdSZdr4rXyFYUqvwunJdm/ARIp1'+ 112 | '204v0AuOi7q1XvMnfpiKbN0IigP8+RX+phwK5yKp+alEZcrvpuBLWjKI5hToLbJ7LrIyqF+Kvp1MwdBT'+ 113 | 'GZXwq+P2gwgE96Sj7i5vNkRhYacWQCkwIrWK+e4BRslV+EK0y+E5atCAjc5VWW86VahQS5C3wu50b+OY'+ 114 | '00fhPsZ056/W+bcPHQbFO3fLEgUHOeLygS11jisk1ftSRcXMw9TIjM1Y9rzMw18ybRUUUq4oBD9YcMZX'+ 115 | 'rjLfI20RZGCwv5a2OmBD4XcMC1YZy9448ZNNypWPNjd6rMwz9zHq1csltGOmtYKkoU32xN9V74ETJPiE'+ 116 | 'L/xxfzULutrb9PHMH6+/PUefCngykAQBUqrqZfqpadlvQiifrl++hKL6d7vWgQ7sYDAOLwd8397+SDbw'+ 117 | 'j0AW+lj/R8Hnq5fdWSAdOUN0OjeMHZ6Pn1ViAZt1y/sLiYDgdKj/9UfCQ7c6K9cC15Tm9qSsQ32RIw4C'+ 118 | 'MCWd+4/B7XGG6RbssM8Z6Z5mqp2zirR90S4/AVQy8uQ7tArL/4DimhXrptsCBCAQEWihQS+ciMiQzv4D'+ 119 | 'pTABNupschbJJ2CHE7R9AisKg6H2vGkzwohewUHGGKxLEN7eEn6myBDa6bQmhWZECVpcXx7dp3mJzGs+'+ 120 | 'gLyGzhjpbl6H0GQLdj6Iv2A97Urka+ey1TRpIwh35842ggiv5ay30TBaSepf/DNamcazj1gxHf5n/T7b'+ 121 | 'p2YugSIV4hM8Cn3priJcUfGPXDzkls8CdRfFmtZIIiIRUECBl7FyB03szYWhhJslLeAfLnFlsPgXeaJH'+ 122 | 'abTndT1RYr+Mhubh24lwlGdQnShhIDAsexSNK73bmRYJC0qRtw2+3RNRBKxYELPZQF05R9BlzdYhmYtD'+ 123 | '4xryr8c07f/+aMk1+wM/zULjgAk9BV7tjc2Fyi+loBOHDVYjLWaPuaulCrVnkxgQ5YCqWuLul5up/GIG'+ 124 | 'Lv6wZcZhd2dF6ZaR5uzu1O4K1pnUn7e9PcgsOtl1JpbsH142M6J4X2fP98wb/oVcaN04ZoTh2FBD6pPb'+ 125 | 'ExlJKcgwXbeUOm6u/nuvhNwZYd3b55HNDG3IBk97X0odHW/1R04zRifRfsKMcV55xU6/SN5McTEu6z7Z'+ 126 | 'TRaSYQGWsklcI/MwgvICeWXEh6esV5AkDwVMuLGxVUDk7R+RVVlYfGaSyDa2X5fiPMpsBfeqEhIZd8SU'+ 127 | '63uGonqHRE8COZI/ima2ronbBt+r92NomElAn8VVWGm99IBjEJsGiWEiFrh6xTv8fK1in11S9+zGqgrv'+ 128 | 'ahaswduzYjhhpJjbjnSzod2Kg8VYwa4hH6prc5puB7VhDM6QiQqZzvlU1OcMiFafnduWmoCS2mIo2doK'+ 129 | 'vO11LtgyZwhBSv6QWSs1EtaGSs57xyubJIGpQ7RfQNbJLj5ErTmhVKdYRdEIWyWQ6VoXunwP3edH7EbO'+ 130 | 'nr2/IRBMxsD0KQjNiQv/JMzyoVKgIWi8Ad/Pv8ADZcb0ft6GJKWNizdUiYg8LR+XjxdXOUJShExMoNZm'+ 131 | 'oMUb+wu99dvQ4YZjyS5Kmebf282Z2VFAHDY8AuYklV0fk5sqfdJthx+to1gu893FaGShLXvkTUM8k5HR'+ 132 | '2cqZuNyoWPksHF8AQHqum3Gu/sV/MaJD2Ijva32W+cJ9zwC0Q8zDmu/A1RbON1+hdpcpkifJncmVFf4p'+ 133 | 'pDPqsCwABOCcxnCnjM4bhGO8nk71geVDnZJ9Z+S+x/fXW67wOst1SEAZab5049ON9b9aCjO40Xsb2haP'+ 134 | '2Ru2ztw9JoBfqE/bC6/122Zmgkg1Fy95nEWyTOczl/bjZmOLHmyefE2ho0nU8y26QF/GN4IctkUHER+I'+ 135 | 'fnqVNROTjYmm/OF9jhVPhgscx4mC7D8fL0ktF8xY7wqPR5LJoBm1Da7vHDXXcJzBHf1T28SVw453xlQS'+ 136 | 's90uanDZP0Ga0FLGPcOGpinIgSl6GJOV4iAriir57Y1FuMmj76xAg+9YrdGgOZdC8QSirg4hht2OJnFy'+ 137 | 'x1ksFgG6Cjl5patN9/i0HURZXT/cpvjTQbjmy3m/19OPTuuyx4vHek0QBCjUo8Y+qiIwLDcIvFletQIL'+ 138 | 'W5XIlDs6jjriMJrxcqvMzlOd3aIhpL/yTgnqkWCy2HEDFHe6yTvxnDZs+SENZKwxIfn2srDXLWPEqxA0'+ 139 | 'wPDjfT17MTXhhog0Tu9uU8cFmEWYyj+jjn2Z/L/KBsca6mpu6iUSDiSZbIjyzvlVt26MLd5kcwOafq0C'+ 140 | 'vjGl1p2eGUUACWxmpwpFa/IF3c1nimUGv+0wapypkCgFd7ZHRKradicQIrgdK46k3GuZVhEUuJtC+cBs'+ 141 | 'pA8BeoDx47+eTfbNpHPKe06RlmAfD/VeldV9EgTKW2WN60tVo2GLNoFoOJF0XXDtDFgNzjBDdR39ACEG'+ 142 | 'VbYM+Zo5y6fNnMizY0D4tKNGRs3IFEhT2MgE3Dk67/yhc1Wk2OzTQbOVD8djlxGj8U+T8Wpaf6lqSRu1'+ 143 | 'Xxcp3upCqK4M8p9Jv2GsskfQcVvZ0k71AWBG3DlHhXtreSbSAoXlQ2bD86d6xHNllD9A4VacbzqC0FjC'+ 144 | 'hELonHlCGq+3gpwFfsZwTVceWMqDi48He2doVEmDHaNjOwPka7A/o4OqClnsLc2YUU+coPU4QMtgxD8/'+ 145 | '5SkmSODyzIqkR6XLpsmtDRttVl/JCGPKx4ylBqjyrf6nBtNaxL6/mZE4BuAg4s0HxVKNKw7dbZLRbKRs'+ 146 | 'y9btNEii3SMIFoWoIcdwuRLcyx/PnVnHmE+CgCSqCsLBSCVncuF6gtDxlL8pY4Qx6b1oG715cQ8DxlRD'+ 147 | 'w9WPk+14rRY0iG+on1vA6FCSqenFhI6PSHZtxZmbvLE2i+igPNwqIvUcGhK3H7cpF4QU7i71o+vsn9Q/'+ 148 | 'viKZN4RD7lbjUifSrjuewjLij4s/NX1zApXHvJ1SoRTKUAYVxWVK05UGn4bTGy/yr7VrrtfbgrMLoMla'+ 149 | 'D4ZYFXuInorvmwUtRYV2lGCv7Ahc/W9ybvwfvIQabwrATRCKUxfin/DezjXXhyYApvlKYkr0GQev2BBB'+ 150 | 'QquPNTav4OmorLq7LoXfKoWAGXf/LNEBx484YdIOt3nKEgsDiOoj7fN7fOG0/pKwBfnnwWJ9j2iBKUNy'+ 151 | '5t/3nJQ0g1oRUtDxEOvqharOaFknXtB8tptDc8rCSIsH7cixdu6oWO7qP5VC6cyEFjM/Lyu0nrrBoC0U'+ 152 | 'rdKhmVc6wqcjYEuO43nIv2on6EZfC9tpaXCxDJYXaWV2RKuJVDkwpafz26wTP5Bjuu6FW6xKbKTMfHGZ'+ 153 | 'xvFHyXtUTm3MRZCBchSuK0A9R/REkvwVjalFIxi7CzHDZedjwgtoj1RH5XlSc8qaU+9vWG1k+rbrFFEO'+ 154 | 'oZ1AjmMkE1r35K3hsTI4GZhTPjkg0pge1FgGKHMwcXR0vSZYxOPF/F7n0WFdHwEfqne2HFkHRfWt+3qE'+ 155 | 'cGvPPB+xtnA44rVC/YipWktw+W9+1BaKhExcxlOrmTmUmoD/Gy5jmQrnBFoxo0xbOJ+iQ2suiEk+gXQD'+ 156 | 'N8T9ZSwjAgkj+dHrSIXRHgCJ3wG+5IsV+42yL5UlqMOvwp3E7xg3dub6Gk+Npw8TTCP7GDbY/Tr5RujI'+ 157 | 'Gy0C1sMuETizjvMO/fTTASqjfd/brgPGppiz6zdRgcOHu6PEYj/6DFmRKMzJGG2F7h9Ct/i7p8rT87FS'+ 158 | 'ONTpDZqBXW8f+pIrIeLKQ6NSkPPacePGd7Zs2jwkUDL3Zb4A04odT2htMRJiARTZFLBHMIcNlybtXLpS'+ 159 | 'l+M0VTXtP1JIhwVKHdFelzOjPHlVMb87C9Vi4ixnOXkvwL65MCL1XOLj0Muy8LHoIStOAsG8VjYbVnhf'+ 160 | 'WEkqQ4JUiR+MLI3AO6YIvXZ1xGRhWmdQtZfQe/9fTS/o/WBmNFe8tQn91m0NK1vVbV+VNVtiMPLJvTCi'+ 161 | 'srMgH4NxKBgfKbtntLtsmMX0egpZAJ667gho/0gTWn2WDAyaxVJegoUv8dVwFAe4MOP7BQW7LQYTs+HD'+ 162 | '55qJthoEUK7YHG+1dlKb6qCEj+tEOAAnZsXvdogOwwXfWrgVI/9+FcBJlrzYtGdHrZP9JXsfQgiChCAa'+ 163 | 'muln3diMzVxhFyTTTJpvVddF6AdxJlD8yJXB6NcpPwtHLSh4aWgq/jVY3/OGSFZ42G5xjfuknUC94krB'+ 164 | 'F1TGcNJjotjcWuybwTbef2uwsfnHyQ3iU+irch990Y6MjVSJUeSfJ/9FmXSCZOzLMJVRmXaENWaIfdkN'+ 165 | 'xl6fr5Y4++KTnSIAbOIpJv7g5gALdRQoBSxbAPr0RobCR8vXodZrv74W12qjJ+GXc3WO884r7cxb6yg3'+ 166 | 'tMusX55ePdDtpEibZ7X4a5bjjJ/k4mWPr7FJTFTVYMXS3gfq1sOU7QA95Tq/evrvs5Ola+lzg7apEbGP'+ 167 | 'FbuxWxZhWhrXEL39jGwFhKTiYW487vgX7lfR4NFAbFlqN2LW3a9etE2f+vjRu1EjQWu/MWb5A+bjD3tL'+ 168 | 'FEYgaDfrqcYPmJ5FCipMhS9f9Tc31+HP+b6tL9NVDMTL/3sFPj37FW7wjR+zVBq6LddQF3Kx1sR5Yjyu'+ 169 | '/XZYYJNU8TriQ2JFffZKSEMGh5qpok+lXkWYOefOBp/tCO+/kTrIdBTRbnpqP0r0HLVezQcFkx4B1VE8'+ 170 | 'T+3muYi4zEqr50iKld0tQCP/WJpKwmPOg/4LVX4lERMzRtsp2Ui1TUt84o0VFSeN8zRDn6SW7y3Nr8JU'+ 171 | '/KpaRrBfuif8WCWgvyV7pqfFdEjvcMDCCCEgGBEA1CzQQ64fFDkwVPz8hTm4N/o2Il3KJWendfSkJ0v1'+ 172 | 'sB3Ak4QOyWh0LNVjCjwoztzOX8jzpKNjHbNPGzRAtvsg9/Gt1MJLmxoHSnXaIu/cnF4yzcy907B7BN/e'+ 173 | 'kDAnSlL7uGO7K5GV6Ud0Mpp6CcPEnrjAJxPT1rSMRAFk9to0U/QhGOXxkXbA1LHTVqOciznqPc4DfVXs'+ 174 | '4m/ODw6Ezrjj8iFr8VWuU6AuI9J4g0zAaQyKjZOhUKRlzXJ27lkmmPdZo1Xoo1M/4voiNMYpZQT2P474'+ 175 | 'f/dkKvQVC817kHRiAazJLvotVXTdzFcXd1e3h2EN+n6vSxxR2fYNNdEwZM0LwvAgbgPLEWSW3Wb/tQ33'+ 176 | 'hB5LxUqUIbEb6ayktHZt0gLh4CMxvhNmtK0yynPbAEUjsrNR27+ZsAM0FaITL3qBTYFvPjI2aoiGq9eQ'+ 177 | 'KiHCOM3R9Zb5KqpkUH/jvP+lzzZR1OlL7d5N2gvMp7NhAs/gJJvRqx7a9TIduZoVeopuLDsCcOMnDm5A'+ 178 | 'A1GZn7Xp3N9BgD8gTPbV1AgPkjx4ViThFIntlqIJ2o/02jPJlZcDiEB4Dr3Scp/NNlTtW6bt2lyRVdVS'+ 179 | 'MEj10WVMeD72+WECuROEOsPv402G3ebwzpeFaPw5+Gp8A9yjzgF4z8DLgYXppirrMEEwOd5bOA6UXGx5'+ 180 | 'vl+mCu3+eVss2XWaQ62hc9dB4VDC9p9f+uj1+QpJHlI/6eHB64Ve8TIUkx4E/0b+KI2HyLD2IgQZfi81'+ 181 | 'jTZylOlTidbkHgYXn5sG687TPYTJ4gelt0tkt36alchDYhFCW1uSNOWeVfiocZ99dVjeDmrZ7Bw3eC/1'+ 182 | 'nRBQ3elI9eZZy+lWqVhJIN+Av9el2/dgJ8Xy/ISDwOOVV82edpm5x9OOqULvIT9eA41nQ/r/SnbJKlqW'+ 183 | 'P/0nV4f3ngmXiRiMjwIn/+rTU9xP0gYfPoieqW0SI6mmo4DZBZlh2cHBtUpCSN9WxeTeqPNpjSPLkJaC'+ 184 | 'YsWcGRyhcDhxAsmpnZuCj/lVBazxe6L5NZMPMaeLmZj7MWTotg5Huhx8SJ4jIUX2yq3CbUW0NxKA8ea3'+ 185 | 'NPBdBWUmmM8Tk9TZ187DzCUM3ngI1ozCo9wqWTEQ+s+nFkkfG17Q+d8+EHeNnDmewmO83qpRdlFCVG5n'+ 186 | 'hqpkfu7gep5sJQz0X93clVEsH2GaRRWW2zmsxeXmsN98LqOMhypgzd1BX+AwCcxj/06S5BBmG79vb6FD'+ 187 | 'mNI78Sg0ZxPgaPp5nruEpaNnHlbCv87OR0RiYB2oX+oUt4hzBLDimBOwWaiTfe3eaUX8BXdGMFKAlnTf'+ 188 | 'SCVT03ASw/tidsikfbbffK4yn///5AYqE7Ru9t4bP99VYapehpkLRGeRDIUJePXg4UDSfCLntSjNKLlX'+ 189 | 'XMcW1Yt5IYe3daQqygvm0zLHUb4KMBpqolso5xsg3mHvmbi6FCgjr0BZQTwkQL7KzdX81C+zH9XheYGB'+ 190 | 'ctNwKwYrYVnbDTyBdx8NpLOfYYPCVds4pr0DrWi2pnSAiWV0zkUKNewoU9vjcGkWcuS/UktL1dIbCw4X'+ 191 | 'ly1qn1aqa4c3Kb7Hq7uwDF4mCe0xJQ27ZOqUWWJABGKns7ptF1EkX2KC0TTBb3mAP7f8yI4H3i9gcYDC'+ 192 | '3NYuoAfNv7ADuwRakX5FqGQfVKWaRKEJ/ZoRrF63iWFWYKYIgKXKe2g3pDk4o0hGJVhg2iNIPgAjJkzr'+ 193 | 'vQ/jC/ZqeOpOcX0eGOVikJmJ9XOoswfPWxvJ8QdRp0gRjrLc8ql55sO+e3qaPT9uE4k/29KD9qAHTcSD'+ 194 | '8FizlwWv3GvM91E5UOLfVM7rTet3a5DXpYsTXLA80eoGwtFRpcqMpLYlAkbeaXFV0eIrHnXU3kWIwAjW'+ 195 | 'A4tS6nsza+a55qkz90ka4gV6MCFpan911IA86RpOYA8FY/zjW8uwN4fDo+WhIsFDqELgUdU2u6vGKrJ7'+ 196 | 'Sg/A++VfjkEj2ApeASkPa/V6rum8WseitVJ8z+CEYQe5gx5se1YTlryjMpKu/rRCNCv52awz2xgqMOY2'+ 197 | 'tEn/tYFXqAHaxRWLr7IYg9kIpU2Qs3wbxP7Uj8pyO886W/KHLlGV0CVX5/w+a8zeOzZ06I7XE+rQidIa'+ 198 | 'hmrrNp6xCwJDSXMcpKiBu/EtgEYFEfRC7SxXJVr2pcpo4JPmGKMvCQIByqvtFp6ccmm+PPxeTMD3ebkO'+ 199 | 'HBSKwhF45FC/FcDAExx0L89tFLG9/N8+xi9fQK1tr4OmX9UeQZ5hOuAw22wouhj1cxjXqEVr4Rwe3lDk'+ 200 | 'R6AFyfyHnTBSR+socjmNej5egM8OHYRuGWbTMH7hZ51bgpR8rZmm9TLxa0uFG2+Wdvb2ZYzXmccs9wgO'+ 201 | 'JWqOzrqwZpDB1cVB4lEVO7HY7RlqTHo+r7K5bEwTccSKzQgRrGSAUlc2aK2I4k21yP+BX1x/pYEu69J+'+ 202 | 'sX9/sAWoDLNTSA61o81Pzmnr9aDQYCipV7X2/da0idrZy7W5GwSBKPnATcO8NKRJny0N2aN6vlFJ1HHK'+ 203 | 'mL8QaPL/eZuPim3QgTAslq9llqO8H87DtPJQclpzbb0UQHhEpbrHOXEnS85Bg23EfCmsREXtnL3Eey7z'+ 204 | '2Pk1iB1B+o3dmV6n9u16xutRV5V/9UAYiehivi6sQWBQlHzAIBFZtxBIRkx5jGA8zsvleurlhQTmGSgI'+ 205 | '+gfFJNIU2FvDzm2cSSoAxiw1v2fZ7uYdifePvrIW1YeRzcArOiRigavSi7MLNjO1Hhf4F6v7ixjn9DB6'+ 206 | 'Z/yk5P+SEUQPk9QfqdvnVOghxwvzNvHGibVYYFKJMBr4SUf3+dXYrpJ175dGTcbZ0HOSl7J/6U4k/gdD'+ 207 | 'LuDZwHPXoSrkVdwG2xdSKKVzBCQqdEjn9cWskt2Ft3cSpiYurpM3II/luklLHVr1XHtcMqJQZijJQQ4f'+ 208 | 'DyJ97SaFd2uTYvU5Ltr12uaV9DoJK2CupY+Z5k+V9uO87FzyfdgijHpOZHkJl0j1VrwNXMCU9T7KChIN'+ 209 | 'OhW8rx9L9XSPXTrMAm+Yk1+Vhe0RSlOWg/ZP6RDCV2UAa8uxlpJdgtnas9ndc9f6cSXRhrLiaqI/tHd2'+ 210 | 'KokyJqiJbRow0/Kd14J9CnjDJB3PrGKtDjcwwyhNNmu1cH8jgK12JKIjbIXXSylH0WgIMfr1xz9Otvku'+ 211 | '67WElrWTYkas4lOMKyJtLfJOOG7Tzqqbhw7GLQ4OgSGhu' 212 | }, 213 | { 214 | password: 'this is a very long string, which should be pre-hashed by PBKDF2 as it exceeds block size', 215 | salt: 'some salt', 216 | logN: 4, 217 | r: 4, 218 | dkLen: 16, 219 | encoding: 'hex', 220 | result: '518a355ac6468a4d98708adf03577df6' 221 | }, 222 | { 223 | password: 'hello', 224 | salt: 'world', 225 | logN: 5, 226 | r: 8, 227 | dkLen: 48, 228 | encoding: null, 229 | result: [212, 108, 63, 108, 230, 193, 1, 5, 181, 168, 169, 234, 8, 53, 241, 230 | 76, 44, 108, 85, 218, 223, 158, 113, 64, 94, 114, 7, 160, 1, 160, 174, 231 | 43, 11, 22, 144, 102, 217, 198, 114, 226, 91, 245, 240, 80, 28, 210, 107, 232 | 239] 233 | }, 234 | { 235 | password: 'pleaseletmein', 236 | salt: 'SodiumChloride', 237 | logN: 14, 238 | r: 8, 239 | dkLen: 256, 240 | encoding: 'hex', 241 | result: '7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887c3b5417f26036e90e9c1fe355d24ee3623c8b8bad9b9aa93286c6429dbc0bfa2e69326c0806f7dc5f825a6b9cc32d18483a117c1ea78e2f38675579c811c0b67c262dbab7fe2b6d989d07fac3443c859cf7b34fed8cc5b279f7bdbf6e0cd8d90a82fe56f3ac7a5b81f98275c9c5cb69f19c8bddc33db6bd7da847ec3197e13f33f70b00a46836b7c0a0379559160ef42c8332097f7ca265fe6ff972ce1ffb515ff7e4e715e4c92839113ea67f2515f311549fc7eee49804136fb0830abb943d3' 242 | }, 243 | { 244 | password: 'this is a long \x00 password', 245 | salt: 'and this is a long \x00 salt', 246 | logN: 14, 247 | r: 8, 248 | dkLen: 256, 249 | encoding: 'hex', 250 | result: 'c3f182ee2dec846e70a6942fb529985a3a09765ef04c612923b17f18555a37076deb2b9830d69de5492651e4506ae5776d96d40f67aaee37e1777b8ad5c3111432bb3b6f7e1264401879e641aea2bd0a21a124fd5c1ece0891338d2c44ba312e497bd93660fc053a5df35ade0ca48fd0f3c6c0f6143bb3548420a7cbf6ce7c82bc6b56c8e33adbf6fbac9e0ffc4aa9fb9fcd97fd393700b7d8eac55d45d4651bdb1a270c35c8d40a22e1b2429d6521c4c673e4ba7e7f4a9638ec3b1adbc6dcab64e211b5a26df8f274511be41228cd9a4fae3ada5236ebf39dfc6cd1864652a16516fb622502205d9fdbf09dc6fa964b57cc468ee8d98e4a00bf064222dafec8' 251 | }, 252 | ]; 253 | 254 | if (typeof Uint8Array !== 'undefined') { 255 | inputs.push({ 256 | password: new Uint8Array(65), 257 | salt: 'salt', 258 | logN: 1, 259 | r: 1, 260 | dkLen: 32, 261 | encoding: 'binary', 262 | result: [236, 122, 177, 168, 83, 62, 253, 45, 27, 145, 154, 151, 66, 174, 56, 101, 91, 130, 207, 52, 20, 52, 161, 66, 241, 202, 39, 120, 158, 73, 124, 69] 263 | }); 264 | } 265 | 266 | var shortInput = { 267 | password: 'password', 268 | salt: 'salt', 269 | logN: 1, 270 | r: 1, 271 | dkLen: 16, 272 | hexResult: '6d1bb878eee9ce4a7b77d7a44103574d', 273 | result: [109, 27, 184, 120, 238, 233, 206, 74, 123, 119, 215, 164, 65, 3, 87, 77] 274 | }; 275 | 276 | 277 | var inputsWithP = [ 278 | { 279 | password: 'password', 280 | salt: 'salt', 281 | N: 2, 282 | r: 10, 283 | p: 10, 284 | result: [0x48, 0x2c, 0x85, 0x8e, 0x22, 0x90, 0x55, 0xe6, 0x2f, 285 | 0x41, 0xe0, 0xec, 0x81, 0x9a, 0x5e, 0xe1, 0x8b, 0xdb, 286 | 0x87, 0x25, 0x1a, 0x53, 0x4f, 0x75, 0xac, 0xd9, 0x5a, 287 | 0xc5, 0xe5, 0xa, 0xa1, 0x5f] 288 | }, 289 | { 290 | password: "password", 291 | salt: "salt", 292 | N: 16, 293 | r: 100, 294 | p: 100, 295 | result: [ 296 | 0x88, 0xbd, 0x5e, 0xdb, 0x52, 0xd1, 0xdd, 0x0, 0x18, 297 | 0x87, 0x72, 0xad, 0x36, 0x17, 0x12, 0x90, 0x22, 0x4e, 298 | 0x74, 0x82, 0x95, 0x25, 0xb1, 0x8d, 0x73, 0x23, 0xa5, 299 | 0x7f, 0x91, 0x96, 0x3c, 0x37, 300 | ] 301 | } 302 | ]; 303 | 304 | describe('limits test', function() { 305 | var v = shortInput; 306 | var v2 = inputs[12]; 307 | 308 | it('should throw with too small logN', function() { 309 | assert.throws(function() { 310 | scrypt(v.password, v.salt, 0, v.r, v.dkLen); 311 | }, Error); 312 | }); 313 | 314 | it('should throw with too big logN', function() { 315 | assert.throws(function() { 316 | scrypt(v.password, v.salt, 32, v.r, v.dkLen); 317 | }, Error); 318 | }); 319 | 320 | it('should throw with too big N', function() { 321 | assert.throws(function() { 322 | scrypt(v.password, v.salt, { N: ((-1)>>>0) + 1, r: v.r, dkLen: v.dkLen }, function() {}); 323 | }, Error); 324 | }); 325 | 326 | it('should throw with too small N', function() { 327 | assert.throws(function() { 328 | scrypt(v.password, v.salt, { N: 1, r: v.r, dkLen: v.dkLen }, function() {}); 329 | }, Error); 330 | }); 331 | 332 | it('should throw when N is not power of two', function() { 333 | assert.throws(function() { 334 | scrypt(v.password, v.salt, { N: 123, r: v.r, dkLen: v.dkLen }, function() {}); 335 | }, Error); 336 | }); 337 | 338 | it('should throw with too large parameters', function() { 339 | assert.throws(function() { 340 | scrypt(v.password, v.salt, v.logN, 1<<31, v.dkLen); 341 | }, Error); 342 | }); 343 | 344 | it('should throw when r = 0', function() { 345 | assert.throws(function() { 346 | scrypt(v.password, v.salt, v.logN, 0, v.dkLen); 347 | }, Error); 348 | }); 349 | 350 | it('should throw when p = 0', function() { 351 | assert.throws(function() { 352 | scrypt(v.password, v.salt, { logN: v.logN, r: v.r, p: 0, dkLen: v.dkLen}); 353 | }, Error); 354 | }); 355 | 356 | it('should not throw when password > 64', function() { 357 | assert.doesNotThrow(function() { 358 | scrypt(v2.password, v2.salt, { logN: v2.logN, r: v2.r, dkLen: v2.dkLen }, function() {}); 359 | }, Error); 360 | }); 361 | }); 362 | 363 | describe('argument order test', function() { 364 | this.timeout(100000); 365 | 366 | var v = shortInput; 367 | 368 | it('all arguments', function(done) { 369 | scrypt(v.password, v.salt, v.logN, v.r, v.dkLen, 1000, function(out) { 370 | assert.equal(v.hexResult, out); 371 | done(); 372 | }, "hex"); 373 | }); 374 | 375 | it('all arguments, zero interruptStep', function(done) { 376 | scrypt(v.password, v.salt, v.logN, v.r, v.dkLen, 0, function(out) { 377 | assert.equal(v.hexResult, out); 378 | done(); 379 | }, "hex"); 380 | }); 381 | 382 | it('drop encoding', function(done) { 383 | scrypt(v.password, v.salt, v.logN, v.r, v.dkLen, 1000, function(out) { 384 | assert.deepEqual(v.result, out); 385 | done(); 386 | }); 387 | }); 388 | 389 | it('drop interruptStep, keep encoding', function(done) { 390 | scrypt(v.password, v.salt, v.logN, v.r, v.dkLen, function(out) { 391 | assert.equal(v.hexResult, out); 392 | done(); 393 | }, 'hex'); 394 | }); 395 | 396 | }); 397 | 398 | describe('options test', function() { 399 | var v = shortInput; 400 | 401 | it('should throw when given too many arguments', function() { 402 | assert.throws(function() { 403 | scrypt(v.password, v.salt, { logN: v.logN, r: 1, dkLen: v.dkLen }, 666, function(){}); 404 | }, Error); 405 | }); 406 | 407 | it('should throw when there is no N or logN', function() { 408 | assert.throws(function() { 409 | scrypt(v.password, v.salt, { r: 1, dkLen: v.dkLen }); 410 | }, Error); 411 | }); 412 | 413 | 414 | 415 | }); 416 | 417 | describe('encoding test', function() { 418 | this.timeout(100000); 419 | 420 | var v = shortInput; 421 | 422 | it('should return string for "hex"', function(done) { 423 | scrypt(v.password, v.salt, { logN: v.logN, r: v.r, dkLen: v.dkLen, encoding: 'hex' }, function(out) { 424 | assert.ok(typeof out === 'string'); 425 | done(); 426 | }); 427 | }); 428 | 429 | it('should return string for "base64"', function(done) { 430 | scrypt(v.password, v.salt, { logN: v.logN, r: v.r, dkLen: v.dkLen, encoding: 'hex' }, function(out) { 431 | assert.ok(typeof out === 'string'); 432 | done(); 433 | }); 434 | }); 435 | 436 | if (typeof Uint8Array !== 'undefined') { 437 | it('should return Uint8Array for "binary"', function(done) { 438 | scrypt(v.password, v.salt, { logN: v.logN, r: v.r, dkLen: v.dkLen, encoding: 'binary' }, function(out) { 439 | assert.ok(out instanceof Uint8Array); 440 | done(); 441 | }); 442 | }); 443 | } 444 | 445 | it('should return Array for undefined', function(done) { 446 | scrypt(v.password, v.salt, { logN: v.logN, r: v.r, dkLen: v.dkLen }, function(out) { 447 | assert.equal(Object.prototype.toString.call(out), "[object Array]"); 448 | done(); 449 | }); 450 | }); 451 | }); 452 | 453 | function async_test(i, interruptStep, done) { 454 | var v = inputs[i]; 455 | scrypt(v.password, v.salt, v.logN, v.r, v.dkLen, interruptStep, function(out) { 456 | assert.deepEqual(v.result, out); 457 | done(); 458 | }, v.encoding); 459 | } 460 | 461 | describe('async input/output test', function() { 462 | this.timeout(100000); 463 | 464 | var step = 1000; 465 | 466 | it('input 0', function(done) { 467 | async_test(0, step, done); 468 | }); 469 | it('input 1', function(done) { 470 | async_test(1, step, done); 471 | }); 472 | it('input 2', function(done) { 473 | async_test(2, step, done); 474 | }); 475 | it('input 3', function(done) { 476 | async_test(3, step, done); 477 | }); 478 | it('input 4', function(done) { 479 | async_test(4, step, done); 480 | }); 481 | it('input 5', function(done) { 482 | async_test(5, step, done); 483 | }); 484 | it('input 6', function(done) { 485 | async_test(6, step, done); 486 | }); 487 | it('input 7', function(done) { 488 | async_test(7, step, done); 489 | }); 490 | it('input 8', function(done) { 491 | async_test(8, step, done); 492 | }); 493 | it('input 9', function(done) { 494 | async_test(9, step, done); 495 | }); 496 | // the following two tests take a bit of time (~2.8s each), 497 | it('input 10', function(done) { 498 | async_test(10, step, done); 499 | }); 500 | it('input 11', function(done) { 501 | async_test(11, step, done); 502 | }); 503 | // the following test tests long input 504 | it('input 12', function(done) { 505 | async_test(12, step, done); 506 | }); 507 | }); 508 | 509 | describe('async input/output test with zero interruptStep', function() { 510 | this.timeout(100000); 511 | 512 | // Only shorter tests: 513 | var step = 0; 514 | 515 | it('input 0', function(done) { 516 | async_test(0, step, done); 517 | }); 518 | it('input 1', function(done) { 519 | async_test(1, step, done); 520 | }); 521 | it('input 2', function(done) { 522 | async_test(2, step, done); 523 | }); 524 | it('input 3', function(done) { 525 | async_test(3, step, done); 526 | }); 527 | 528 | }); 529 | 530 | function async_test_opts(i, interruptStep, done) { 531 | var v = inputsWithP[i]; 532 | scrypt(v.password, v.salt, { 533 | N: v.N, 534 | r: v.r, 535 | p: v.p, 536 | dkLen: v.result.length, 537 | interruptStep: interruptStep, 538 | encoding: v.encoding 539 | }, function(out) { 540 | assert.deepEqual(v.result, out); 541 | done(); 542 | }); 543 | } 544 | 545 | 546 | describe('async input/output test with options and p with zero interruptStep', function() { 547 | this.timeout(100000); 548 | 549 | var step = 0; 550 | 551 | it('input 0', function(done) { 552 | async_test_opts(0, step, done); 553 | }); 554 | //// Takes too long 555 | // it('input 1', function(done) { 556 | // async_test_opts(1, step, done); 557 | // }); 558 | 559 | }); 560 | 561 | describe('async input/output test with options and p', function() { 562 | this.timeout(100000); 563 | 564 | var step = 1000; 565 | 566 | it('input 0', function(done) { 567 | async_test_opts(0, step, done); 568 | }); 569 | //// Takes too long 570 | // it('input 1', function(done) { 571 | // async_test_opts(1, step, done); 572 | // }); 573 | 574 | }); 575 | --------------------------------------------------------------------------------