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

@ahextechnology/otp-generator

v1.0.3

Published

Repository containing Node.js code for TOTP and HOTP implementations for secure two-factor authentication.

Downloads

1

Readme

TOTP and HOTP Implementation

This package provides functionality to generate and verify Time-based One-Time Passwords (TOTP) and HMAC-based One-Time Passwords (HOTP) using the crypto module in Node.js. The implementation follows the RFC 4226 (HOTP) and RFC 6238 (TOTP) standards.

Installation

To use this package, you need to have Node.js installed. You can include this code in your project by copying the provided functions into a file, or by creating a module.

Usage

Configuration

You can configure the number of bytes, encoding, algorithm, number of digits, and step as needed:

const crypto = require('crypto');
let bytes = 10;
let encoding = 'base64';
let algorithm = 'sha1';
let digits = 6;
let step = 30;

Functions

generateSecret()

Generates a secret key for TOTP/HOTP.

function generateSecret() {
  const secret = crypto.randomBytes(bytes).toString(encoding);
  return secret;
}

generateTOTP(secret, time = null, digits, step)

Generates a TOTP based on the provided secret, time, number of digits, and step.

function generateTOTP(secret, time = null, digits, step) {
  const currentTime = time || Date.now();
  const timeInSeconds = Math.floor(currentTime / 1000);
  const counter = Buffer.alloc(8);
  let timeCounter = Math.floor(timeInSeconds / step);

  for (let i = counter.length - 1; i >= 0; i--) {
    counter[i] = timeCounter & 0xff;
    timeCounter = Math.floor(timeCounter / 256);
  }

  const hmac = crypto.createHmac(algorithm, Buffer.from(secret, encoding));
  hmac.update(counter);
  const hash = hmac.digest();

  const offset = hash[hash.length - 1] & 0xf;
  const binary =
    ((hash[offset] & 0x7f) << 24) |
    ((hash[offset + 1] & 0xff) << 16) |
    ((hash[offset + 2] & 0xff) << 8) |
    (hash[offset + 3] & 0xff);

  const mod = Math.pow(10, digits);
  const otp = binary % mod;
  return otp.toString().padStart(digits, '0');
}

verifyTOTP(secret, token, window = 0, digits, step)

Verifies a TOTP based on the provided secret, token, window, number of digits, and step.

function verifyTOTP(secret, token, window = 0, digits, step) {
  const currentTime = Math.floor(Date.now() / 1000);
  for (let i = -window; i <= window; i++) {
    const adjustedTime = currentTime + i * step;
    const totp = generateTOTP(secret, adjustedTime * 1000, digits, step);
    if (token === totp) {
      return true;
    }
  }
  return false;
}

generateHOTP(secret, counter, digits)

Generates an HOTP based on the provided secret, counter, and number of digits.

function generateHOTP(secret, counter, digits) {
  const hmac = crypto.createHmac(algorithm, Buffer.from(secret, encoding));
  const counterBuffer = Buffer.alloc(8);
  counterBuffer.writeUIntBE(counter, 0, 8);
  hmac.update(counterBuffer);
  const hash = hmac.digest();

  const offset = hash[hash.length - 1] & 0xf;
  const binary =
    ((hash[offset] & 0x7f) << 24) |
    ((hash[offset + 1] & 0xff) << 16) |
    ((hash[offset + 2] & 0xff) << 8) |
    (hash[offset + 3] & 0xff);

  const mod = Math.pow(10, digits);
  const otp = binary % mod;
  return otp.toString().padStart(digits, '0');
}

verifyHOTP(secret, token, counter, digits)

Verifies an HOTP based on the provided secret, token, counter, and number of digits.

function verifyHOTP(secret, token, counter, digits) {
  const hotp = generateHOTP(secret, counter, digits);
  return token === hotp;
}

Example Usage

const {
  generateSecret,
  generateTOTP,
  verifyTOTP,
  generateHOTP,
  verifyHOTP,
} = require('./path/to/this/module');

const secret = generateSecret();
console.log('Secret:', secret);

const totp = generateTOTP(secret, null, digits, step);
console.log('TOTP:', totp);

const isValidTOTP = verifyTOTP(secret, totp, 1, digits, step);
console.log('Is valid TOTP:', isValidTOTP);

const hotp = generateHOTP(secret, 1, digits);
console.log('HOTP:', hotp);

const isValidHOTP = verifyHOTP(secret, hotp, 1, digits);
console.log('Is valid HOTP:', isValidHOTP);

Explanation

  1. Why 8 Bytes for the Counter?

    • The HOTP and TOTP algorithms specify that the counter value used in the HMAC computation should be an 8-byte (64-bit) integer. This allows a very high number of possible one-time passwords and ensures that the counter can support a large range of values.
  2. Why Math.pow(10, digits)?

    • The base 10 is used because we are generating numeric OTPs. Raising 10 to the power of digits (e.g., 6) gives the range within which the OTP should fall (e.g., 0 to 999999 for a 6-digit OTP).

License

This module is available under the MIT License.