How to pgp message signer with browser-local keys
- Step 1Pick the action — Set Action to
Generate key pair,Sign message, orVerify signed message. The form below the dropdown changes to show only the inputs that action needs — there is no separate import screen or saved-key list. - Step 2If generating, choose the algorithm and identity — When Action is
Generate key pair, a second dropdown appears:Ed25519 (fast)(default) orRSA-4096 (compatible). Optionally fill Name and Email for the user ID embedded in the key — if you leave them blank the tool usesJAD Security user/user@example.com. RSA-4096 generation is CPU-heavy and can take several seconds in-browser. - Step 3Set the passphrase — For
GenerateandSign, a password field appears. On generate it encrypts the new private key (OpenPGP derives the key-protection from this passphrase). On sign it must match the passphrase that already protects the armored private key you paste. Verify needs no passphrase — it only uses a public key. - Step 4Paste the inputs for sign or verify — Sign: type the message in the first textarea and paste your
-----BEGIN PGP PRIVATE KEY BLOCK-----into the second. Verify: paste the-----BEGIN PGP SIGNED MESSAGE-----block in the first textarea and the signer's-----BEGIN PGP PUBLIC KEY BLOCK-----in the second. - Step 5Run and read the result — Generate downloads
pgp-keypair.json(both armored keys). Sign downloadssigned-message.asc— an armored cleartext-signed block. Verify shows JSON:valid(true/false),keyId(the 16-hex signing key ID on success, or an error string on failure), andtext(the message that was actually signed). - Step 6Distribute and re-verify — Publish the
signed-message.ascblock and your public key. Anyone can confirm it withgpg --verifyor by pasting both back into this tool's Verify action. Archive thepgp-keypair.jsonprivate key in your own secret store — this tool does not keep a copy, so if you lose it you must generate a new pair.
What each action reads and produces
The three values of the action control and the exact inputs/outputs of each, taken from the tool's processor. Inputs not listed for an action are ignored by that action.
| Action | Required inputs | Optional inputs | Output | Output filename |
|---|---|---|---|---|
generate | (none — runs with defaults) | algorithm (ed25519/rsa), name, email, passphrase | JSON object with publicKey + privateKey armored blocks (report) | pgp-keypair.json |
sign (default) | message, armoredKey (private key block), passphrase | (none) | Armored cleartext-signed message (text) | signed-message.asc |
verify | signedMessage, publicKey | (none) | JSON: { valid, keyId, text } | (JSON result shown inline) |
Key generation options
The only generation controls the tool exposes. Bit size and curve are fixed — there is no 2048-bit, 3072-bit, Curve25519-vs-Ed25519, or expiry-date control.
| Option | Values / default | Behaviour | When to choose it |
|---|---|---|---|
algorithm | ed25519 (default) · rsa | ed25519 → ECC key on the Ed25519 curve. rsa → fixed 4096-bit RSA. No other sizes or curves are selectable | Ed25519 for speed and tiny signatures; RSA-4096 only when a recipient's toolchain predates ECC support |
name | Free text (default JAD Security user) | Becomes the user-ID name embedded in the key | Set it so verifiers see a human identity, not the placeholder |
email | Free text (default user@example.com) | Becomes the user-ID email embedded in the key | Set it to your real address; it is not validated for deliverability |
passphrase | Free text (may be empty) | Encrypts the generated private key. An empty passphrase produces an unprotected private key | Always set one — an empty passphrase means anyone with the .json can sign as you |
Where the work happens and how it's gated
Execution location and tier facts for this tool, from the schema and registry. Because input is text, the security family's per-file size limits do not gate this tool.
| Property | Value | Source / note |
|---|---|---|
| Execution | Browser-only (OpenPGP.js WASM) | Listed in BROWSER_ONLY_SECURITY_SLUGS; the server engine has no PGP case |
| Public API | Returns 400 with a pointer to the web tool | PGP keygen/sign relies on browser WASM, so the API runner rejects it |
| Minimum tier | Developer | minTier: developer in the registry — Free/Pro/Pro-media cannot open it |
| Input type | Text / armored blocks (no file upload) | inputType: text; the UI shows textareas, not a drop zone |
| File-size limit | Not applicable | No file is read, so the 10 MB/100 MB/500 MB/2 GB family caps never apply |
Cookbook
Concrete runs for each action. Keys and signatures below are illustrative (truncated armor) — your real blocks are far longer. Everything here happens in your browser tab.
Generate an Ed25519 key pair for signing releases
Action generate, algorithm ed25519, with a real name/email and a passphrase. The tool returns a JSON file containing both armored keys. Archive the private key in your own secret manager — the tool keeps no copy.
Action: generate
Algorithm: ed25519 (fast)
Name: Release Bot
Email: releases@example.com
Passphrase: ••••••••••••
Download → pgp-keypair.json
{
"publicKey": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n...\n-----END...",
"privateKey": "-----BEGIN PGP PRIVATE KEY BLOCK-----\n...\n-----END..."
}
The privateKey block is already passphrase-encrypted by OpenPGP.Cleartext-sign a release announcement
Action sign. Paste the message and the armored private key, enter its passphrase. Output is an armored cleartext-signed block — the original text stays readable, with a detached-style signature appended.
Action: sign
Message: v2.4.0 is live. SHA-256 of the tarball:
9f2c...e1a. Signed by releases@example.com.
Private key: -----BEGIN PGP PRIVATE KEY BLOCK-----...
Passphrase: ••••••••••••
Download → signed-message.asc
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
v2.4.0 is live. SHA-256 of the tarball:
9f2c...e1a. Signed by releases@example.com.
-----BEGIN PGP SIGNATURE-----
...
-----END PGP SIGNATURE-----Verify a signed advisory against a published public key
Action verify. Paste the signed block and the signer's public key. The JSON verdict tells you whether the signature checks out, which key ID made it, and what text was actually under the signature.
Action: verify
Signed message: -----BEGIN PGP SIGNED MESSAGE-----...
Public key: -----BEGIN PGP PUBLIC KEY BLOCK-----...
Result:
{
"valid": true,
"keyId": "a1b2c3d4e5f60718",
"text": "v2.4.0 is live. SHA-256 of the tarball: 9f2c...e1a..."
}Cross-check the verdict against gpg on the command line
The browser result should match what GnuPG reports for the same block and key. Use this to confirm the in-browser verification before trusting it in a workflow.
$ gpg --import signer-public.asc $ gpg --verify signed-message.asc gpg: Signature made Mon 13 Jun 2026 ... gpg: using EDDSA key A1B2C3D4E5F60718... gpg: Good signature from "Release Bot <releases@example.com>" Browser verify → "valid": true, "keyId": "a1b2c3d4e5f60718" (GnuPG's long key ID ends in the same 16 hex chars.)
Tampered message fails verification
Change a single character of a signed block and verify it. The signature no longer matches the text, so valid is false and keyId carries the OpenPGP error string instead of a key ID.
Original line: ...tarball: 9f2c...e1a.
Edited line: ...tarball: 9f2c...e1b. ← one char changed
Action: verify (same public key)
Result:
{
"valid": false,
"keyId": "Signed digest did not match",
"text": "...tarball: 9f2c...e1b..."
}
→ Re-sign from the source message; never edit a signed block in place.Edge cases and what actually happens
Tool is Developer-tier only
Tier-gatedThe registry sets minTier: developer for this tool. Free, Pro, and Pro-media accounts cannot run generate/sign/verify here — the page surfaces an upgrade prompt. There is no free fallback because the WASM signing path is part of the Developer feature set.
Called through the public API or MCP runner
400 rejectedPGP keygen and signing depend on the browser-targeted OpenPGP.js WASM bundle, so the server engine has no case for this slug and the API runner returns 400 with a pointer back to the web tool. Automate it by driving the browser UI, not by POSTing to /api/v1/tools/pgp-message-signer/run.
Sign with a wrong or missing passphrase
Decrypt errorSigning first decrypts the pasted private key with the passphrase. If the passphrase is wrong (or the key is passphrase-protected and you left the field blank), OpenPGP.js throws on decryptKey and the sign fails. Re-enter the exact passphrase the key was created with.
Sign with the message field empty
No message providedThe sign path throws No message provided. when message is empty. PGP cleartext signing needs at least one character of text — there is no concept of signing an empty document here.
Sign without pasting a private key
Paste a PGP private key blockSign throws Paste a PGP private key block. if the armoredKey field is empty. The tool has no saved-key list to fall back on, so every sign needs the armored private key pasted in that session.
Verify without the signed block or public key
Invalid inputVerify throws Paste the signed cleartext message. when the signed block is empty, and Paste the signer's public key. when the public key is empty. Both are required; verify never uses a private key or passphrase.
Verify a block whose signing key differs from the pasted public key
valid:falseIf the signature was made by a different key than the public key you paste, OpenPGP.js cannot confirm it: valid comes back false and keyId holds the error message rather than a key ID. Make sure you are using the signer's actual public key, not a colleague's.
Generate with an empty passphrase
By designLeaving the passphrase blank on generate produces an unprotected private key — anyone who obtains the pgp-keypair.json can sign as you with no further secret. The tool allows it but you should always set a passphrase for any key you will actually use.
Expecting a persistent encrypted key vault
Not in this UIThe shipped interface does not store keys between sessions — it does not wire up any IndexedDB key list, and there is no import-and-save screen. You paste the private key and passphrase each time you sign, and they are discarded when the tab closes. Keep your own copy of pgp-keypair.json.
Looking for message encryption, not just signing
Out of scopeThis tool only generates keys, signs cleartext, and verifies signatures — it does not encrypt or decrypt message bodies. For at-rest file confidentiality use aes-256-encryptor (AES-GCM 256 with PBKDF2). PGP-style public-key message encryption is not implemented here.
Frequently asked questions
Does my private key or passphrase ever reach a JAD server?
No. The tool runs OpenPGP.js entirely in your browser tab — generate, sign, and verify all execute client-side. The slug is on the browser-only list and the server API path returns 400 for it, so there is no code that could transmit your key. The private key, passphrase, and message live only in the tab and are gone when you close it.
Which key algorithms and sizes can I generate?
Two: ed25519 (the default, an elliptic-curve key with fast, compact signatures) and rsa, which is fixed at 4096 bits. There is no control for 2048/3072-bit RSA, expiry dates, sub-keys, or other curves — those are not offered by this tool.
Where are my keys stored after I generate them?
They are not stored by the tool. Generate hands you a pgp-keypair.json download containing both armored keys, and that is the only copy. The shipped UI has no saved-key list and no persistent key vault, so you must keep the file yourself — ideally in a secret manager. Lose it and you have to generate a fresh pair.
How do I sign a message?
Set Action to Sign message, type your text in the message box, paste your -----BEGIN PGP PRIVATE KEY BLOCK----- into the key box, and enter the passphrase that protects it. The tool returns signed-message.asc, an armored cleartext-signed block where the original text stays readable with a signature appended.
What does the verify result actually tell me?
Verify returns JSON with three fields: valid (true if the signature matches the text and the pasted public key), keyId (the 16-hex signing key ID on success, or the OpenPGP error string on failure), and text (the exact message that was under the signature). Check valid first, then confirm keyId is the key you expected.
Can I import an existing PGP key?
For signing, yes in the sense that you paste any armored OpenPGP private key block into the sign form along with its passphrase — the tool will use it. There is no separate import-and-store step, though; the key is used for that one sign and not retained. To verify, you paste the signer's public key block the same way.
Can this tool encrypt a message, not just sign it?
No. It only generates key pairs, cleartext-signs messages, and verifies signatures. It does not perform PGP public-key encryption of message bodies. For protecting a file's contents at rest, use the AES tool: aes-256-encryptor.
Why can't I run this through the API or a script?
The signing path depends on the browser-targeted OpenPGP.js WASM bundle, which the server engine doesn't load. The public API runner returns a 400 for this slug with a pointer to the web tool. If you need automation, drive the browser UI; the server cannot run PGP signing on your behalf.
What tier do I need, and is there a size limit?
It is a Developer-tier tool — Free, Pro, and Pro-media accounts can't open it. There is no file-size limit because the tool takes text and armored blocks pasted into textareas rather than uploaded files, so the security family's per-file caps don't apply here.
Will the signed message be readable, or is it scrambled?
Readable. This is a cleartext signature: the output (signed-message.asc) keeps your original message in plain text and appends a -----BEGIN PGP SIGNATURE----- block. Recipients can read it without any key; they only need your public key to confirm it is authentic and unchanged.
Is the output compatible with GnuPG and other PGP tools?
Yes. OpenPGP.js emits standard OpenPGP armor, so signed-message.asc verifies with gpg --verify, Sequoia, Mailvelope, and any OpenPGP-compliant client, and keys from pgp-keypair.json import with gpg --import. The example cookbook shows a gpg cross-check that should match the in-browser verdict's last 16 hex digits.
What other JAD security tools pair well with PGP signing?
For a content hash to embed inside the message you sign, use multi-hash-fingerprinter (md5/sha-1/sha-256/sha-512). To confirm two artifacts are byte-identical before signing, use file-integrity-monitor. To check a key's protecting passphrase is strong, run it through password-entropy-auditor. For encrypting a file at rest, use aes-256-encryptor.
Privacy first
Every JAD Security operation runs entirely in your browser. Files, passwords, and PGP private keys never leave your device — verified by zero outbound network requests during processing.