Update Argon2 Browser

This commit is contained in:
Sven Seeberg 2020-10-20 19:09:14 +02:00
parent 670e002430
commit 1122e63756
Signed by: sven.seeberg
GPG key ID: 29559DD5A83806B5
7 changed files with 58 additions and 62 deletions

View file

@ -10,15 +10,17 @@ Argon2 is a password-hashing function, the winner of Password Hashing Competitio
## The numbers
| | Time, ms (lower is better) |
|----------------|----------------------------|
| Chrome WASM | 360 |
| Firefox WASM | 340 |
| Safari WASM | 310 |
| Native -O3 SSE | 90 |
| Native -O3 | 140 |
| Native -O1 | 300 |
| Native -O0 | 750 |
| | Time, ms (lower is better) |
|-------------------|----------------------------|
| Chrome WASM | 225 |
| Chrome WASM+SIMD | 119 |
| Firefox WASM | 195 |
| Firefox WASM+SIMD | 135 |
| Safari WASM | 174 |
| Native -O3 SSE | 15 |
| Native -O3 | 42 |
| Native -O1 | 55 |
| Native -O0 | 395 |
## Test Environment
@ -33,56 +35,45 @@ Algorithm parameters (`-d -t 100 -m 10 -p 1`):
Environment:
- MacBook pro, Intel Core i5, 2.5GHz (x64), macOS 10.14.6 (18G95)
- Chrome 76.0.3809.100 (Official Build)
- Firefox 69.0.1
- Savari v13.0 (14608.1.49)
- native argon2 compiled from https://github.com/P-H-C/phc-winner-argon2 @4844d2f
- MacBook pro 2020, Intel Core i7, 2.3GHz (x64), macOS 10.14.6 (18G95)
- Chrome 85.0.4183.83 (Official Build)
- Firefox 80.0.1
- Safari 13.1.2 (15609.3.5.1.3)
- native argon2 compiled from https://github.com/P-H-C/phc-winner-argon2 @440ceb9
## Code size
| File | Code size, kB |
|-------------|---------------|
| argon2.js | 16 |
| argon2.wasm | 31 |
| argon2.wasm | 25 |
## Is Argon2 modified?
The only change is [disabling threading support](https://github.com/antelle/argon2-browser/commit/4b8950395c8c03a888ba6f417a4001458cdd3231).
## Difficulties
## SIMD
Argon2 is using uint64, which is not supported by JavaScript.
This function is called ~30M times per one iteration:
```cpp
uint64_t fBlaMka(uint64_t x, uint64_t y) {
const uint64_t m = UINT64_C(0xFFFFFFFF);
const uint64_t xy = (x & m) * (y & m);
return x + y + 2 * xy;
}
```
SIMD is not quite here in WebAssembly, however for those who would like to give it a try,
we already provide a working build with SIMD. At the moment it works only in Chrome,
to be able to use it, you need to either add
[this origin trial](https://developers.chrome.com/origintrials/#/view_trial/-4708513410415853567) to your website,
or enable the SIMD feature in Chrome flags.
And this one:
```cpp
uint64_t rotr64(const uint64_t w, const unsigned c) {
return (w >> c) | (w << (64 - c));
}
```
More about WebAssembly SIMD support in V8: https://v8.dev/features/simd
In C++, we can make use of SSE for 64-bit arithmetics. In JavaScript, when no 64-bit unsigned long type is available, different engines have different time penalties of this operation.
On Firefox you need to enable `javascript.options.wasm_simd` option in about:config.
WASM can support 64-bit integers but it requires compilation with LLVM, and not as asm.js => wasm. But this build is producing bad wasm for now. A simple experiment can be found in [perf-test.c](perf-test.c): compiling it with i64 support in LLVM gives us 4x boost.
To use the SIMD version, load `argon2-simd.wasm` instead of `argon2.wasm`.
## JS Library
Until WASM is mature, js library is using only asm.js. Here's how to try it.
Install with npm:
The library can be installed from npm:
```bash
npm install argon2-browser
```
Add script to your HTML:
Then add script to your HTML or use your favorite bundler:
```html
<script src="node_modules/argon2-browser/lib/argon2.js"></script>
```
@ -101,7 +92,6 @@ argon2.verify({ pass: 'password', encoded: 'enc-hash' })
.catch(e => console.error(e.message, e.code))
```
Bring your own bundler and promise polyfill.
Other parameters:
```javascript
argon2.hash({
@ -116,7 +106,6 @@ argon2.hash({
secret: new Uint8Array([...]), // optional secret data
ad: new Uint8Array([...]), // optional associated data
type: argon2.ArgonType.Argon2d, // or argon2.ArgonType.Argon2i
distPath: '' // asm.js script location, without trailing slash
})
// result
.then(res => {
@ -142,11 +131,11 @@ You can use this module in several ways:
## Node.js support
Of course you [can use](examples/node) generated asm.js code in node.js but it's not sensible: you will get much better speed by compiling native node.js addon, which is not that hard. Wait, it's already done, just install [this package](https://github.com/ranisalt/node-argon2).
Of course you [can use](examples/node) generated WASM in node.js, but it's not sensible: you will get much better speed by compiling it as a native node.js addon, which is not that hard. Wait, it's already done, just install [this package](https://github.com/ranisalt/node-argon2).
## Is it used anywhere?
It is! [KeeWeb](https://github.com/keeweb/keeweb) (web-based password manager) is using both asm.js and WebAssembly Argon2 implementations.
It is! [KeeWeb](https://github.com/keeweb/keeweb) (web-based password manager) is using it as a password hashing function implementation.
[Check out the source code](https://github.com/keeweb/keeweb/blob/develop/app/scripts/util/kdbxweb/kdbxweb-init.js#L11), if you're interested.
## Building
@ -156,7 +145,7 @@ You can build everything with
./build.sh
```
Prerequesties:
Prerequisites:
- emscripten with WebAssembly support ([howto](http://webassembly.org/getting-started/developers-guide/))
- CMake

BIN
node_modules/argon2-browser/dist/argon2-simd.wasm generated vendored Executable file

Binary file not shown.

File diff suppressed because one or more lines are too long

BIN
node_modules/argon2-browser/dist/argon2.wasm generated vendored Normal file → Executable file

Binary file not shown.

View file

@ -103,14 +103,14 @@
}
function createWasmMemory(mem) {
const KB = 1024 * 1024;
const KB = 1024;
const MB = 1024 * KB;
const GB = 1024 * MB;
const WASM_PAGE_SIZE = 64 * 1024;
const WASM_PAGE_SIZE = 64 * KB;
const totalMemory = (2 * GB - 64 * KB) / 1024 / WASM_PAGE_SIZE;
const totalMemory = (2 * GB - 64 * KB) / WASM_PAGE_SIZE;
const initialMemory = Math.min(
Math.max(Math.ceil((mem * 1024) / WASM_PAGE_SIZE), 256) + 256,
Math.max(Math.ceil((mem * KB) / WASM_PAGE_SIZE), 256) + 256,
totalMemory
);
@ -173,6 +173,7 @@
const saltEncoded = encodeUtf8(params.salt);
const salt = allocateArrayStr(Module, saltEncoded);
const saltlen = saltEncoded.length;
const argon2Type = params.type || ArgonType.Argon2d;
const hash = Module.allocate(
new Array(params.hashLen || 24),
'i8',
@ -185,13 +186,19 @@
const ad = params.ad ? allocateArray(Module, params.ad) : 0;
const adlen = params.ad ? params.ad.byteLength : 0;
const hashlen = params.hashLen || 24;
const encodedlen = Module._argon2_encodedlen(
tCost,
mCost,
parallelism,
saltlen,
hashlen,
argon2Type
);
const encoded = Module.allocate(
new Array(512),
new Array(encodedlen + 1),
'i8',
Module.ALLOC_NORMAL
);
const encodedlen = 512;
const argon2Type = params.type || ArgonType.Argon2d;
const version = 0x13;
let err;
let res;

View file

@ -1,8 +1,8 @@
{
"_from": "argon2-browser",
"_id": "argon2-browser@1.14.0",
"_id": "argon2-browser@1.15.2",
"_inBundle": false,
"_integrity": "sha512-Y/sIQd15JsDXMOFC+bWaq7JfCLwem13duG/gpFf0VKusIwCfgrKUdMoRv2w4t+Z+zZgLYyltd0Jp9A278SAG/Q==",
"_integrity": "sha512-kn9rs/+dZk0K4L9Vj8ZDdNw+s9vTYvmHCi8TT7z5OHeoFEwJnElZioICNLWXCve9sHc0d6TfeD0b1GKcscsuwg==",
"_location": "/argon2-browser",
"_phantomChildren": {},
"_requested": {
@ -19,10 +19,10 @@
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/argon2-browser/-/argon2-browser-1.14.0.tgz",
"_shasum": "cd173f5f5e4ebe6bdb9bc54492949e216456b415",
"_resolved": "https://registry.npmjs.org/argon2-browser/-/argon2-browser-1.15.2.tgz",
"_shasum": "1d37c0ef3eac357b6571297cbaf9958aa62eb0d6",
"_spec": "argon2-browser",
"_where": "/home/sven/Code/wahlgang-id",
"_where": "/home/sven/Code/nb-abstimm-id",
"author": {
"name": "Antelle"
},
@ -35,9 +35,9 @@
"devDependencies": {
"chai": "^4.2.0",
"http-server": "^0.12.3",
"mocha": "^8.1.1",
"prettier": "^2.0.5",
"puppeteer": "^5.2.1"
"mocha": "^8.1.3",
"prettier": "^2.1.2",
"puppeteer": "^5.3.1"
},
"directories": {
"doc": "docs",
@ -55,5 +55,5 @@
"prepare-deployment": "node ci/prepare-deployment",
"test": "mocha"
},
"version": "1.14.0"
"version": "1.15.2"
}

6
package-lock.json generated
View file

@ -3,9 +3,9 @@
"lockfileVersion": 1,
"dependencies": {
"argon2-browser": {
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/argon2-browser/-/argon2-browser-1.14.0.tgz",
"integrity": "sha512-Y/sIQd15JsDXMOFC+bWaq7JfCLwem13duG/gpFf0VKusIwCfgrKUdMoRv2w4t+Z+zZgLYyltd0Jp9A278SAG/Q=="
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/argon2-browser/-/argon2-browser-1.15.2.tgz",
"integrity": "sha512-kn9rs/+dZk0K4L9Vj8ZDdNw+s9vTYvmHCi8TT7z5OHeoFEwJnElZioICNLWXCve9sHc0d6TfeD0b1GKcscsuwg=="
}
}
}