Skip to content

Encryption

The SDK provides three encryption methods, each suited to a different use case.

MethodUploadEmail deliveryReturns
encrypt()NoNoUint8Array
encryptAndUpload()YesNo{ uuid }
encryptAndDeliver()YesYes{ uuid }

Recipients

Before encrypting, build one or more recipients. PostGuard can encrypt with any wallet attribute. Email is the most common, but you can also target recipients by name, BSN, domain, or any other verified attribute.

The SvelteKit example uses pg.recipient.email() and pg.recipient.emailDomain():

ts
		method: 'POST',
		headers: {
			'Content-Type': 'application/json',
			Authorization: `Bearer ${apiKey}`
		},
		body: JSON.stringify({
			pubSignId: [{ t: 'pbdf.sidn-pbdf.email.email' }]
		})
	});
	if (!response.ok) {
		const text = await response.text();
		throw new Error(`Failed to fetch signing keys: ${response.status} ${text}`);

Source: encryption.ts#L20-L31

The Thunderbird addon builds recipients with custom policies when configured:

ts
      const timestamp = Math.round(date.getTime() / 1000);

      // Build attachments list
      const composeAttachments = await browser.compose.listAttachments(tab.id);
      const attachmentData = await Promise.all(
        composeAttachments.map(async (att) => {
          const file = await browser.compose.getAttachmentFile(att.id) as unknown as File;
          return {
            name: file.name,
            type: file.type,
            data: await file.arrayBuffer(),
          };
        })
      );

Source: background.ts#L362-L376

Under the hood, pg.recipient.email() creates a policy with the attribute type pbdf.sidn-pbdf.email.email, while pg.recipient.emailDomain() extracts the domain from the email and uses pbdf.sidn-pbdf.email.domain.

encrypt()

Encrypts raw data and returns the ciphertext as a Uint8Array. No files are uploaded. The Thunderbird addon uses this to encrypt MIME email content:

ts
          }
        } catch (e) {
          console.warn("[PostGuard] Could not fetch related message headers:", e);
        }
      }

      // Build inner MIME
      const mimeData = buildInnerMime({
        from: details.from,

Source: background.ts#L388-L396

Parameters

ParameterTypeRequiredDescription
signSignMethodYesAuthentication method
recipientsRecipient[]YesOne or more recipients
dataUint8Array | ReadableStream<Uint8Array>YesData to encrypt

encryptAndUpload()

Encrypts one or more files and uploads them to Cryptify. The files are bundled into a ZIP archive, encrypted, and streamed to Cryptify in chunks (1 MB by default). Returns a UUID that recipients can use to download and decrypt.

WARNING

Requires cryptifyUrl to be set in the constructor.

Parameters

ParameterTypeRequiredDescription
signSignMethodYesAuthentication method
recipientsRecipient[]YesOne or more recipients
filesFile[] | FileListYesFiles to encrypt
onProgress(pct: number) => voidNoUpload progress callback (0-100)
signalAbortSignalNoCancel the operation

encryptAndDeliver()

Same as encryptAndUpload, but also triggers Cryptify to send email notifications to all recipients with a link to decrypt. The SvelteKit example uses this with an API key:

ts
export async function encryptAndSend(options: EncryptAndSendOptions): Promise<void> {
	const {
		files,
		citizen,
		organisation,
		apiKey,
		message,
		onProgress,
		abortController = new AbortController()
	} = options;

	// Fetch MPK and signing keys in parallel
	const [mpk, signingKeys] = await Promise.all([fetchMPK(), fetchSigningKeys(apiKey)]);

	// Build encryption policy
	const ts = Math.round(Date.now() / 1000);
	const policy: Record<string, { ts: number; con: { t: string; v?: string }[] }> = {};

	// Citizen: must prove exact email address
	policy[citizen.email] = {
		ts,
		con: [{ t: 'pbdf.sidn-pbdf.email.email', v: citizen.email }]
	};

	// Organisation: must prove an email at the correct domain
	policy[organisation.email] = {
		ts,
		con: [{ t: 'pbdf.sidn-pbdf.email.domain', v: extractDomain(organisation.email) }]
	};

	const sealOptions: ISealOptions = {
		policy,
		pubSignKey: signingKeys.pubSignKey as ISealOptions['pubSignKey']
	};
	if (signingKeys.privSignKey) {
		sealOptions.privSignKey = signingKeys.privSignKey as ISealOptions['pubSignKey'];
	}

Source: encryption.ts#L50-L87

Delivery options

OptionTypeDefaultDescription
messagestringundefinedCustom message in the notification email
language'EN' | 'NL''EN'Language of the notification email
confirmToSenderbooleanfalseSend a delivery confirmation to the sender

Error handling

All encryption methods can throw:

  • PostGuardError: general SDK error
  • NetworkError: PKG or Cryptify communication failure (includes status and body properties)
  • YiviNotInstalledError: Yivi packages not installed (when using pg.sign.yivi)

See Error Handling for the full error reference.