digitalbazaar / forge

A native implementation of TLS in Javascript and tools to write crypto-based and network-heavy webapps
https://digitalbazaar.com/
Other
5.07k stars 784 forks source link

Forge pbkdf2 too slow compared to subtle.deriveBits #962

Open Gu7z opened 2 years ago

Gu7z commented 2 years ago

I had node-forge in my application for a long time but when the amount of information increased, the time to decrypt it increase too

I was searching alternatives for the node-forge library and found Web Crypto

The following code generated the same keys but with a huge time difference

const webCrypto = async () => {
  const keyMaterial = await window.crypto.subtle.importKey(
    'raw',
    Buffer.from('password', 'binary'),
    { name: 'PBKDF2' },
    false,
    ['deriveBits', 'deriveKey']
  )

  const keyAsArrayBuffer = await window.crypto.subtle.deriveBits(
    {
      name: 'PBKDF2',
      salt: Buffer.from('salt', 'binary'),
      iterations: 4500,
      hash: 'SHA-1'
    },
    keyMaterial,
    128 << 3
  )

  const keyAsUint8Array = new Uint8Array(keyAsArrayBuffer)

  const key = [...new Uint8Array(keyAsUint8Array)]
    .map((b) => b.toString(16).padStart(2, '0'))
    .join('')

  console.log(key)
}

const nodeForge = async () => {
  const key = forge.pkcs5.pbkdf2('password', 'salt', 4500, 128)
  console.log(forge.util.bytesToHex(key))
}

const cryptoTest = async () => {
  console.time('webCrypto')
  await webCrypto()
  console.timeEnd('webCrypto')

  console.time('nodeForge')
  await nodeForge()
  console.timeEnd('nodeForge')
}

cryptoTest()

The difference from my console image

am I implementing correctly node-forge or have I missed something?

Gu7z commented 2 years ago

Anyone? :eyes:

davidlehn commented 2 years ago

Without looking into it, I assume the performance difference is because the forge version is all in JavaScript and the webcrypto version is native. Forge will try to use native APIs in Node.js. But that code pre-dates webcrypto and it's never gained support for trying to use a webcrypto version if available.

I'm pretty sure in browsers the pure js forge version is going to be slow. 5x+ is unfortunate, but it is what it is. I'm sure the js code could be modernized and optimized. But since webcrypto support is so common, it's probably a better choice to just use that for most use cases.

If there's a desire to use the forge API across platforms but have it use webcrypto APIs if available, someone could likely write a patch to do that.