Open VityaSchel opened 8 months ago
I resolved this using custom service worker with WASM.
First, you need webpack or other bundler to bundle everything into single js file in service worker. Then install argon2-browser and use this code:
import argon2 from 'argon2-browser'
const crypto_pwhash_SALTBYTES = 16
const crypto_pwhash_MEMLIMIT_MODERATE = 268435456
const crypto_pwhash_OPSLIMIT_MODERATE = 3
const crypto_aead_xchacha20poly1305_ietf_KEYBYTES = 32
const channel = new BroadcastChannel('sw-messages')
self.addEventListener('message', async event => {
if(typeof event.data === 'object') {
if (event.data.type === 'hash' && 'plain' in event.data) {
const OLD_ENC_SALT = new Uint8Array(crypto_pwhash_SALTBYTES)
const result = await argon2.hash({
pass: event.data.plain,
salt: OLD_ENC_SALT,
time: crypto_pwhash_OPSLIMIT_MODERATE,
mem: crypto_pwhash_MEMLIMIT_MODERATE / 1024,
hashLen: crypto_aead_xchacha20poly1305_ietf_KEYBYTES,
parallelism: 1,
type: argon2.ArgonType.Argon2id
})
channel.postMessage({ type: 'hash_result', result, plain: event.data.plain })
}
}
})
Then build it into single file, import with service worker and you can use it like this on your website:
const hashChannel = new BroadcastChannel('sw-messages')
const plain = 'what you want to hash goes here'
const sw = navigator.serviceWorker.controller
if (!sw) return console.error('Service Worker not ready')
sw.postMessage({ type: 'hash', plain })
const subscription = (event: MessageEvent<{ type: 'hash_result', result: import('argon2-browser').Argon2BrowserHashResult, plain: string }>) => {
if (
typeof event.data === 'object'
&& event.data.type === 'hash_result'
&& 'result' in event.data
&& event.data.plain === plain
) {
hashChannel.removeEventListener('message', subscription)
resolve(event.data.result.hash)
}
}
hashChannel.addEventListener('message', subscription)
Oh and this is the config I used for webpack to correctly bundle wasm:
/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path')
const { IgnorePlugin } = require('webpack')
/** @type {import('webpack').Configuration} */
const config = {
mode: 'production',
entry: __dirname + '/index.ts',
output: {
path: path.resolve(__dirname, '../public'),
filename: 'custom-worker.js'
},
module: {
rules: [
{
test: /\.wasm$/,
type: 'javascript/auto',
use: [{
loader: 'base64-loader'
}]
}
],
noParse: /\.wasm$/
},
plugins: [
new IgnorePlugin({ resourceRegExp: /\/__tests__\// })
],
resolve: {
fallback: {
path: require.resolve('path-browserify'),
fs: false
}
}
}
module.exports = config
When using crypto_pwhash_MEMLIMIT_MODERATE/1024 memory (256 MiB), 3 iterations, it takes more than a second to hash and while it hashing, render loop is blocked and page is frozen I'm using service worker anyway, maybe use that here?