npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@advena/web-timing-safe-equal

v1.0.4

Published

A timing-safe comparison function utilizing the 'Double HMAC validation pattern' with webcrypto, designed to operate in Node.JS, Edge, and Browser environments.

Downloads

3,577

Readme

Web Timing Safe Equal

A JavaScript library for timing-safe comparison of strings using the "Double HMAC verification" pattern. The library works in Node.js, Edge and Browser environments and uses the Subtle WebCrypto API under the hood.

Node.js
If you need a timing safe comparison function for Node.js only, then consider using the native crypto.timingSafeEqual implementation.

Installation

npm install @advena/web-timing-safe-equal

Usage

const { webTimingSafeEqual } = require("web-timing-safe-equal");

const left = "my secret value";
const right = "another secret value";

(async () => {
  const isEqual = await webTimingSafeEqual(left, right);
  console.log("Are the values equal?", isEqual); // false
})();

About web-timing-safe-equal

Inspiration

Node.JS has a native crypto.timingSafeEqual function for time constant comparison, which has been available since version 6 (2016).

However, there is no similar function for time safe comparison of values in web or edge environments. Cloudflare Workers runtime, upon which the Next.js Edge runtime is built, recently added the Node.js timingSafeEqual to their runtime as a non-standard extension. You can find more information in the Cloudflare Workers documentation. This means timingSafeEqual might be available in the latest Edge runtime.

There is a feature request with the Web3 Consortium to add a similar native function to the WebCrypto API. However, even if it is implemented, it may take years for browsers to support it.

Several alternative libraries, such as scmp and buffer-equal-constant-time, use the "Bitwise comparison with XOR" pattern. While this should work in theory, it may not be effective in practice due to potential time leaks caused by the way bits are implemented in JavaScript. Time-safe comparison with "Bitwise comparison with XOR" in JavaScript is difficult to implement and test, and it cannot be guaranteed to be secure. The ideal solution would be to implement a safe function at a lower level, outside of JavaScript.

In the meantime, we can use the "Double HMAC Verification" pattern as a common alternative for time-constant comparison. This pattern compares two HMACs: hmac(key, left) === hmac(key, right). In this case, it doesn't matter if === leaks length information, because the HMAC hashes constantly change. Therefore, even if the first byte of hmac(key, left) and hmac(key, right) matches, an attacker cannot rely on the assumption that they have correctly guessed it. Moving to the next byte will change the hash, effectively turning the attack into a brute-force attempt instead of a time-based one.

Performance

The webTimingSafeEqual function runs about 110 times slower than timingSafeEqual method. If you pre-generate a key or provide your own, then it's only 65 times slower than timingSafeEqual method.

crypto.timingSafeEqual('a','b') // fastest
(async()=>{
  await webTimingSafeEqual('a', 'b'); // 110 times slower

  const secretKey = await generateSecretKey();
  await webTimingSafeEqual('a', 'b', {secretKey}); // 65 times slower
})()

API

webTimingSafeEqual(left, right, [options])

Asynchronous method

  • left: (string | Uint8Array) - First value to compare
  • right: (string | Uint8Array) - Second value to compare
  • options: (object) - Optional configuration object
    • secretKey: (string | CryptoKey) - Optional HMAC key for comparison (default: auto-generated key)
    • keyLength: (integer) - Optional length in bytes of the auto-generated key (default: 64)
    • keyAlgorithm: ("SHA-1" | "SHA-256" | "SHA-384" | "SHA-512") - Optional hash algorithm for the key (default: "SHA-256")
    • hmacAlgorithm: ("SHA-1" | "SHA-256" | "SHA-384" | "SHA-512") - Optional hash algorithm for the HMAC (default: "SHA-256")

Returns a Promise that resolves to a boolean indicating whether the two values are equal.

generateSecretKey([options])

Asynchronous method

  • options: (object) - Optional configuration object
    • keyLength: (integer) - Length of key in bytes (default: 64)
    • algorithm: ("SHA-1" | "SHA-256" | "SHA-384" | "SHA-512") - Hash algorithm (default: "SHA-256")

Returns a Promise that resolves to a randomly generated HMAC secret key (CryptoKey).

hmac(secretKey, message, [algorithm])

Asynchronous method

  • secretKey: (string | Uint8Array | CryptoKey) - Secret key for HMAC computation
  • message: (string | Uint8Array) - Message to compute the HMAC for
  • algorithm: ("SHA-1" | "SHA-256" | "SHA-384" | "SHA-512") - Optional hash algorithm for HMAC (default: "SHA-256")

Returns a Promise that resolves to a hexadecimal digest of the HMAC computation.

Security

This library implements the "Double HMAC verification" pattern to provide a timing-safe comparison of strings. However, it is crucial to understand that the security of your application depends on various factors, and using this library alone does not guarantee your application is secure from timing attacks. Please consult a security expert if you have concerns about the security of your application.

Todo

I've built this package for personal use. However, If it should ever gain traction then I would consider adding:

  • tests
  • CJS/ESM dual build
  • rewrite in typescript and provide types
  • ...?

Disclaimer

Please note that I am not responsible for any errors or issues that may arise from using this package. By using this package, you acknowledge that you are using it at your own risk and that I cannot be held accountable for any problems or damages that may occur as a result of using this v. Please ensure that you have adequate backups and precautions in place before implementing or using this package in any production or critical environments.

I myself have used it on one large Next.js client project and have not seen any issues yet.