Skip to content

"async" argon2 freezes the main event loop #62861

Description

@ChALkeR

Original detect from @deepview-autofix:

Image

To validate:

import { argon2, randomBytes } from 'node:crypto'

const parameters = {
  message: 'password',
  nonce: randomBytes(16),
  parallelism: 4,
  tagLength: 64,
  memory: 65536,
  passes: 1000, // the only thing changed from doc to demonstrate
};

console.log(`Start at ${new Date().toISOString()}`)
argon2('argon2id', parameters, () => {})
console.log(`Unblocked at ${new Date().toISOString()}`) // this takes 10 seconds on my Air

cc @panva perhaps?

Likely too complex for an autofix.

Also does not qualify to be a security bug, hence public.

Activity

  1. changed the title [-]async argon2 freezes the event loop[/-] [+]async argon2 freezes the main event loop[/+] on Apr 21, 2026
  2. changed the title [-]async argon2 freezes the main event loop[/-] [+]"async" argon2 freezes the main event loop[/+] on Apr 21, 2026
  3. added
    cryptoIssues and PRs related to the crypto subsystem.
    on Apr 21, 2026
  4. panva commented on Apr 21, 2026

    @panva
    Member

    FYI the API is still in

    Stability: 1.2 - Release candidate

    cc @jasnell @ranisalt

  5. ChALkeR commented on Apr 21, 2026

    @ChALkeR
    MemberAuthor

    FYI the API is still in

    Yes, I'm aware, and that's precisely why this is public!

  6. panva commented on Apr 21, 2026

    @panva
    Member

    Yes, I'm aware, and that's precisely why this is public!

    I'm aware that you're aware :) Just calling it out for clarity.

  7. panva commented on Apr 21, 2026

    @panva
    Member

    @ChALkeR what about the scrypt or PBKDF2 jobs?

  8. ChALkeR commented on Apr 21, 2026

    @ChALkeR
    MemberAuthor

    I'm aware that you're aware :) Just calling it out for clarity.

    It had "FYI" so I replied 😄

    @ChALkeR what about the scrypt or PBKDF2 jobs?

    @panva scrypt is fine:

    console.time('ASync')
    console.time('Sync')
    scrypt('password', 'salt', 64, { N: 2**18, maxmem: 2**30 }, () => console.timeEnd('ASync'))
    console.timeEnd('Sync')
    Sync: 0.4ms
    ASync: 416.924ms
    

    pbkdf2 is fine too:

    console.time('ASync')
    console.time('Sync')
    pbkdf2('secret', 'salt', 1e6, 64, 'sha512', () => console.timeEnd('ASync'))
    console.timeEnd('Sync')
    Sync: 0.117ms
    ASync: 201.389ms
    

    compare to argon2:

    console.time('ASync')
    console.time('Sync')
    argon2('argon2id', parameters, () => console.timeEnd('ASync'))
    console.timeEnd('Sync')

    passes=10 (parameters from doc example):

    Sync: 117.201ms
    ASync: 217.662ms
    

    passes=100:

    Sync: 974.533ms
    ASync: 2.034s
    

    passes=1000:

    Sync: 8.570s
    ASync: 16.860s
    

    It literally is just computed twice: once in sync, once in async, per every async call (at least judging from the numbers)

  9. added
    performanceIssues and PRs related to the performance of Node.js.
    on Apr 21, 2026
  10. added
    experimentalIssues and PRs related to experimental features.
    on Apr 21, 2026
  11. self-assigned this
    on Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

cryptoIssues and PRs related to the crypto subsystem.experimentalIssues and PRs related to experimental features.performanceIssues and PRs related to the performance of Node.js.securityIssues and PRs related to security.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions