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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mtproto2/crypto

v0.1.0

Published

Cryptographic primitives for MTProto 2.0 — AES-IGE, RSA-PAD, DH, PQ

Readme

@mtproto2/crypto

Cryptographic primitives for Telegram's MTProto 2.0 protocol.

All operations use the Node.js node:crypto built-in module. There are no external dependencies.

Installation

npm install @mtproto2/crypto

API

AES-256-IGE

AES in Infinite Garble Extension mode, used for MTProto message encryption.

import { aesIgeEncrypt, aesIgeDecrypt } from '@mtproto2/crypto';

// key: 32 bytes, iv: 32 bytes (first 16 = cipher IV, last 16 = plain IV)
// data must be 16-byte aligned
const encrypted = aesIgeEncrypt(data, key, iv);
const decrypted = aesIgeDecrypt(encrypted, key, iv);

AES-256-CTR

Streaming AES-CTR cipher, used for transport obfuscation.

import { AesCtr } from '@mtproto2/crypto';

// key: 32 bytes, iv: 16 bytes
const ctr = new AesCtr(key, iv);
const encrypted = ctr.encrypt(data);
const decrypted = ctr.decrypt(encrypted);

Each AesCtr instance maintains internal counter state. Create a new instance for each connection -- never reuse across different (key, IV) contexts.

RSA-PAD

MTProto RSA_PAD encryption scheme for auth key exchange.

import { rsaPad, TELEGRAM_RSA_KEYS } from '@mtproto2/crypto';

// data: up to 192 bytes, publicKey: { n: bigint, e: bigint }
const encrypted = rsaPad(data, TELEGRAM_RSA_KEYS[0]);

TELEGRAM_RSA_KEYS contains Telegram's official server RSA public keys used during the auth key generation step. These are hard-coded per the MTProto specification.

The RSA_PAD algorithm:

  1. Pads data to 192 bytes with random bytes
  2. Reverses the padded data
  3. Loops: generates a random temp_key, computes SHA-256 hash, AES-IGE encrypts, XORs keys
  4. Performs modular exponentiation with the RSA public key

SHA-1 and SHA-256

import { sha1, sha256 } from '@mtproto2/crypto';

// Accepts multiple buffers (concatenated before hashing)
const hash1 = sha1(data);            // 20 bytes
const hash2 = sha256(data1, data2);  // 32 bytes

Diffie-Hellman

import { modPow, isGoodPrime, isGoodGa } from '@mtproto2/crypto';

// Modular exponentiation: (base ^ exp) mod mod
const result = modPow(base, exp, mod);

// Validate DH prime (2048-bit, safe prime, valid g)
const primeOk = isGoodPrime(dhPrime, g);

// Validate g_a or g_b range
const gaOk = isGoodGa(ga, dhPrime);

isGoodPrime performs:

  • 2048-bit length check
  • Miller-Rabin primality test on dhPrime
  • Miller-Rabin primality test on (dhPrime - 1) / 2 (safe prime check)
  • Generator validation per the MTProto specification (g=2..7)

isGoodGa verifies:

  • 1 < g_a < dhPrime - 1
  • 2^(2048-64) < g_a < dhPrime - 2^(2048-64)

PQ Factorization

import { factorizePQ } from '@mtproto2/crypto';

// Factor a composite number into two primes [p, q] where p < q
const [p, q] = factorizePQ(pq);

Uses Pollard's rho algorithm. The pq value is a server-provided challenge during auth key exchange.

Key Derivation

import { deriveAesKeyIv } from '@mtproto2/crypto';

// MTProto 2.0 key derivation from auth_key and msg_key
// isClient: true for client->server (x=0), false for server->client (x=8)
const { key, iv } = deriveAesKeyIv(authKey, msgKey, isClient);

Auth Key Helpers

import { calcAuthKeyId, calcMsgKey } from '@mtproto2/crypto';

// auth_key_id = last 8 bytes of SHA-1(auth_key)
const authKeyId = calcAuthKeyId(authKey);

// msg_key = middle 16 bytes (bytes 8-24) of SHA-256(substr(auth_key, 88+x, 32) + plaintext)
const msgKey = calcMsgKey(authKey, plaintext, isClient);

Random Generation

import { randomBytes, randomBigInt } from '@mtproto2/crypto';

// Cryptographically secure random bytes
const bytes = randomBytes(32);

// Random bigint of exactly N bits (top bit always set)
const big = randomBigInt(2048);

Security Notes

  • All random generation uses crypto.randomBytes() from the Node.js node:crypto module. Math.random() is never used.
  • msg_key comparisons in the mtproto package use crypto.timingSafeEqual() to prevent timing attacks.
  • DH validation functions enforce the full set of checks specified by the MTProto protocol documentation.

License

MIT