Skip to content

Encrypt PDFs

Set encryption in constructor options for a new PDF, or call encrypt() before endPDF(). Recipe applies encryption to the final byte output, including after deferred page insertion.

import { createRecipe } from "@muhammara/wasm";

var Recipe = await createRecipe();
var pdfBytes = new Recipe({
  userPassword: "open-password",
  ownerPassword: "owner-password",
  userProtectionFlag: Recipe.permission("print, copy"),
})
  .createPage("letter")
  .text("Protected document", 72, 72, { size: 24 })
  .endPage()
  .endPDF();

userPassword controls opening the document. ownerPassword (or its password alias) controls owner access, and userProtectionFlag is a numeric permission mask. Recipe.permission() combines the supported names print, modify, copy, edit, fillform, extract, assemble, and printbest.

Byte-first encryption supports RC4 and AES-128 through PDF 1.7. It does not support PDF 2.0/AES-256. Recipe also cannot directly open a password-protected source; use the low-level recrypt() API to decrypt bytes first, modify the plain bytes, then configure output encryption.

import { createMuhammaraWasm, createRecipe } from "@muhammara/wasm";

var [muhammara, Recipe] = await Promise.all([
  createMuhammaraWasm(),
  createRecipe(),
]);
var encryptedInputBytes = new Recipe({ userPassword: "current-password" })
  .createPage(300, 180)
  .text("Original protected PDF", 36, 48)
  .endPage()
  .endPDF();
var plainBytes = muhammara.recrypt(encryptedInputBytes, {
  password: "current-password",
});
var outputBytes = new Recipe(plainBytes)
  .editPage(1)
  .text("Updated", 72, 72)
  .endPage()
  .encrypt({ ownerPassword: "new-owner-password" })
  .endPDF();

See Change PDF Passwords for a complete browser workflow and Differences And Restrictions for the security boundary.