Comparing version 0.8.0 to 0.9.0
# Argon2 | ||
[![Build Status](https://travis-ci.org/P-H-C/phc-winner-argon2.svg?branch=master)](https://travis-ci.org/P-H-C/phc-winner-argon2) | ||
[![codecov.io](https://codecov.io/github/P-H-C/phc-winner-argon2/coverage.svg?branch=master)](https://codecov.io/github/P-H-C/phc-winner-argon2?branch=master) | ||
This is the reference C implementation of Argon2, the password-hashing | ||
@@ -7,11 +10,21 @@ function that won the [Password Hashing Competition | ||
You should use Argon2 whenever you need to hash passwords for credential | ||
storage, key derivation, or other applications. | ||
Argon2 is a password-hashing function that summarizes the state of the | ||
art in the design of memory-hard functions and can be used to hash | ||
passwords for credential storage, key derivation, or other applications. | ||
There are two main versions of Argon2, **Argon2i** and **Argon2d**. Argon2i | ||
is the safest against side-channel attacks, while Argon2d provides the | ||
highest resistance against GPU cracking attacks. | ||
It has a simple design aimed at the highest memory filling rate and | ||
effective use of multiple computing units, while still providing defense | ||
against tradeoff attacks (by exploiting the cache and memory organization | ||
of the recent processors). | ||
Argon2i and Argon2d are parametrized by | ||
Argon2 has two variants: Argon2d and Argon2i. Argon2d is faster and | ||
uses data-depending memory access, which makes it highly resistant | ||
against GPU cracking attacks and suitable for applications with no threats | ||
from side-channel timing attacks (eg. cryptocurrencies). Argon2i instead | ||
uses data-independent memory access, which is preferred for password | ||
hashing and password-based key derivation, but it is slower as it makes | ||
more passes over the memory to protect from tradeoff attacks. | ||
Argon2i and Argon2d are parametrized by: | ||
* A **time** cost, which defines the amount of computation realized and | ||
@@ -198,2 +211,10 @@ therefore the execution time, given in number of iterations | ||
## Test Suite | ||
There are two sets of test suites. One is a low level test for the hash | ||
function, the other tests the higher level API. Both of these are built and | ||
executed by running: | ||
`make test` | ||
## Intellectual property | ||
@@ -200,0 +221,0 @@ |
132
index.js
@@ -11,3 +11,5 @@ const bindings = require('bindings')('argon2'); | ||
const fail = (message, callback) => { | ||
const limits = Object.freeze(bindings.limits); | ||
const fail = (message, reject) => { | ||
'use strict'; | ||
@@ -17,58 +19,36 @@ | ||
if (typeof callback === 'undefined') { | ||
if (typeof reject === 'function') { | ||
process.nextTick(reject.bind(null, error)); | ||
} else { | ||
throw error; | ||
} else { | ||
process.nextTick(() => { | ||
callback(error, null); | ||
}); | ||
} | ||
}; | ||
const validate = (salt, options, callback) => { | ||
const validate = (salt, options, resolve, reject) => { | ||
'use strict'; | ||
if (salt.length !== 16) { | ||
fail('Invalid salt length, must be 16 bytes.', callback); | ||
if (!Buffer.isBuffer(salt) || salt.length < 8) { | ||
fail('Invalid salt, must be a buffer with 8 or more bytes.', reject); | ||
return false; | ||
} | ||
for (const key of Object.keys(defaults)) { | ||
options[key] = options[key] || defaults[key]; | ||
if (options.parallelism === 'auto') { | ||
options.parallelism = require('os').cpus().length; | ||
} | ||
if (isNaN(options.timeCost)) { | ||
fail('Invalid time cost, must be a number.', callback); | ||
return false; | ||
} else if (options.timeCost <= 0) { | ||
fail('Time cost too low, minimum of 1.', callback); | ||
return false; | ||
} else if (options.timeCost >= 4294967296) { | ||
fail('Time cost too high, maximum of 4294967295.', callback); | ||
return false; | ||
// TODO: replace var with const https://github.com/tapjs/node-tap/issues/236 | ||
for (var key of Object.keys(limits)) { | ||
var max = limits[key].max; | ||
var min = limits[key].min; | ||
var value = options[key]; | ||
if (!Number.isInteger(value) || value > max || value < min) { | ||
fail(`Invalid ${key}, must be an integer between ${min} and ${max}.`, reject); | ||
return false; | ||
} | ||
} | ||
if (isNaN(options.memoryCost)) { | ||
fail('Invalid memory cost, must be a number.', callback); | ||
return false; | ||
} else if (options.memoryCost <= 0) { | ||
fail('Memory cost too low, minimum of 1.', callback); | ||
return false; | ||
} else if (options.memoryCost >= 32) { | ||
fail('Memory cost too high, maximum of 31.', callback); | ||
return false; | ||
if (typeof resolve === 'function') { | ||
resolve(); | ||
} | ||
if (isNaN(options.parallelism)) { | ||
fail('Invalid parallelism, must be a number.', callback); | ||
return false; | ||
} else if (options.parallelism <= 0) { | ||
fail('Parallelism too low, minimum of 1.', callback); | ||
return false; | ||
} else if (options.parallelism >= 4294967296) { | ||
fail('Parallelism too high, maximum of 4294967295.', callback); | ||
return false; | ||
} | ||
options.argon2d = !!options.argon2d; | ||
return true; | ||
@@ -78,33 +58,28 @@ }; | ||
module.exports = { | ||
defaults, | ||
defaults, limits, | ||
hash (plain, salt, options, callback) { | ||
hash(plain, salt, options) { | ||
'use strict'; | ||
if (!Buffer.isBuffer(salt)) { | ||
salt = new Buffer(salt); | ||
} | ||
options = Object.assign({}, defaults, options); | ||
if (!callback) { | ||
callback = options; | ||
options = defaults; | ||
if (!Buffer.isBuffer(plain)) { | ||
plain = new Buffer(plain); | ||
} | ||
options = Object.assign({}, options); | ||
if (validate(salt, options, callback)) { | ||
return bindings.hash(plain, salt, options.timeCost, options.memoryCost, | ||
options.parallelism, options.argon2d, callback); | ||
} | ||
return new Promise(validate.bind(null, salt, options)) | ||
.then(bindings.hash.bind(null, plain, salt, options.timeCost, | ||
options.memoryCost, options.parallelism, options.argon2d)); | ||
}, | ||
hashSync (plain, salt, options) { | ||
hashSync(plain, salt, options) { | ||
'use strict'; | ||
if (!Buffer.isBuffer(salt)) { | ||
salt = new Buffer(salt); | ||
console.warn('The synchronous API is deprecated, use ES6 await instead.'); | ||
options = Object.assign({}, defaults, options); | ||
if (!Buffer.isBuffer(plain)) { | ||
plain = new Buffer(plain); | ||
} | ||
options = Object.assign({}, options || defaults); | ||
if (validate(salt, options)) { | ||
@@ -116,25 +91,46 @@ return bindings.hashSync(plain, salt, options.timeCost, | ||
generateSalt (callback) { | ||
generateSalt(length) { | ||
'use strict'; | ||
return crypto.randomBytes(16, callback); | ||
length = typeof length === 'undefined' ? 16 : length; | ||
return new Promise((resolve, reject) => { | ||
crypto.randomBytes(length, (err, salt) => { | ||
/* istanbul ignore if */ | ||
if (err) { | ||
return reject(err); | ||
} | ||
return resolve(salt); | ||
}); | ||
}); | ||
}, | ||
generateSaltSync () { | ||
generateSaltSync(length) { | ||
'use strict'; | ||
return crypto.randomBytes(16); | ||
console.warn('The synchronous API is deprecated, use ES6 await instead.'); | ||
length = typeof length === 'undefined' ? 16 : length; | ||
return crypto.randomBytes(length); | ||
}, | ||
verify (hash, plain, callback) { | ||
verify(hash, plain) { | ||
'use strict'; | ||
return bindings.verify(hash, plain, /argon2d/.test(hash), callback); | ||
if (!Buffer.isBuffer(plain)) { | ||
plain = new Buffer(plain); | ||
} | ||
return bindings.verify(hash, plain, /argon2d/.test(hash)); | ||
}, | ||
verifySync (hash, plain) { | ||
verifySync(hash, plain) { | ||
'use strict'; | ||
console.warn('The synchronous API is deprecated, use ES6 await instead.'); | ||
if (!Buffer.isBuffer(plain)) { | ||
plain = new Buffer(plain); | ||
} | ||
return bindings.verifySync(hash, plain, /argon2d/.test(hash)); | ||
} | ||
}; |
{ | ||
"name": "argon2", | ||
"version": "0.8.0", | ||
"version": "0.9.0", | ||
"description": "An Argon2 library for Node", | ||
@@ -9,3 +9,3 @@ "main": "index.js", | ||
"clean": "node-gyp clean", | ||
"test": "nodeunit test.spec.js" | ||
"test": "xo && tap test.spec.js --reporter=list" | ||
}, | ||
@@ -36,7 +36,11 @@ "repository": { | ||
"async-benchmark": "^1.0.1", | ||
"nodeunit": "^0.9.1" | ||
"tap": "^5.7.0", | ||
"xo": "^0.12.1" | ||
}, | ||
"engines": { | ||
"node": ">=4.0.0" | ||
"node": ">=4.0.0" | ||
}, | ||
"xo": { | ||
"space": 2 | ||
} | ||
} |
130
README.md
# node-argon2 [![NPM package][npm-image]][npm-url] [![Build status][travis-image]][travis-url] [![Coverage status][coverage-image]][coverage-url] [![Code Quality][codequality-image]][codequality-url] [![Dependencies][david-dm-image]][david-dm-url] | ||
Bindings to the reference [Argon2](https://github.com/P-H-C/phc-winner-argon2) | ||
Bindings to the reference [Argon2](https://github.com/P-H-C/phc-winner-argon2) | ||
implementation. | ||
@@ -12,15 +12,13 @@ | ||
and async, and to verify if a password matches a hash, and also generate random | ||
cryptographically-safe salts. Salts **must** be exactly 16-byte long buffers | ||
but strings will automatically be converted (this is **deprecated** and should | ||
NOT be relied upon). | ||
cryptographically-safe salts. Salts **must** be at least 8-byte long buffers. | ||
To hash a password: | ||
```js | ||
var argon2 = require('argon2'); | ||
const argon2 = require('argon2'); | ||
const salt = new Buffer('somesalt'); | ||
argon2.hash('password', 'somesalt', function (err, hash) { | ||
if (err) // hashing failure | ||
throw err; | ||
doSomethingWith(hash); | ||
argon2.hash('password', salt).then(hash => { | ||
// ... | ||
}).catch(err => { | ||
// ... | ||
}); | ||
@@ -31,16 +29,21 @@ | ||
try { | ||
var hash = argon2.hashSync('password', 'somesaltwith16ch'); | ||
const hash = argon2.hashSync('password', salt); | ||
} catch (err) { | ||
console.log(err); | ||
//... | ||
} | ||
// ES6 | ||
try { | ||
const hash = await argon2.hash('password', salt); | ||
} catch (err) { | ||
//... | ||
} | ||
``` | ||
Resultant hashes will be 90 characters long. You can choose between Argon2i and | ||
Argon2d by passing an object as the third argument with the `argon2d` key set to | ||
whether or not you want Argon2d: | ||
You can choose between Argon2i and Argon2d by passing an object as the third | ||
argument with the `argon2d` key set to whether or not you want Argon2d: | ||
```js | ||
var argon2 = require('argon2'); | ||
argon2.hash('password', 'somesalt', { | ||
argon2.hash('password', salt, { | ||
argon2d: true | ||
}, function (err, hash) { | ||
}.then(hash => { | ||
// ... | ||
@@ -52,3 +55,3 @@ }); | ||
try { | ||
var hash = argon2.hashSync('password', 'somesaltwith16ch', { | ||
const hash = argon2.hashSync('password', salt, { | ||
argon2d: true | ||
@@ -59,12 +62,21 @@ }); | ||
} | ||
// ES6 | ||
try { | ||
const hash = await argon2.hash('password', salt, { | ||
argon2d: true | ||
}); | ||
} catch (err) { | ||
// ... | ||
} | ||
``` | ||
The `argon2d` option is flexible and accepts any truthy or falsy values. | ||
You can provide your own salt as the second parameter. It is recommended to use | ||
the salt generating methods instead of a hardcoded, constant salt: | ||
You can provide your own salt as the second parameter. It is **highly** | ||
recommended to use the salt generating methods instead of a hardcoded, constant | ||
salt: | ||
```js | ||
var argon2 = require('argon2'); | ||
argon2.generateSalt(function (err, salt) { | ||
doSomethingWith(salt); | ||
argon2.generateSalt().then(salt => { | ||
// ... | ||
}); | ||
@@ -75,4 +87,26 @@ | ||
var salt = argon2.generateSaltSync(); | ||
// ES6 | ||
const salt = await argon2.generateSalt(); | ||
``` | ||
You can also pass a desired salt length as parameter. Although the default of 16 | ||
is enough and very safe, Argon2 will use all salt bytes. | ||
```js | ||
argon2.generateSalt(32).then(salt => { | ||
// ... | ||
}); | ||
// OR | ||
var salt = argon2.generateSaltSync(32); | ||
// ES6 | ||
const salt = await argon2.generateSalt(32); | ||
``` | ||
Please keep in mind synchronous salt generation is blocking, since it waits for | ||
entropy when enough is not available, so please refrain from using sync version. | ||
You can also modify time, memory and parallelism constraints passing the object | ||
@@ -82,8 +116,8 @@ as the third parameter, with keys `timeCost`, `memoryCost` and `parallelism`, | ||
```js | ||
var argon2 = require('argon2'); | ||
const options = { | ||
timeCost: 4, memoryCost: 13, parallelism: 2, argon2d: true | ||
}; | ||
argon2.generateSalt(function (err, salt) { | ||
argon2.hash('password', salt, { | ||
timeCost: 4, memoryCost: 13, parallelism: 2 | ||
}, function (err, hash) { | ||
argon2.generateSalt().then(salt => { | ||
argon2.hash('password', salt, options).then(hash => { | ||
// ... | ||
@@ -95,5 +129,7 @@ }); | ||
var hash = argon2.hashSync('password', argon2.generateSaltSync(), { | ||
timeCost: 4, memoryCost: 13, parallelism: 2 | ||
}); | ||
var hash = argon2.hashSync('password', argon2.generateSaltSync(), options); | ||
// ES6 | ||
var hash = await argon2.hash('password', await argon2.generateSalt(), options); | ||
``` | ||
@@ -103,4 +139,2 @@ | ||
```js | ||
var argon2 = require('argon2'); | ||
console.log(argon2.defaults); | ||
@@ -112,9 +146,6 @@ // => { timeCost: 3, memoryCost: 12, parallelism: 1, argon2d: false } | ||
```js | ||
var argon2 = require('argon2'); | ||
argon2.verify('<big long hash>', 'password', function (err) { | ||
if (err) // password did not match | ||
throw err; | ||
authenticate(); | ||
argon2.verify('<big long hash>', 'password').then(() => { | ||
// password match | ||
}).catch(() => { | ||
// password did not match | ||
}); | ||
@@ -125,6 +156,15 @@ | ||
if (argon2.verifySync('<big long hash>', 'password')) { | ||
authenticate(); | ||
// password match | ||
} else { | ||
fail(); | ||
// password did not match | ||
} | ||
// ES6 | ||
try { | ||
await argon2.verify('<big long hash>', 'password'); | ||
// password match | ||
} catch (err) { | ||
// password did not match | ||
} | ||
``` | ||
@@ -131,0 +171,0 @@ First parameter must have been generated by an Argon2 encoded hashing method, |
998
test.spec.js
@@ -1,635 +0,671 @@ | ||
const argon2 = process.env.COVERAGE | ||
? require('./index-cov') | ||
: require('./index'); | ||
const argon2 = require('./index'); | ||
const t = require('tap'); | ||
const password = 'password'; | ||
const salt = new Buffer(16); | ||
salt.fill(0).write('somesalt'); | ||
const salt = new Buffer('somesalt'); | ||
const saltWithNull = new Buffer('\0abcdefghijklmno'); | ||
module.exports = { | ||
testDefaults (assert) { | ||
'use strict'; | ||
// Like argon2's modified base64 implementation, this function truncates any | ||
// trailing '=' characters for a more compact representation. | ||
const truncatedBase64 = (buffer) => { | ||
return buffer.toString('base64').replace(/\=*$/, ''); | ||
}; | ||
assert.expect(1); | ||
// hashes for argon2i and argon2d with default options | ||
const hashes = Object.freeze({ | ||
argon2i: '$argon2i$m=4096,t=3,p=1$c29tZXNhbHQ$vpOd0mbc3AzXEHMgcTb1CrZt5XuoRQuz1kQtGBv7ejk', | ||
argon2d: '$argon2d$m=4096,t=3,p=1$c29tZXNhbHQ$/rwrGjZ1NrS+TEgQxricD7B57yJMKGQ/uov96abC6ko' | ||
}); | ||
assert.deepEqual(argon2.defaults, { | ||
timeCost: 3, | ||
memoryCost: 12, | ||
parallelism: 1, | ||
argon2d: false | ||
}); | ||
assert.done(); | ||
}, | ||
const limits = argon2.limits; | ||
console.warn = () => {}; | ||
testHash (assert) { | ||
'use strict'; | ||
t.test('defaults', t => { | ||
'use strict'; | ||
assert.expect(3); | ||
t.equivalent(argon2.defaults, { | ||
timeCost: 3, | ||
memoryCost: 12, | ||
parallelism: 1, | ||
argon2d: false | ||
}); | ||
t.end(); | ||
}); | ||
argon2.hash(password, salt, (err, hash) => { | ||
assert.ok(hash, 'Hash should be defined.'); | ||
assert.equal(hash, '$argon2i$m=4096,t=3,p=1$c29tZXNhbHQAAAAAAAAAAA$FHF/OZ0GJpMRAlBmPTqXxw36Ftp87JllALZPcP9w9gs'); | ||
assert.equal(undefined, err); | ||
assert.done(); | ||
}); | ||
}, | ||
t.test('basic async hash', t => { | ||
'use strict'; | ||
testHashArgon2d (assert) { | ||
'use strict'; | ||
t.plan(1); | ||
assert.expect(3); | ||
return argon2.hash(password, salt).then(hash => { | ||
t.equal(hash, hashes.argon2i); | ||
}); | ||
}).catch(t.threw); | ||
argon2.hash(password, salt, { | ||
argon2d: true | ||
}, (err, hash) => { | ||
assert.ok(hash, 'Hash should be defined.'); | ||
assert.ok(/\$argon2d\$/.test(hash), 'Should have argon2d signature.'); | ||
assert.equal(undefined, err); | ||
assert.done(); | ||
}); | ||
}, | ||
t.test('async hash with null in password', t => { | ||
'use strict'; | ||
testHashTruthyArgon2d (assert) { | ||
'use strict'; | ||
t.plan(1); | ||
assert.expect(3); | ||
return argon2.hash('pass\0word', salt).then(hash => { | ||
t.equal(hash, '$argon2i$m=4096,t=3,p=1$c29tZXNhbHQ$tcauj48oAe6NE/VLzTawLTQtmX848wkNs1d7z53ahNE'); | ||
}); | ||
}).catch(t.threw); | ||
argon2.hash(password, salt, { | ||
argon2d: 'foo' | ||
}, (err, hash) => { | ||
assert.ok(hash, 'Hash should be defined.'); | ||
assert.ok(/\$argon2d\$/.test(hash), 'Should have argon2d signature.'); | ||
assert.equal(undefined, err); | ||
assert.done(); | ||
}); | ||
}, | ||
t.test('async hash with null in salt', t => { | ||
'use strict'; | ||
testHashFalsyArgon2d (assert) { | ||
'use strict'; | ||
t.plan(1); | ||
assert.expect(3); | ||
return argon2.hash(password, saltWithNull).then(hash => { | ||
const saltBase64 = hash.substring(24, 46); | ||
t.equal(saltBase64, truncatedBase64(saltWithNull)); | ||
}); | ||
}).catch(t.threw); | ||
argon2.hash(password, salt, { | ||
argon2d: '' | ||
}, (err, hash) => { | ||
assert.ok(hash, 'Hash should be defined.'); | ||
assert.ok(/\$argon2i\$/.test(hash), 'Should not have argon2d signature.'); | ||
assert.equal(undefined, err); | ||
assert.done(); | ||
t.test('async hash with longer salt', t => { | ||
'use strict'; | ||
t.plan(1); | ||
/* intentionally using a length that is not multiple of 3 */ | ||
return argon2.generateSalt(500).then(salt => { | ||
return argon2.hash('password', salt).then(hash => { | ||
t.match(hash, /.*\$.{667}\$/, 'Hash should use the entire salt'); | ||
return argon2.verify(hash, 'password').then(t.end); | ||
}); | ||
}, | ||
}); | ||
}).catch(t.threw); | ||
testHashLongSalt (assert) { | ||
'use strict'; | ||
t.test('async hash with argon2d', t => { | ||
'use strict'; | ||
assert.expect(3); | ||
t.plan(2); | ||
argon2.hash(password, 'somesaltwaytoobig', (err, hash) => { | ||
assert.ok(err, 'Error should be defined.'); | ||
assert.equal(err.message, 'Invalid salt length, must be 16 bytes.'); | ||
assert.equal(undefined, hash); | ||
assert.done(); | ||
}); | ||
}, | ||
return argon2.hash(password, salt, { | ||
argon2d: true | ||
}).then(hash => { | ||
t.match(hash, /\$argon2d\$/, 'Should have argon2d signature.'); | ||
t.equal(hash, hashes.argon2d); | ||
}); | ||
}).catch(t.threw); | ||
testHashTimeCost (assert) { | ||
'use strict'; | ||
t.test('async hash with truthy argon2d', t => { | ||
'use strict'; | ||
assert.expect(3); | ||
t.plan(1); | ||
argon2.hash(password, salt, { | ||
timeCost: 4 | ||
}, (err, hash) => { | ||
assert.ok(hash, 'Hash should be defined.'); | ||
assert.ok(/t=4/.test(hash), 'Should have correct time cost.'); | ||
assert.equal(undefined, err); | ||
assert.done(); | ||
}); | ||
}, | ||
return argon2.hash(password, salt, { | ||
argon2d: 'foo' | ||
}).then(hash => { | ||
t.match(hash, /\$argon2d\$/, 'Should have argon2d signature.'); | ||
}); | ||
}).catch(t.threw); | ||
testHashInvalidTimeCost (assert) { | ||
'use strict'; | ||
t.test('async hash with falsy argon2d', t => { | ||
'use strict'; | ||
assert.expect(3); | ||
t.plan(1); | ||
argon2.hash(password, salt, { | ||
timeCost: 'foo' | ||
}, (err, hash) => { | ||
assert.ok(err, 'Error should be defined.'); | ||
assert.equal(err.message, 'Invalid time cost, must be a number.'); | ||
assert.equal(undefined, hash); | ||
assert.done(); | ||
}); | ||
}, | ||
return argon2.hash(password, salt, { | ||
argon2d: '' | ||
}).then(hash => { | ||
t.notMatch(hash, /\$argon2d\$/, 'Should not have argon2d signature.'); | ||
}); | ||
}).catch(t.threw); | ||
testHashLowTimeCost (assert) { | ||
'use strict'; | ||
t.test('async hash with invalid salt', t => { | ||
'use strict'; | ||
assert.expect(3); | ||
t.plan(1); | ||
argon2.hash(password, salt, { | ||
timeCost: -4294967290 | ||
}, (err, hash) => { | ||
assert.ok(err, 'Error should be defined.'); | ||
assert.equal(err.message, 'Time cost too low, minimum of 1.'); | ||
assert.equal(undefined, hash); | ||
assert.done(); | ||
}); | ||
}, | ||
return argon2.hash(password, 'stringsalt').catch(err => { | ||
t.match(err.message, /invalid salt.+must be a buffer/i); | ||
}); | ||
}); | ||
testHashHighTimeCost (assert) { | ||
'use strict'; | ||
t.test('async hash with short salt', t => { | ||
'use strict'; | ||
assert.expect(3); | ||
t.plan(1); | ||
argon2.hash(password, salt, { | ||
timeCost: 4294967297 | ||
}, (err, hash) => { | ||
assert.ok(err, 'Error should be defined.'); | ||
assert.equal(err.message, 'Time cost too high, maximum of 4294967295.'); | ||
assert.equal(undefined, hash); | ||
assert.done(); | ||
}); | ||
}, | ||
return argon2.hash(password, salt.slice(0, 7)).catch(err => { | ||
t.match(err.message, /invalid salt.+with 8 or more bytes/i); | ||
}); | ||
}); | ||
testHashMemoryCost (assert) { | ||
'use strict'; | ||
t.test('async hash with time cost', t => { | ||
'use strict'; | ||
assert.expect(3); | ||
t.plan(1); | ||
argon2.hash(password, salt, { | ||
memoryCost: 13 | ||
}, (err, hash) => { | ||
assert.ok(hash, 'Hash should be defined.'); | ||
assert.ok(/m=8192/.test(hash), 'Should have correct memory cost.'); | ||
assert.equal(undefined, err); | ||
assert.done(); | ||
}); | ||
}, | ||
return argon2.hash(password, salt, { | ||
timeCost: 4 | ||
}).then(hash => { | ||
t.match(hash, /t=4/, 'Should have correct time cost.'); | ||
}); | ||
}).catch(t.threw); | ||
testHashInvalidMemoryCost (assert) { | ||
'use strict'; | ||
t.test('async hash with invalid time cost', t => { | ||
'use strict'; | ||
assert.expect(3); | ||
t.plan(1); | ||
argon2.hash(password, salt, { | ||
memoryCost: 'foo' | ||
}, (err, hash) => { | ||
assert.ok(err, 'Error should be defined.'); | ||
assert.equal(err.message, 'Invalid memory cost, must be a number.'); | ||
assert.equal(undefined, hash); | ||
assert.done(); | ||
}); | ||
}, | ||
return argon2.hash(password, salt, { | ||
timeCost: 'foo' | ||
}).catch(err => { | ||
t.match(err.message, /invalid timeCost.+must be an integer/i); | ||
}); | ||
}); | ||
testHashLowMemoryCost (assert) { | ||
'use strict'; | ||
t.test('async hash with low time cost', t => { | ||
'use strict'; | ||
assert.expect(3); | ||
t.plan(1); | ||
argon2.hash(password, salt, { | ||
memoryCost: -4294967290 | ||
}, (err, hash) => { | ||
assert.ok(err, 'Error should be defined.'); | ||
assert.equal(err.message, 'Memory cost too low, minimum of 1.'); | ||
assert.equal(undefined, hash); | ||
assert.done(); | ||
}); | ||
}, | ||
return argon2.hash(password, salt, { | ||
timeCost: limits.timeCost.min - 1 | ||
}).catch(err => { | ||
t.match(err.message, /invalid timeCost.+between \d+ and \d+/i); | ||
}); | ||
}); | ||
testHashHighMemoryCost (assert) { | ||
'use strict'; | ||
t.test('async hash with high time cost', t => { | ||
'use strict'; | ||
assert.expect(3); | ||
t.plan(1); | ||
argon2.hash(password, salt, { | ||
memoryCost: 32 | ||
}, (err, hash) => { | ||
assert.ok(err, 'Error should be defined.'); | ||
assert.equal(err.message, 'Memory cost too high, maximum of 31.'); | ||
assert.equal(undefined, hash); | ||
assert.done(); | ||
}); | ||
}, | ||
return argon2.hash(password, salt, { | ||
timeCost: limits.timeCost.max + 1 | ||
}).catch(err => { | ||
t.match(err.message, /invalid timeCost.+between \d+ and \d+/i); | ||
}); | ||
}); | ||
testHashParallelism (assert) { | ||
'use strict'; | ||
t.test('async hash with memory cost', t => { | ||
'use strict'; | ||
assert.expect(3); | ||
t.plan(1); | ||
argon2.hash(password, salt, { | ||
parallelism: 2 | ||
}, (err, hash) => { | ||
assert.ok(hash, 'Hash should be defined.'); | ||
assert.ok(/p=2/.test(hash), 'Should have correct parallelism.'); | ||
assert.equal(undefined, err); | ||
assert.done(); | ||
}); | ||
}, | ||
return argon2.hash(password, salt, { | ||
memoryCost: 13 | ||
}).then(hash => { | ||
t.match(hash, /m=8192/, 'Should have correct memory cost.'); | ||
}); | ||
}).catch(t.threw); | ||
testHashInvalidParallelism (assert) { | ||
'use strict'; | ||
t.test('async hash with invalid time cost', t => { | ||
'use strict'; | ||
assert.expect(3); | ||
t.plan(1); | ||
argon2.hash(password, salt, { | ||
parallelism: 'foo' | ||
}, (err, hash) => { | ||
assert.ok(err, 'Error should be defined.'); | ||
assert.equal(err.message, 'Invalid parallelism, must be a number.'); | ||
assert.equal(undefined, hash); | ||
assert.done(); | ||
}); | ||
}, | ||
return argon2.hash(password, salt, { | ||
memoryCost: 'foo' | ||
}).catch(err => { | ||
t.match(err.message, /invalid memoryCost.+must be an integer/i); | ||
}); | ||
}); | ||
testHashLowParallelism (assert) { | ||
'use strict'; | ||
t.test('async hash with low time cost', t => { | ||
'use strict'; | ||
assert.expect(3); | ||
t.plan(1); | ||
argon2.hash(password, salt, { | ||
parallelism: -4294967290 | ||
}, (err, hash) => { | ||
assert.ok(err, 'Error should be defined.'); | ||
assert.equal(err.message, 'Parallelism too low, minimum of 1.'); | ||
assert.equal(undefined, hash); | ||
assert.done(); | ||
}); | ||
}, | ||
return argon2.hash(password, salt, { | ||
memoryCost: limits.memoryCost.min - 1 | ||
}).catch(err => { | ||
t.match(err.message, /invalid memoryCost.+between \d+ and \d+/i); | ||
}); | ||
}); | ||
testHashHighParallelism (assert) { | ||
'use strict'; | ||
t.test('async hash with high time cost', t => { | ||
'use strict'; | ||
assert.expect(3); | ||
t.plan(1); | ||
argon2.hash(password, salt, { | ||
parallelism: 4294967297 | ||
}, (err, hash) => { | ||
assert.ok(err, 'Error should be defined.'); | ||
assert.equal(err.message, 'Parallelism too high, maximum of 4294967295.'); | ||
assert.equal(undefined, hash); | ||
assert.done(); | ||
}); | ||
}, | ||
return argon2.hash(password, salt, { | ||
memoryCost: limits.memoryCost.max + 1 | ||
}).catch(err => { | ||
t.match(err.message, /invalid memoryCost.+between \d+ and \d+/i); | ||
}); | ||
}); | ||
testHashAllOptions (assert) { | ||
'use strict'; | ||
t.test('async hash with parallelism', t => { | ||
'use strict'; | ||
assert.expect(3); | ||
t.plan(1); | ||
argon2.hash(password, salt, { | ||
timeCost: 4, | ||
memoryCost: 13, | ||
parallelism: 2 | ||
}, (err, hash) => { | ||
assert.ok(hash, 'Hash should be defined.'); | ||
assert.ok(/m=8192,t=4,p=2/.test(hash), 'Should have correct options.'); | ||
assert.equal(undefined, err); | ||
assert.done(); | ||
}); | ||
}, | ||
return argon2.hash(password, salt, { | ||
parallelism: 2 | ||
}).then(hash => { | ||
t.match(hash, /p=2/, 'Should have correct parallelism.'); | ||
}); | ||
}).catch(t.threw); | ||
testHashSync (assert) { | ||
'use strict'; | ||
t.test('async hash with invalid parallelism', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
t.plan(1); | ||
const hash = argon2.hashSync(password, salt); | ||
assert.equal(hash, '$argon2i$m=4096,t=3,p=1$c29tZXNhbHQAAAAAAAAAAA$FHF/OZ0GJpMRAlBmPTqXxw36Ftp87JllALZPcP9w9gs'); | ||
assert.done(); | ||
}, | ||
return argon2.hash(password, salt, { | ||
parallelism: 'foo' | ||
}).catch(err => { | ||
t.match(err.message, /invalid parallelism, must be an integer/i); | ||
}); | ||
}); | ||
testHashArgon2dSync (assert) { | ||
'use strict'; | ||
t.test('async hash with low parallelism', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
t.plan(1); | ||
const hash = argon2.hashSync(password, salt, { | ||
argon2d: true | ||
}); | ||
assert.ok(/\$argon2d\$/.test(hash), 'Should use argon2d signature.'); | ||
assert.done(); | ||
}, | ||
return argon2.hash(password, salt, { | ||
parallelism: limits.parallelism.min - 1 | ||
}).catch(err => { | ||
t.match(err.message, /invalid parallelism.+between \d+ and \d+/i); | ||
}); | ||
}); | ||
testHashTruthyArgon2dSync (assert) { | ||
'use strict'; | ||
t.test('async hash with high parallelism', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
t.plan(1); | ||
const hash = argon2.hashSync(password, salt, { | ||
argon2d: 'foo' | ||
}); | ||
assert.ok(/\$argon2d\$/.test(hash), 'Should use argon2d signature.'); | ||
assert.done(); | ||
}, | ||
return argon2.hash(password, salt, { | ||
parallelism: limits.parallelism.max + 1 | ||
}).catch(err => { | ||
t.match(err.message, /invalid parallelism.+between \d+ and \d+/i); | ||
}); | ||
}); | ||
testHashFalsyArgon2dSync (assert) { | ||
'use strict'; | ||
t.test('async hash with all options', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
t.plan(1); | ||
const hash = argon2.hashSync(password, salt, { | ||
argon2d: '' | ||
}); | ||
assert.ok(/\$argon2i\$/.test(hash), 'Should not use argon2d signature.'); | ||
assert.done(); | ||
}, | ||
return argon2.hash(password, salt, { | ||
timeCost: 4, | ||
memoryCost: 13, | ||
parallelism: 2 | ||
}).then(hash => { | ||
t.match(hash, /m=8192,t=4,p=2/, 'Should have correct options.'); | ||
}); | ||
}).catch(t.threw); | ||
testHashSyncTimeCost (assert) { | ||
'use strict'; | ||
t.test('basic sync hash', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
const hash = argon2.hashSync(password, salt); | ||
t.equal(hash, hashes.argon2i); | ||
t.end(); | ||
}); | ||
const hash = argon2.hashSync(password, salt, { | ||
timeCost: 4 | ||
}); | ||
assert.ok(/t=4/.test(hash), 'Should have correct time cost.'); | ||
assert.done(); | ||
}, | ||
t.test('sync hash with null in password', t => { | ||
'use strict'; | ||
testHashSyncInvalidTimeCost (assert) { | ||
'use strict'; | ||
const hash = argon2.hashSync('pass\0word', salt); | ||
t.equal(hash, '$argon2i$m=4096,t=3,p=1$c29tZXNhbHQ$tcauj48oAe6NE/VLzTawLTQtmX848wkNs1d7z53ahNE'); | ||
t.end(); | ||
}); | ||
assert.expect(1); | ||
t.test('sync hash with null in salt', t => { | ||
'use strict'; | ||
assert.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
timeCost: 'foo' | ||
}); | ||
}, /invalid/i); | ||
assert.done(); | ||
}, | ||
const hash = argon2.hashSync(password, saltWithNull); | ||
const saltBase64 = hash.substring(24, 46); | ||
t.equal(saltBase64, truncatedBase64(saltWithNull)); | ||
t.end(); | ||
}); | ||
testHashSyncLowTimeCost (assert) { | ||
'use strict'; | ||
t.test('sync hash with longer salt', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
t.plan(1); | ||
assert.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
timeCost: -4294967290 | ||
}); | ||
}, /too low/); | ||
assert.done(); | ||
}, | ||
return argon2.generateSalt(32).then(salt => { | ||
const hash = argon2.hashSync('password', salt); | ||
return argon2.verify(hash, 'password').then(t.pass); | ||
}); | ||
}).catch(t.threw); | ||
testHashSyncHighTimeCost (assert) { | ||
'use strict'; | ||
t.test('sync hash with argon2d', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
const hash = argon2.hashSync(password, salt, { | ||
argon2d: true | ||
}); | ||
t.match(hash, /\$argon2d\$/, 'Should use argon2d signature.'); | ||
t.equal(hash, hashes.argon2d); | ||
t.end(); | ||
}); | ||
assert.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
timeCost: 4294967297 | ||
}); | ||
}, /too high/); | ||
assert.done(); | ||
}, | ||
t.test('sync hash with truthy argon2d', t => { | ||
'use strict'; | ||
testHashSyncMemoryCost (assert) { | ||
'use strict'; | ||
const hash = argon2.hashSync(password, salt, { | ||
argon2d: 'foo' | ||
}); | ||
t.match(hash, /\$argon2d\$/, 'Should use argon2d signature.'); | ||
t.end(); | ||
}); | ||
assert.expect(1); | ||
t.test('sync hash with falsy argon2d', t => { | ||
'use strict'; | ||
const hash = argon2.hashSync(password, salt, { | ||
memoryCost: 13 | ||
}); | ||
assert.ok(/m=8192/.test(hash), 'Should have correct memory cost.'); | ||
assert.done(); | ||
}, | ||
const hash = argon2.hashSync(password, salt, { | ||
argon2d: '' | ||
}); | ||
t.match(hash, /\$argon2i\$/, 'Should not use argon2d signature.'); | ||
t.end(); | ||
}); | ||
testHashSyncInvalidMemoryCost (assert) { | ||
'use strict'; | ||
t.test('sync hash with invalid salt', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
t.throws(() => { | ||
argon2.hashSync(password, 'stringsalt'); | ||
}, /invalid salt.+must be a buffer/i); | ||
t.end(); | ||
}); | ||
assert.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
memoryCost: 'foo' | ||
}); | ||
}, /invalid/i); | ||
assert.done(); | ||
}, | ||
t.test('sync hash with short salt', t => { | ||
'use strict'; | ||
testHashSyncLowMemoryCost (assert) { | ||
'use strict'; | ||
t.throws(() => { | ||
argon2.hashSync(password, salt.slice(0, 7)); | ||
}, /invalid salt.+with 8 or more bytes/i); | ||
t.end(); | ||
}); | ||
assert.expect(1); | ||
t.test('sync hash with time cost', t => { | ||
'use strict'; | ||
assert.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
memoryCost: -4294967290 | ||
}); | ||
}, /too low/); | ||
assert.done(); | ||
}, | ||
const hash = argon2.hashSync(password, salt, { | ||
timeCost: 4 | ||
}); | ||
t.match(hash, /t=4/, 'Should have correct time cost.'); | ||
t.end(); | ||
}); | ||
testHashSyncHighMemoryCost (assert) { | ||
'use strict'; | ||
t.test('sync hash with invalid time cost', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
t.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
timeCost: 'foo' | ||
}); | ||
}, /invalid timeCost.+must be an integer/i); | ||
t.end(); | ||
}); | ||
assert.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
memoryCost: 32 | ||
}); | ||
}, /too high/); | ||
assert.done(); | ||
}, | ||
t.test('sync hash with low time cost', t => { | ||
'use strict'; | ||
testHashSyncParallelism (assert) { | ||
'use strict'; | ||
t.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
timeCost: limits.timeCost.min - 1 | ||
}); | ||
}, /invalid timeCost.+between \d+ and \d+/i); | ||
t.end(); | ||
}); | ||
assert.expect(1); | ||
t.test('sync hash with high time cost', t => { | ||
'use strict'; | ||
const hash = argon2.hashSync(password, salt, { | ||
parallelism: 2 | ||
t.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
timeCost: limits.timeCost.max + 1 | ||
}); | ||
assert.ok(/p=2/.test(hash), 'Should have correct parallelism.'); | ||
assert.done(); | ||
}, | ||
}, /invalid timeCost.+between \d+ and \d+/i); | ||
t.end(); | ||
}); | ||
testHashSyncInvalidParallelism (assert) { | ||
'use strict'; | ||
t.test('sync hash with memory cost', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
const hash = argon2.hashSync(password, salt, { | ||
memoryCost: 13 | ||
}); | ||
t.match(hash, /m=8192/, 'Should have correct memory cost.'); | ||
t.end(); | ||
}); | ||
assert.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
parallelism: 'foo' | ||
}); | ||
}, /invalid/i); | ||
assert.done(); | ||
}, | ||
t.test('sync hash with invalid memory cost', t => { | ||
'use strict'; | ||
testHashSyncLowParallelism (assert) { | ||
'use strict'; | ||
t.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
memoryCost: 'foo' | ||
}); | ||
}, /invalid memoryCost.+must be an integer/i); | ||
t.end(); | ||
}); | ||
assert.expect(1); | ||
t.test('sync hash with low memory cost', t => { | ||
'use strict'; | ||
assert.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
parallelism: -4294967290 | ||
}); | ||
}, /too low/); | ||
assert.done(); | ||
}, | ||
t.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
memoryCost: limits.memoryCost.min - 1 | ||
}); | ||
}, /invalid memoryCost.+between \d+ and \d+/i); | ||
t.end(); | ||
}); | ||
testHashSyncHighParallelism (assert) { | ||
'use strict'; | ||
t.test('sync hash with high memory cost', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
t.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
memoryCost: limits.memoryCost.max + 1 | ||
}); | ||
}, /invalid memoryCost.+between \d+ and \d+/i); | ||
t.end(); | ||
}); | ||
assert.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
parallelism: 4294967297 | ||
}); | ||
}, /too high/); | ||
assert.done(); | ||
}, | ||
t.test('sync hash with parallelism', t => { | ||
'use strict'; | ||
testHashSyncAllOptions (assert) { | ||
'use strict'; | ||
const hash = argon2.hashSync(password, salt, { | ||
parallelism: 2 | ||
}); | ||
t.match(hash, /p=2/, 'Should have correct parallelism.'); | ||
t.end(); | ||
}); | ||
assert.expect(1); | ||
t.test('sync hash with invalid parallelism', t => { | ||
'use strict'; | ||
const hash = argon2.hashSync(password, salt, { | ||
timeCost: 4, | ||
memoryCost: 13, | ||
parallelism: 2 | ||
t.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
parallelism: 'foo' | ||
}); | ||
assert.ok(/m=8192,t=4,p=2/.test(hash), 'Should have correct options.'); | ||
assert.done(); | ||
}, | ||
}, /invalid parallelism, must be an integer/i); | ||
t.end(); | ||
}); | ||
testHashSyncLongSalt (assert) { | ||
'use strict'; | ||
t.test('sync hash with low parallelism', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
t.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
parallelism: limits.parallelism.min - 1 | ||
}); | ||
}, /invalid parallelism.+between \d+ and \d+/i); | ||
t.end(); | ||
}); | ||
assert.throws(() => { | ||
argon2.hashSync(password, 'somesaltwaytoobig'); | ||
t.test('sync hash with high parallelism', t => { | ||
'use strict'; | ||
t.throws(() => { | ||
argon2.hashSync(password, salt, { | ||
parallelism: limits.parallelism.max + 1 | ||
}); | ||
assert.done(); | ||
}, | ||
}, /invalid parallelism.+between \d+ and \d+/i); | ||
t.end(); | ||
}); | ||
testGenerateSalt (assert) { | ||
'use strict'; | ||
t.test('sync hash with all options', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
const hash = argon2.hashSync(password, salt, { | ||
timeCost: 4, | ||
memoryCost: 13, | ||
parallelism: 2 | ||
}); | ||
t.match(hash, /m=8192,t=4,p=2/, 'Should have correct options.'); | ||
t.end(); | ||
}); | ||
argon2.generateSalt((err, salt) => { | ||
assert.ok(salt.length <= 16); | ||
assert.done(); | ||
}); | ||
}, | ||
t.test('async generate salt with default length', t => { | ||
'use strict'; | ||
testGenerateSaltSync (assert) { | ||
'use strict'; | ||
t.plan(1); | ||
assert.expect(1); | ||
return argon2.generateSalt().then(salt => { | ||
t.equal(salt.length, 16); | ||
}); | ||
}).catch(t.threw); | ||
assert.ok(argon2.generateSaltSync().length <= 16); | ||
assert.done(); | ||
}, | ||
t.test('async generate salt with specified length', t => { | ||
'use strict'; | ||
testVerifyOk (assert) { | ||
'use strict'; | ||
t.plan(1); | ||
assert.expect(1); | ||
return argon2.generateSalt(32).then(salt => { | ||
t.equal(salt.length, 32); | ||
}); | ||
}).catch(t.threw); | ||
argon2.verify(argon2.hashSync(password, argon2.generateSaltSync()), | ||
password, (err) => { | ||
assert.equal(undefined, err); | ||
assert.done(); | ||
}); | ||
}, | ||
t.test('sync generate salt with default length', t => { | ||
'use strict'; | ||
testVerifyFail (assert) { | ||
'use strict'; | ||
t.equal(argon2.generateSaltSync().length, 16); | ||
t.end(); | ||
}); | ||
assert.expect(1); | ||
t.test('sync generate salt with specified length', t => { | ||
'use strict'; | ||
argon2.verify(argon2.hashSync(password, argon2.generateSaltSync()), | ||
'passwolrd', (err) => { | ||
assert.ok(err, 'Error should be defined.'); | ||
assert.done(); | ||
}); | ||
}, | ||
t.equal(argon2.generateSaltSync(32).length, 32); | ||
t.end(); | ||
}); | ||
testVerifyArgon2dOk (assert) { | ||
'use strict'; | ||
t.test('async verify correct password', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
return argon2.generateSalt().then(salt => { | ||
return argon2.hash(password, salt).then(hash => { | ||
return argon2.verify(hash, password).then(t.pass); | ||
}); | ||
}); | ||
}).catch(t.threw); | ||
argon2.hash(password, argon2.generateSaltSync(), { | ||
argon2d: true | ||
}, (err, hash) => { | ||
argon2.verify(hash, password, (err) => { | ||
assert.equal(undefined, err); | ||
assert.done(); | ||
}); | ||
t.test('async verify wrong password', t => { | ||
'use strict'; | ||
return argon2.generateSalt().then(salt => { | ||
return argon2.hash(password, salt).then(hash => { | ||
return argon2.verify(hash, 'passworld').catch(t.pass); | ||
}); | ||
}, | ||
}); | ||
}).catch(t.threw); | ||
testVerifyArgon2dFail (assert) { | ||
'use strict'; | ||
t.test('async verify with null in password', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
return argon2.generateSalt().then(salt => { | ||
return argon2.hash('pass\0word', salt).then(hash => { | ||
return argon2.verify(hash, 'pass\0word').then(t.pass); | ||
}); | ||
}); | ||
}).catch(t.threw); | ||
argon2.hash(password, argon2.generateSaltSync(), { | ||
t.test('async verify argon2d correct password', t => { | ||
'use strict'; | ||
return argon2.generateSalt().then(salt => { | ||
return argon2.hash(password, salt, { | ||
argon2d: true | ||
}, (err, hash) => { | ||
argon2.verify(hash, 'passwolrd', (err) => { | ||
assert.ok(err, 'Error should be defined.'); | ||
assert.done(); | ||
}); | ||
}).then(hash => { | ||
return argon2.verify(hash, password).then(t.pass); | ||
}); | ||
}, | ||
}); | ||
}).catch(t.threw); | ||
testVerifySyncOk (assert) { | ||
'use strict'; | ||
t.test('async verify argon2d wrong password', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
return argon2.generateSalt().then(salt => { | ||
return argon2.hash(password, salt, { | ||
argon2d: true | ||
}).then(hash => { | ||
return argon2.verify(hash, 'passwolrd').catch(t.pass); | ||
}); | ||
}); | ||
}).catch(t.threw); | ||
assert.equal(true, argon2.verifySync(argon2.hashSync(password, | ||
argon2.generateSaltSync()), password)); | ||
assert.done(); | ||
}, | ||
t.test('sync verify correct password', t => { | ||
'use strict'; | ||
testVerifySyncFail (assert) { | ||
'use strict'; | ||
t.plan(1); | ||
assert.expect(1); | ||
return argon2.generateSalt().then(salt => { | ||
return argon2.hash(password, salt).then(hash => { | ||
t.true(argon2.verifySync(hash, password)); | ||
}); | ||
}); | ||
}).catch(t.threw); | ||
assert.equal(false, argon2.verifySync(argon2.hashSync(password, | ||
argon2.generateSaltSync()), 'passworld')); | ||
assert.done(); | ||
}, | ||
t.test('sync verify wrong password', t => { | ||
'use strict'; | ||
testVerifyArgon2dSyncOk (assert) { | ||
'use strict'; | ||
t.plan(1); | ||
assert.expect(1); | ||
return argon2.generateSalt().then(salt => { | ||
return argon2.hash(password, salt).then(hash => { | ||
t.false(argon2.verifySync(hash, 'passworld')); | ||
}); | ||
}); | ||
}).catch(t.threw); | ||
argon2.hash(password, argon2.generateSaltSync(), { | ||
t.test('sync verify with null in password', t => { | ||
'use strict'; | ||
t.plan(1); | ||
return argon2.generateSalt().then(salt => { | ||
return argon2.hash('pass\0word', salt).then(hash => { | ||
t.true(argon2.verifySync(hash, 'pass\0word')); | ||
}); | ||
}); | ||
}).catch(t.threw); | ||
t.test('sync verify argon2d correct password', t => { | ||
'use strict'; | ||
t.plan(1); | ||
return argon2.generateSalt().then(salt => { | ||
return argon2.hash(password, salt, { | ||
argon2d: true | ||
}, (err, hash) => { | ||
assert.equal(true, argon2.verifySync(hash, password)); | ||
assert.done(); | ||
}).then(hash => { | ||
t.true(argon2.verifySync(hash, password)); | ||
}); | ||
}, | ||
}); | ||
}).catch(t.threw); | ||
testVerifyArgon2dSyncFail (assert) { | ||
'use strict'; | ||
t.test('sync verify argon2d wrong password', t => { | ||
'use strict'; | ||
assert.expect(1); | ||
t.plan(1); | ||
argon2.hash(password, argon2.generateSaltSync(), { | ||
return argon2.generateSalt().then(salt => { | ||
return argon2.hash(password, salt, { | ||
argon2d: true | ||
}, (err, hash) => { | ||
assert.equal(false, argon2.verifySync(hash, 'passwolrd')); | ||
assert.done(); | ||
}).then(hash => { | ||
t.false(argon2.verifySync(hash, 'passwolrd')); | ||
}); | ||
} | ||
}; | ||
}); | ||
}).catch(t.threw); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
620
179
0
164076
4
28
2