Comparing version 0.18.3 to 0.19.0
@@ -40,3 +40,3 @@ 'use strict' | ||
detail: 'The argon2 package now uses value of memory cost instead of exponent.\n' + | ||
`Replacing memoryCost ${exp} with 2**${exp}=${1 << exp}.\n` | ||
`Replacing memoryCost ${exp} with 2**${exp}=${1 << exp}.\n` | ||
}) | ||
@@ -47,15 +47,21 @@ options.memoryCost = 1 << exp | ||
if ('salt' in options) { | ||
return resolve() | ||
return resolve(options.salt) | ||
} | ||
crypto.randomBytes(16, (err, salt) => { | ||
/* istanbul ignore if */ | ||
if (err) { | ||
return reject(err) | ||
} | ||
options.salt = salt | ||
return resolve() | ||
return resolve(salt) | ||
}) | ||
}).then(() => { | ||
}).then(salt => { | ||
return new Promise((resolve, reject) => { | ||
bindings.hash(Buffer.from(plain), options, resolve, reject) | ||
bindings.hash(Buffer.from(plain), Object.assign(options, {salt}), (err, value) => { | ||
/* istanbul ignore if */ | ||
if (err) { | ||
return reject(err) | ||
} | ||
return resolve(value) | ||
}) | ||
}) | ||
@@ -67,12 +73,7 @@ }).then(hash => { | ||
const { | ||
type, version, memoryCost: m, timeCost: t, parallelism: p, salt | ||
} = options | ||
return phc.serialize({ | ||
id: type2string[options.type], | ||
version: options.version, | ||
params: { | ||
m: options.memoryCost, | ||
t: options.timeCost, | ||
p: options.parallelism | ||
}, | ||
salt: options.salt, | ||
hash | ||
id: type2string[type], version, params: {m, t, p}, salt, hash | ||
}) | ||
@@ -82,2 +83,13 @@ }) | ||
const needsRehash = (digest, options) => { | ||
options = Object.assign({}, defaults, options) | ||
const { | ||
version, params: {m: memoryCost, t: timeCost} | ||
} = phc.deserialize(digest) | ||
return +version !== +options.version || | ||
+memoryCost !== +options.memoryCost || | ||
+timeCost !== +options.timeCost | ||
} | ||
const verify = (digest, plain) => { | ||
@@ -99,3 +111,9 @@ const { | ||
} | ||
bindings.hash(Buffer.from(plain), options, resolve, reject) | ||
bindings.hash(Buffer.from(plain), options, (err, value) => { | ||
/* istanbul ignore if */ | ||
if (err) { | ||
return reject(err) | ||
} | ||
return resolve(value) | ||
}) | ||
}).then(expected => expected.equals(hash)) | ||
@@ -108,2 +126,3 @@ } | ||
hash, | ||
needsRehash, | ||
verify | ||
@@ -110,0 +129,0 @@ } |
{ | ||
"name": "argon2", | ||
"version": "0.18.3", | ||
"version": "0.19.0", | ||
"description": "An Argon2 library for Node", | ||
@@ -9,5 +9,6 @@ "main": "argon2.js", | ||
"benchmark": "node test/benchmark.js", | ||
"clean": "node-gyp clean && rm -rf coverage .nyc_output", | ||
"lint": "standard --verbose | snazzy", | ||
"test": "tsc -p . && node test/test-d.js && nyc --reporter=lcov jest" | ||
"clean": "node-gyp clean && rm -rf .nyc_output", | ||
"lint": "standard --verbose", | ||
"test": "mocha test/test.js", | ||
"test-ts": "tsc -p . && node test/test-d.js" | ||
}, | ||
@@ -34,3 +35,3 @@ "repository": { | ||
"any-promise": "^1.3.0", | ||
"bindings": "^1.2.1", | ||
"bindings": "^1.3.0", | ||
"nan": "^2.10.0" | ||
@@ -40,5 +41,4 @@ }, | ||
"@types/node": "^9.3.0", | ||
"jest": "^22.0.6", | ||
"nyc": "^11.0.1", | ||
"sandra": "^0.2.1", | ||
"mocha": "^5.1.1", | ||
"sandra": "^0.3.0", | ||
"typescript": "^2.1.5" | ||
@@ -48,3 +48,6 @@ }, | ||
"node": ">=6.0.0" | ||
}, | ||
"standard": { | ||
"env": "mocha" | ||
} | ||
} |
343
test/test.js
@@ -1,2 +0,2 @@ | ||
/* global expect, test */ | ||
const assert = require('assert') | ||
const argon2 = require('../argon2') | ||
@@ -7,5 +7,2 @@ const {defaults, limits} = argon2 | ||
// Like argon2's modified base64 implementation, expect function truncates any | ||
// trailing '=' characters for a more compact representation. | ||
// hashes for argon2i and argon2d with default options | ||
@@ -23,195 +20,227 @@ const hashes = Object.freeze({ | ||
test('defaults', () => { | ||
expect(defaults).toEqual({ | ||
hashLength: 32, | ||
timeCost: 3, | ||
memoryCost: 2 ** 12, | ||
parallelism: 1, | ||
type: argon2.argon2i, | ||
raw: false, | ||
version: 0x13 | ||
describe('Argon2', () => { | ||
it('defaults', () => { | ||
assert.deepStrictEqual({ | ||
hashLength: 32, | ||
timeCost: 3, | ||
memoryCost: 1 << 12, | ||
parallelism: 1, | ||
type: argon2.argon2i, | ||
raw: false, | ||
version: 0x13 | ||
}, defaults) | ||
}) | ||
}) | ||
test('basic hash', () => { | ||
return argon2.hash(password, {salt}).then(hash => { | ||
expect(hash).toBe(hashes.argon2i) | ||
}) | ||
}) | ||
describe('hash', () => { | ||
it('hash with argon2i', () => { | ||
return argon2.hash(password, {salt}).then(hash => { | ||
assert.strictEqual(hashes.argon2i, hash) | ||
}) | ||
}) | ||
test('hash with null in password', () => { | ||
return argon2.hash('pass\0word', {salt}).then(hash => { | ||
expect(hash).toBe(hashes.withNull) | ||
}) | ||
}) | ||
it('argon2i with raw hash', () => { | ||
return argon2.hash(password, {raw: true, salt}).then(hash => { | ||
assert(hashes.rawArgon2i.equals(hash)) | ||
}) | ||
}) | ||
test('with raw hash', () => { | ||
return argon2.hash(password, {raw: true, salt}).then(hash => { | ||
expect(hash).toEqual(hashes.rawArgon2i) | ||
}) | ||
}) | ||
it('hash with argon2d', () => { | ||
return argon2.hash(password, {type: argon2.argon2d, salt}).then(hash => { | ||
assert.strictEqual(hashes.argon2d, hash) | ||
}) | ||
}) | ||
test('with raw hash, null in password', () => { | ||
return argon2.hash('pass\0word', {raw: true, salt}).then(hash => { | ||
expect(hash).toEqual(hashes.rawWithNull) | ||
}) | ||
}) | ||
it('argon2d with raw hash', () => { | ||
return argon2.hash(password, {type: argon2.argon2d, raw: true, salt}).then(hash => { | ||
assert(hashes.rawArgon2d.equals(hash)) | ||
}) | ||
}) | ||
test('hash with argon2d', () => { | ||
return argon2.hash(password, {type: argon2.argon2d, salt}).then(hash => { | ||
expect(hash).toBe(hashes.argon2d) | ||
}) | ||
}) | ||
it('hash with argon2id', () => { | ||
return argon2.hash(password, {type: argon2.argon2id, salt}).then(hash => { | ||
assert.strictEqual(hashes.argon2id, hash) | ||
}) | ||
}) | ||
test('argon2d with raw hash', () => { | ||
return argon2.hash(password, {type: argon2.argon2d, raw: true, salt}).then(hash => { | ||
expect(hash).toEqual(hashes.rawArgon2d) | ||
}) | ||
}) | ||
it('argon2id with raw hash', () => { | ||
return argon2.hash(password, {type: argon2.argon2id, raw: true, salt}).then(hash => { | ||
assert(hashes.rawArgon2id.equals(hash)) | ||
}) | ||
}) | ||
test('hash with argon2id', () => { | ||
return argon2.hash(password, {type: argon2.argon2id, salt}).then(hash => { | ||
expect(hash).toBe(hashes.argon2id) | ||
}) | ||
}) | ||
it('hash with null in password', () => { | ||
return argon2.hash('pass\0word', {salt}).then(hash => { | ||
assert.strictEqual(hashes.withNull, hash) | ||
}) | ||
}) | ||
test('argon2id with raw hash', () => { | ||
return argon2.hash(password, {type: argon2.argon2id, raw: true, salt}).then(hash => { | ||
expect(hash).toEqual(hashes.rawArgon2id) | ||
}) | ||
}) | ||
test('hash with time cost', () => { | ||
return argon2.hash(password, {timeCost: 4}).then(hash => { | ||
expect(hash).toMatch(/t=4/) | ||
it('with raw hash, null in password', () => { | ||
return argon2.hash('pass\0word', {raw: true, salt}).then(hash => { | ||
assert(hashes.rawWithNull.equals(hash)) | ||
}) | ||
}) | ||
}) | ||
}) | ||
test('hash with low time cost', () => { | ||
return argon2.hash(password, {timeCost: limits.timeCost.min - 1}).catch(err => { | ||
expect(err.message).toMatch(/invalid timeCost.+between \d+ and \d+/i) | ||
}) | ||
}) | ||
describe('set options', () => { | ||
it('hash with time cost', () => { | ||
return argon2.hash(password, {timeCost: 4}).then(hash => { | ||
assert(/t=4/.test(hash)) | ||
}) | ||
}) | ||
test('hash with high time cost', () => { | ||
return argon2.hash(password, {timeCost: limits.timeCost.max + 1}).catch(err => { | ||
expect(err.message).toMatch(/invalid timeCost.+between \d+ and \d+/i) | ||
}) | ||
}) | ||
it('hash with low time cost', () => { | ||
return argon2.hash(password, {timeCost: limits.timeCost.min - 1}).catch(err => { | ||
assert(/invalid timeCost.+between \d+ and \d+/i.test(err.message)) | ||
}) | ||
}) | ||
test('hash with hash length', () => { | ||
// 4 bytes ascii == 6 bytes base64 | ||
return argon2.hash(password, {hashLength: 4}).catch(err => { | ||
expect(err.message).toMatch(/\$\w{6}$/) | ||
}) | ||
}) | ||
it('hash with high time cost', () => { | ||
return argon2.hash(password, {timeCost: limits.timeCost.max + 1}).catch(err => { | ||
assert(/invalid timeCost.+between \d+ and \d+/i.test(err.message)) | ||
}) | ||
}) | ||
test('hash with low hash length', () => { | ||
return argon2.hash(password, {hashLength: limits.hashLength.min - 1}).catch(err => { | ||
expect(err.message).toMatch(/invalid hashLength.+between \d+ and \d+/i) | ||
}) | ||
}) | ||
it('hash with hash length', () => { | ||
// 4 bytes ascii == 6 bytes base64 | ||
return argon2.hash(password, {hashLength: 4}).catch(err => { | ||
assert(/\$\w{6}$/.test(err.message)) | ||
}) | ||
}) | ||
test('hash with high hash length', () => { | ||
return argon2.hash(password, {hashLength: limits.hashLength.max + 1}).catch(err => { | ||
expect(err.message).toMatch(/invalid hashLength.+between \d+ and \d+/i) | ||
}) | ||
}) | ||
it('hash with low hash length', () => { | ||
return argon2.hash(password, {hashLength: limits.hashLength.min - 1}).catch(err => { | ||
assert(/invalid hashLength.+between \d+ and \d+/i.test(err.message)) | ||
}) | ||
}) | ||
test('hash with memory cost', () => { | ||
return argon2.hash(password, {memoryCost: 2 ** 13}).then(hash => { | ||
expect(hash).toMatch(/m=8192/) | ||
}) | ||
}) | ||
it('hash with high hash length', () => { | ||
return argon2.hash(password, {hashLength: limits.hashLength.max + 1}).catch(err => { | ||
assert(/invalid hashLength.+between \d+ and \d+/i.test(err.message)) | ||
}) | ||
}) | ||
test('hash with low memory cost', () => { | ||
return argon2.hash(password, {memoryCost: limits.memoryCost.min / 2}).catch(err => { | ||
expect(err.message).toMatch(/invalid memoryCost.+between \d+ and \d+/i) | ||
}) | ||
}) | ||
it('hash with memory cost', () => { | ||
return argon2.hash(password, {memoryCost: 1 << 13}).then(hash => { | ||
assert(/m=8192/.test(hash)) | ||
}) | ||
}) | ||
test('hash with high memory cost', () => { | ||
return argon2.hash(password, {memoryCost: limits.memoryCost.max * 2}).catch(err => { | ||
expect(err.message).toMatch(/invalid memoryCost.+between \d+ and \d+/i) | ||
}) | ||
}) | ||
it('hash with low memory cost', () => { | ||
return argon2.hash(password, {memoryCost: limits.memoryCost.min / 2}).catch(err => { | ||
assert(/invalid memoryCost.+between \d+ and \d+/i.test(err.message)) | ||
}) | ||
}) | ||
test('hash with parallelism', () => { | ||
return argon2.hash(password, {parallelism: 2}).then(hash => { | ||
expect(hash).toMatch(/p=2/) | ||
}) | ||
}) | ||
it('hash with high memory cost', () => { | ||
return argon2.hash(password, {memoryCost: limits.memoryCost.max * 2}).catch(err => { | ||
assert(/invalid memoryCost.+between \d+ and \d+/i.test(err.message)) | ||
}) | ||
}) | ||
test('hash with low parallelism', () => { | ||
return argon2.hash(password, {parallelism: limits.parallelism.min - 1}).catch(err => { | ||
expect(err.message).toMatch(/invalid parallelism.+between \d+ and \d+/i) | ||
}) | ||
}) | ||
it('hash with parallelism', () => { | ||
return argon2.hash(password, {parallelism: 2}).then(hash => { | ||
assert(/p=2/.test(hash)) | ||
}) | ||
}) | ||
test('hash with high parallelism', () => { | ||
return argon2.hash(password, {parallelism: limits.parallelism.max + 1}).catch(err => { | ||
expect(err.message).toMatch(/invalid parallelism.+between \d+ and \d+/i) | ||
}) | ||
}) | ||
it('hash with low parallelism', () => { | ||
return argon2.hash(password, {parallelism: limits.parallelism.min - 1}).catch(err => { | ||
assert(/invalid parallelism.+between \d+ and \d+/i.test(err.message)) | ||
}) | ||
}) | ||
test('hash with all options', () => { | ||
return argon2.hash(password, {timeCost: 4, memoryCost: 2 ** 13, parallelism: 2}).then(hash => { | ||
expect(hash).toMatch(/m=8192,t=4,p=2/) | ||
}) | ||
}) | ||
it('hash with high parallelism', () => { | ||
return argon2.hash(password, {parallelism: limits.parallelism.max + 1}).catch(err => { | ||
assert(/invalid parallelism.+between \d+ and \d+/i.test(err.message)) | ||
}) | ||
}) | ||
test('verify correct password', () => { | ||
return argon2.hash(password).then(hash => { | ||
return argon2.verify(hash, password).then(matches => { | ||
expect(matches).toBeTruthy() | ||
it('hash with all options', () => { | ||
return argon2.hash(password, {timeCost: 4, memoryCost: 1 << 13, parallelism: 2}).then(hash => { | ||
assert(/m=8192,t=4,p=2/.test(hash)) | ||
}) | ||
}) | ||
}) | ||
}) | ||
test('verify wrong password', () => { | ||
return argon2.hash(password).then(hash => { | ||
return argon2.verify(hash, 'passworld').then(matches => { | ||
expect(matches).toBeFalsy() | ||
describe('needsRehash', () => { | ||
it('needs rehash old version', () => { | ||
return argon2.hash(password, {version: 0x10}).then(hash => { | ||
assert(argon2.needsRehash(hash)) | ||
assert(!argon2.needsRehash(hash, {version: 0x10})) | ||
}) | ||
}) | ||
}) | ||
}) | ||
test('verify with null in password', () => { | ||
return argon2.hash('pass\0word').then(hash => { | ||
return argon2.verify(hash, 'pass\0word').then(matches => { | ||
expect(matches).toBeTruthy() | ||
it('needs rehash low memory cost', () => { | ||
return argon2.hash(password, {memoryCost: defaults.memoryCost / 2}).then(hash => { | ||
assert(argon2.needsRehash(hash)) | ||
assert(!argon2.needsRehash(hash, {memoryCost: defaults.memoryCost / 2})) | ||
}) | ||
}) | ||
}) | ||
}) | ||
test('verify argon2d correct password', () => { | ||
return argon2.hash(password, {type: argon2.argon2d}).then(hash => { | ||
return argon2.verify(hash, password).then(matches => { | ||
expect(matches).toBeTruthy() | ||
it('needs rehash low time cost', () => { | ||
return argon2.hash(password, {timeCost: defaults.timeCost - 1}).then(hash => { | ||
assert(argon2.needsRehash(hash)) | ||
assert(!argon2.needsRehash(hash, {timeCost: defaults.timeCost - 1})) | ||
}) | ||
}) | ||
}) | ||
}) | ||
test('verify argon2d wrong password', () => { | ||
return argon2.hash(password, {type: argon2.argon2d}).then(hash => { | ||
return argon2.verify(hash, 'passworld').then(matches => { | ||
expect(matches).toBeFalsy() | ||
describe('verify', () => { | ||
it('verify correct password', () => { | ||
return argon2.hash(password).then(hash => { | ||
return argon2.verify(hash, password).then(matches => { | ||
assert(matches) | ||
}) | ||
}) | ||
}) | ||
}) | ||
}) | ||
test('verify argon2id correct password', () => { | ||
return argon2.hash(password, {type: argon2.argon2id}).then(hash => { | ||
return argon2.verify(hash, password).then(matches => { | ||
expect(matches).toBeTruthy() | ||
it('verify wrong password', () => { | ||
return argon2.hash(password).then(hash => { | ||
return argon2.verify(hash, 'passworld').then(matches => { | ||
assert(!matches) | ||
}) | ||
}) | ||
}) | ||
}) | ||
}) | ||
test('verify argon2id wrong password', () => { | ||
return argon2.hash(password, {type: argon2.argon2id}).then(hash => { | ||
return argon2.verify(hash, 'passworld').then(matches => { | ||
expect(matches).toBeFalsy() | ||
it('verify with null in password', () => { | ||
return argon2.hash('pass\0word').then(hash => { | ||
return argon2.verify(hash, 'pass\0word').then(matches => { | ||
assert(matches) | ||
}) | ||
}) | ||
}) | ||
it('verify argon2d correct password', () => { | ||
return argon2.hash(password, {type: argon2.argon2d}).then(hash => { | ||
return argon2.verify(hash, password).then(matches => { | ||
assert(matches) | ||
}) | ||
}) | ||
}) | ||
it('verify argon2d wrong password', () => { | ||
return argon2.hash(password, {type: argon2.argon2d}).then(hash => { | ||
return argon2.verify(hash, 'passworld').then(matches => { | ||
assert(!matches) | ||
}) | ||
}) | ||
}) | ||
it('verify argon2id correct password', () => { | ||
return argon2.hash(password, {type: argon2.argon2id}).then(hash => { | ||
return argon2.verify(hash, password).then(matches => { | ||
assert(matches) | ||
}) | ||
}) | ||
}) | ||
it('verify argon2id wrong password', () => { | ||
return argon2.hash(password, {type: argon2.argon2id}).then(hash => { | ||
return argon2.verify(hash, 'passworld').then(matches => { | ||
assert(!matches) | ||
}) | ||
}) | ||
}) | ||
}) | ||
}) |
Sorry, the diff of this file is too big to display
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
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
4
315836
3571
Updatedbindings@^1.3.0