Comparing version 0.10.1 to 0.11.0
@@ -0,1 +1,12 @@ | ||
# 20160406 | ||
* Version 1.3 of Argon2 | ||
* Version number in encoded hash | ||
* Refactored low-level API | ||
* Visibility control for library symbols | ||
* Microsft Visual Studio solution | ||
* New bindings | ||
* Minor bug and warning fixes (no security issue) | ||
# 20151206 | ||
@@ -2,0 +13,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) | ||
[![Build status](https://ci.appveyor.com/api/projects/status/8nfwuwq55sgfkele?svg=true)](https://ci.appveyor.com/project/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) | ||
@@ -52,6 +53,6 @@ | ||
``` | ||
Usage: ./argon2 salt [-d] [-t iterations] [-m memory] [-p parallelism] | ||
Usage: ./argon2 salt [-d] [-t iterations] [-m memory] [-p parallelism] [-h hash length] [-e|-r] | ||
Password is read from stdin | ||
Parameters: | ||
salt The salt to use, at most 16 characters | ||
salt The salt to use, at least 8 characters | ||
-d Use Argon2d instead of Argon2i (which is the default) | ||
@@ -61,7 +62,11 @@ -t N Sets the number of iterations to N (default = 3) | ||
-p N Sets parallelism to N threads (default 1) | ||
-h N Sets hash output length to N bytes (default 32) | ||
-e Output only encoded hash | ||
-r Output only the raw bytes of the hash | ||
``` | ||
For example, to hash "password" using "somesalt" as a salt and doing 2 | ||
iterations, consuming 64 MiB, and using four parallel threads: | ||
iterations, consuming 64 MiB, using four parallel threads and an output hash | ||
of 24 bytes | ||
``` | ||
$ echo -n "password" | ./argon2 somesalt -t 2 -m 16 -p 4 | ||
$ echo -n "password" | ./argon2 somesalt -t 2 -m 16 -p 4 -h 24 | ||
Type: Argon2i | ||
@@ -71,5 +76,5 @@ Iterations: 2 | ||
Parallelism: 4 | ||
Hash: 4162f32384d8f4790bd994cb73c83a4a29f076165ec18af3cfdcf10a8d1b9066 | ||
Encoded: $argon2i$m=65536,t=2,p=4$c29tZXNhbHQAAAAAAAAAAA$QWLzI4TY9HkL2ZTLc8g6SinwdhZewYrzz9zxCo0bkGY | ||
0.271 seconds | ||
Hash: 45d7ac72e76f242b20b77b9bf9bf9d5915894e669a24e6c6 | ||
Encoded: $argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG | ||
0.188 seconds | ||
Verification ok | ||
@@ -204,3 +209,4 @@ ``` | ||
* [Haskell](https://hackage.haskell.org/package/argon2-1.0.0/docs/Crypto-Argon2.html) by [@ocharles](https://github.com/ocharles) | ||
* [Javascript](https://github.com/ranisalt/node-argon2), by [@ranisalt](https://github.com/ranisalt) | ||
* [JavaScript](https://github.com/ranisalt/node-argon2), by [@ranisalt](https://github.com/ranisalt) | ||
* [JavaScript](https://github.com/cjlarose/argon2-ffi), by [@cjlarose](https://github.com/cjlarose) | ||
* [JVM](https://github.com/phxql/argon2-jvm) by [@phXql](https://github.com/phxql) | ||
@@ -207,0 +213,0 @@ * [Lua](https://github.com/thibaultCha/lua-argon2) by [@thibaultCha](https://github.com/thibaultCha) |
@@ -12,4 +12,4 @@ import argon2 from './'; | ||
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' | ||
argon2i: '$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$iWh06vD8Fy27wf9npn6FXWiCX4K6pW6Ue1Bnzz07Z8A', | ||
argon2d: '$argon2d$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$2+JCoQtY/2x5F0VB9pEVP3xBNguWP1T25Ui0PtZuk8o' | ||
}); | ||
@@ -26,8 +26,10 @@ | ||
const hash = await argon2.hash(passwordWithNull, salt); | ||
t.equal(hash, '$argon2i$m=4096,t=3,p=1$c29tZXNhbHQ$tcauj48oAe6NE/VLzTawLTQtmX848wkNs1d7z53ahNE'); | ||
t.equal(hash, '$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$gk27gZBfGSSQTGxrg0xP9BjOw1pY1QMEdLcNe+t6N8Q'); | ||
}); | ||
t.test('hash with null in salt', async t => { | ||
const paramsLen = '$argon2i$v=19$m=4096,t=3,p=1'.length; | ||
const hash = await argon2.hash(password, saltWithNull); | ||
t.equal(hash.substring(23, 47), '$' + truncatedBase64(saltWithNull) + '$'); | ||
const saltBase64 = '$' + truncatedBase64(saltWithNull) + '$'; | ||
t.equal(hash.substring(paramsLen, paramsLen + 24), saltBase64); | ||
}); | ||
@@ -34,0 +36,0 @@ |
25
index.js
@@ -13,2 +13,6 @@ const bindings = require('bindings')('argon2'); | ||
const isValidHash = hash => { | ||
return /^\$argon2[di](\$v=\d+)?\$m=\d+,t=\d+,p=\d+(?:\$[a-zA-Z0-9+\/]+){2}$/.test(hash); | ||
}; | ||
const validate = (salt, options) => { | ||
@@ -22,2 +26,3 @@ 'use strict'; | ||
if (options.parallelism === 'auto') { | ||
/* istanbul ignore next */ | ||
options.parallelism = require('os').cpus().length; | ||
@@ -50,4 +55,6 @@ } | ||
validate(salt, options); | ||
return bindings.hash(plain, salt, options.timeCost, options.memoryCost, | ||
options.parallelism, options.argon2d); | ||
return new Promise((resolve, reject) => { | ||
return bindings.hash(plain, salt, options.timeCost, options.memoryCost, | ||
options.parallelism, options.argon2d, resolve, reject); | ||
}); | ||
} catch (err) { | ||
@@ -99,4 +106,4 @@ return Promise.reject(err); | ||
if (!Buffer.isBuffer(hash)) { | ||
hash = new Buffer(hash); | ||
if (!isValidHash(hash)) { | ||
return Promise.reject(new Error('Invalid hash, must be generated by Argon2.')); | ||
} | ||
@@ -108,3 +115,5 @@ | ||
return bindings.verify(hash, plain, /argon2d/.test(hash)); | ||
return new Promise((resolve, reject) => { | ||
bindings.verify(hash, plain, hash[7] === 'd', resolve, reject); | ||
}); | ||
}, | ||
@@ -117,4 +126,4 @@ | ||
if (!Buffer.isBuffer(hash)) { | ||
hash = new Buffer(hash); | ||
if (!isValidHash(hash)) { | ||
throw new Error('Invalid hash, must be generated by Argon2.'); | ||
} | ||
@@ -126,4 +135,4 @@ | ||
return bindings.verifySync(hash, plain, /argon2d/.test(hash)); | ||
return bindings.verifySync(new Buffer(hash), plain, hash[7] === 'd'); | ||
} | ||
}; |
{ | ||
"name": "argon2", | ||
"version": "0.10.1", | ||
"version": "0.11.0", | ||
"description": "An Argon2 library for Node", | ||
@@ -30,3 +30,3 @@ "main": "index.js", | ||
"bindings": "^1.2.1", | ||
"nan": "^2.2.0" | ||
"nan": "^2.2.1" | ||
}, | ||
@@ -36,3 +36,5 @@ "devDependencies": { | ||
"async-benchmark": "^1.0.1", | ||
"babel-tap": "^4.0.0", | ||
"babel-preset-es2015": "^6.6.0", | ||
"babel-preset-stage-3": "^6.5.0", | ||
"babel-tap": "^5.0.0", | ||
"xo": "^0.13.0" | ||
@@ -39,0 +41,0 @@ }, |
@@ -9,2 +9,5 @@ # 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] | ||
### Before installing | ||
**Don't forget to checkout submodules! Always `git clone --recursive` or run | ||
`git submodule update --init` after cloning.** | ||
You **MUST** have a **node-gyp** global install before proceeding with install, | ||
@@ -11,0 +14,0 @@ along with GCC >= 4.8 / Clang >= 3.3. On Windows, you must compile under Visual |
@@ -14,4 +14,4 @@ const argon2 = require('./index'); | ||
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' | ||
argon2i: '$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$iWh06vD8Fy27wf9npn6FXWiCX4K6pW6Ue1Bnzz07Z8A', | ||
argon2d: '$argon2d$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$2+JCoQtY/2x5F0VB9pEVP3xBNguWP1T25Ui0PtZuk8o' | ||
}); | ||
@@ -50,3 +50,3 @@ | ||
return argon2.hash('pass\0word', salt).then(hash => { | ||
t.equal(hash, '$argon2i$m=4096,t=3,p=1$c29tZXNhbHQ$tcauj48oAe6NE/VLzTawLTQtmX848wkNs1d7z53ahNE'); | ||
t.equal(hash, '$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$gk27gZBfGSSQTGxrg0xP9BjOw1pY1QMEdLcNe+t6N8Q'); | ||
}); | ||
@@ -61,4 +61,5 @@ }).catch(t.threw); | ||
return argon2.hash(password, saltWithNull).then(hash => { | ||
const saltBase64 = hash.substring(24, 46); | ||
t.equal(saltBase64, truncatedBase64(saltWithNull)); | ||
const paramsLen = '$argon2i$v=19$m=4096,t=3,p=1'.length; | ||
const saltBase64 = hash.substring(paramsLen, paramsLen + 24); | ||
t.equal(saltBase64, '$' + truncatedBase64(saltWithNull) + '$'); | ||
}); | ||
@@ -70,3 +71,3 @@ }).catch(t.threw); | ||
t.plan(1); | ||
t.plan(2); | ||
@@ -77,3 +78,3 @@ /* intentionally using a length that is not multiple of 3 */ | ||
t.match(hash, /.*\$.{667}\$/, 'Hash should use the entire salt'); | ||
return argon2.verify(hash, 'password').then(t.end); | ||
return argon2.verify(hash, 'password').then(t.ok); | ||
}); | ||
@@ -310,3 +311,3 @@ }); | ||
const hash = argon2.hashSync('pass\0word', salt); | ||
t.equal(hash, '$argon2i$m=4096,t=3,p=1$c29tZXNhbHQ$tcauj48oAe6NE/VLzTawLTQtmX848wkNs1d7z53ahNE'); | ||
t.equal(hash, '$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$gk27gZBfGSSQTGxrg0xP9BjOw1pY1QMEdLcNe+t6N8Q'); | ||
t.end(); | ||
@@ -319,4 +320,5 @@ }); | ||
const hash = argon2.hashSync(password, saltWithNull); | ||
const saltBase64 = hash.substring(24, 46); | ||
t.equal(saltBase64, truncatedBase64(saltWithNull)); | ||
const paramsLen = '$argon2i$v=19$m=4096,t=3,p=1'.length; | ||
const saltBase64 = hash.substring(paramsLen, paramsLen + 24); | ||
t.equal(saltBase64, '$' + truncatedBase64(saltWithNull) + '$'); | ||
t.end(); | ||
@@ -588,2 +590,17 @@ }); | ||
t.test('async verify invalid hash', t => { | ||
'use strict'; | ||
t.plan(1); | ||
return argon2.generateSalt().then(salt => { | ||
return argon2.hash(password, salt).then(hash => { | ||
/* cut just a piece of the hash making it invalid */ | ||
return argon2.verify(hash.slice(8), password).catch(err => { | ||
t.match(err.message, /invalid hash.+generated by argon2/i); | ||
}); | ||
}); | ||
}); | ||
}).catch(t.threw); | ||
t.test('async verify with null in password', t => { | ||
@@ -659,2 +676,17 @@ 'use strict'; | ||
t.test('sync verify invalid hash', t => { | ||
'use strict'; | ||
t.plan(1); | ||
return argon2.generateSalt().then(salt => { | ||
return argon2.hash(password, salt).then(hash => { | ||
/* cut just a piece of the hash making it invalid */ | ||
t.throws(() => { | ||
argon2.verifySync(hash.slice(8), password); | ||
}, /invalid hash.+generated by argon2/i); | ||
}); | ||
}); | ||
}).catch(t.threw); | ||
t.test('sync verify with null in password', t => { | ||
@@ -661,0 +693,0 @@ 'use strict'; |
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
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
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
868
213
168238
6
28
Updatednan@^2.2.1