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

@localonlytools/pdf-decrypt

v1.0.1

Published

Full-featured PDF decryption with AES-256 and RC4 support. Forked from @pdfsmaller/pdf-decrypt.

Downloads

382

Readme

@localonlytools/pdf-decrypt

Fork notice: This is a fork of @pdfsmaller/pdf-decrypt by PDFSmaller.com. All credit for the original work goes to the original author.

Full-featured PDF decryption with AES-256, AES-128, and RC4 support. Built for browsers, Node.js 18+, Cloudflare Workers, and Deno.

This package powers the PDF tools on Local Only Tools — a privacy-focused collection of browser-based utilities where all processing happens entirely on your device. No data is ever transmitted to a server. Check out the full suite of tools at localonly.tools, including PDF Merge, PDF Split, PDF Compress, and PDF Redact.

Features

  • AES-256 decryption (V=5, R=6) — PDF 2.0 standard
  • AES-128 decryption (V=4, R=4) — PDF 1.6+ standard
  • RC4 40/128-bit decryption (V=1-2, R=2-3) — legacy support
  • User + Owner passwords — accepts either password to decrypt
  • Batched async decryption — processes thousands of objects without browser freeze
  • Web Crypto API — no native dependencies, works everywhere
  • Lightweight — ~18KB total (crypto + decryption logic)
  • Zero dependencies — only pdf-lib as a peer dependency
  • TypeScript types included

Installation

npm install @localonlytools/pdf-decrypt pdf-lib

Quick Start

import { decryptPDF } from '@localonlytools/pdf-decrypt';
import fs from 'fs';

const pdfBytes = fs.readFileSync('encrypted.pdf');
const decrypted = await decryptPDF(new Uint8Array(pdfBytes), 'my-password');
fs.writeFileSync('decrypted.pdf', decrypted);

API

decryptPDF(pdfBytes, password)

Decrypt a password-protected PDF. Supports AES-256, AES-128, and RC4 encryption — the algorithm is detected automatically.

| Parameter | Type | Description | |-----------|------|-------------| | pdfBytes | Uint8Array | The encrypted PDF file as bytes | | password | string | The user or owner password |

Returns: Promise<Uint8Array> — The decrypted PDF bytes

Throws:

  • "This PDF is not encrypted" — if the PDF has no encryption dictionary
  • "Incorrect password" — if neither user nor owner password matches
  • "Unsupported encryption" — if the encryption version is not supported

isEncrypted(pdfBytes)

Check if a PDF is encrypted without attempting to decrypt it.

| Parameter | Type | Description | |-----------|------|-------------| | pdfBytes | Uint8Array | The PDF file as bytes |

Returns: Promise<{ encrypted: boolean, algorithm?: 'AES-256' | 'AES-128' | 'RC4', version?: number, revision?: number, keyLength?: number }>

Examples

Decrypt with Auto-Detection

import { decryptPDF, isEncrypted } from '@localonlytools/pdf-decrypt';

// Check encryption type first
const info = await isEncrypted(pdfBytes);
if (info.encrypted) {
  console.log(`Encrypted with ${info.algorithm}`);
  const decrypted = await decryptPDF(pdfBytes, password);
}

Roundtrip with @pdfsmaller/pdf-encrypt

import { encryptPDF } from '@pdfsmaller/pdf-encrypt';
import { decryptPDF } from '@localonlytools/pdf-decrypt';

// Encrypt
const encrypted = await encryptPDF(pdfBytes, 'secret');

// Decrypt
const decrypted = await decryptPDF(encrypted, 'secret');

Browser Usage

<input type="file" id="pdf-input" accept=".pdf" />
<input type="password" id="password" placeholder="Enter password" />
<button id="decrypt-btn">Decrypt</button>

<script type="module">
  import { decryptPDF } from '@localonlytools/pdf-decrypt';

  document.getElementById('decrypt-btn').addEventListener('click', async () => {
    const file = document.getElementById('pdf-input').files[0];
    const password = document.getElementById('password').value;
    const pdfBytes = new Uint8Array(await file.arrayBuffer());

    try {
      const decrypted = await decryptPDF(pdfBytes, password);

      // Download
      const blob = new Blob([decrypted], { type: 'application/pdf' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = 'decrypted.pdf';
      a.click();
    } catch (e) {
      alert(e.message);
    }
  });
</script>

Supported Encryption

| Algorithm | PDF Version | Key Length | Status | |-----------|-------------|-----------|--------| | AES-256 (V=5, R=6) | 2.0 (ISO 32000-2) | 256-bit | Supported | | AES-128 (V=4, R=4) | 1.6+ (ISO 32000-1) | 128-bit | Supported | | RC4 (V=2, R=3) | 1.4+ (ISO 32000-1) | 128-bit | Supported | | RC4 (V=1, R=2) | 1.1+ | 40-bit | Supported |

Comparison with pdf-decrypt-lite

| Feature | pdf-decrypt | pdf-decrypt-lite | |---------|-------------|-----------------| | AES-256 | Yes | No | | AES-128 | Yes | No | | RC4 128-bit | Yes | Yes | | RC4 40-bit | Yes | Yes | | Batched async | Yes | No (sync only) | | Size | ~18KB | ~8KB | | Use case | Full decryption | RC4-only, minimal |

Choose pdf-decrypt-lite if you only need RC4 and want the smallest possible bundle. Choose pdf-decrypt for full AES-256 + AES-128 + RC4 support.

Related Packages

| Package | Description | |---------|-------------| | @pdfsmaller/pdf-encrypt | Full encryption — AES-256 + RC4 (companion to this package) | | @pdfsmaller/pdf-encrypt-lite | Lightweight RC4-only encryption (~7KB) | | @pdfsmaller/pdf-decrypt-lite | Lightweight RC4-only decryption (~8KB) |

License

MIT — Originally by PDFSmaller.com. See the original repository for more details. Maintained by Local Only Tools.