EBP is a self-declared successor to PGP, built from the ground up to be quantum-secure.
This repository contains the reference implementation of EBP. Its purpose is to demonstrate the architecture, protocols, and intended usage model of the system rather than to serve as a production-hardened security solution.
Project page: williamdoyle.ca/ebp
All released application files will come with an EBP signature from ebpdk1m6l96sg6xpwcspl5yn9zph8j82x7ujsuuwl5gwqhctgmndjtvvjq5vwp99
- Navigate to the releases page
- Locate the latest release and click the "Assets" dropdown
- Select the
.AppImagefile and download it - Once downloaded, make sure it has permission to run as a program
- Double-click the downloaded file to launch the EBP program
- Navigate to the releases page
- Locate the latest release and click the "Assets" dropdown
- Select the
.dmgfile and download it - Run the file, drag the image of the fox into the applications icon
- EBP is now installed on your mac and can be run like any other application
- Navigate to the releases page
- Locate the latest release and click the "Assets" dropdown
- Select and download the
.msifile - Run the
.msifile and follow the wizard to install EBP on your system - Launch EBP like any other windows program. It can be found by searching for "EBP"
If you are comfortable with the CLI and or would like to contribute to this codebase you will likely want to run ebp from source.
- Install Deno
- Clone this repository
- Run tests to verify everything works:
deno task test:core
- Run
deno task gui - navigate to http://localhost:8787 (or wherever the terminal points you to) in your browser
- click on settings
- Set server url to https://ebp-cqyo.onrender.com
If you wish to create your own build file you should be able to do so fairly easily.
- install Node + NPM, Rust + Cargo, and Deno
- run the shell script for your OS (
build_desktop_mac.sh,build_desktop_windows.sh, orbuild_desktop_linux.sh)
If all goes well this should result in an executable file... EBP.AppImage on Linux, __ on Mac, or __ on Windows.
The EBP GUI includes a built-in interface for sending and receiving email. It connects directly over standard SMTP and IMAP protocols, making it compatible with most email providers. EBP also supports OAuth with Gmail and Outlook for a simpler experience.
To run using OAuth you will need to provide the following values in your .env file.
MAIL_OAUTH_GMAIL_CLIENT_ID=""
MAIL_OAUTH_GMAIL_CLIENT_SECRET="" # only provided to key server (playing double duty by also handeling oauth)
# MAIL_OAUTH_OUTLOOK_CLIENT_ID="" # no longer concerned with outlook because the headache wasn't worth the time
# MAIL_OAUTH_OUTLOOK_CLIENT_SECRET="" # only provided to key server, not the users machineIf you are using a testing gmail client oauth cred you may find this following link helpful for adding people as test users. console.cloud.google.com/auth/audience. Make sure you are in the correct project. Scroll down to "Test users" and click "add users".
Proton users must install and run Proton Mail Bridge to use EBP Native Email.
Add two test email accounts two the dotenv file in order to test email functionality in the e2e test suite.
TEST_EMAIL_ONE=""
TEST_EMAIL_ONE_PWORD=""
TEST_EMAIL_ONE_SMTP_PORT="465"
TEST_EMAIL_ONE_SMTP_HOST=""
TEST_EMAIL_ONE_IMAP_PORT="993"
TEST_EMAIL_ONE_IMAP_HOST=""
TEST_EMAIL_TWO=""
TEST_EMAIL_TWO_PWORD=""
TEST_EMAIL_TWO_SMTP_PORT="465"
TEST_EMAIL_TWO_SMTP_HOST=""
TEST_EMAIL_TWO_IMAP_PORT="993"
TEST_EMAIL_TWO_IMAP_HOST=""EBP includes a Chrome extension that adds sign/encrypt and decrypt/verify controls to webmail using the local GUI backend API.
Supported email clients (web):
- Gmail
- Outlook (Outlook on the web)
- Proton Mail
This extension will work on any chromium based browser.
- Open
chrome://extensionsor - Enable Developer Mode.
- Click Load unpacked and select this folder:
/even-better-privacy/email/chrome-extension
See the extension guide in email/chrome-extension/README.md
I have not yet published the extension to the webstore. I intend to do this soon.
If you intend to run your own key server you will need to create a .env file in the project root (the same folder as this ReadMe.md). Example:
DB_TYPE=psql # options include sqlite | psql
# postgres database connection details
PG_HOST=localhost
PG_PORT=5432
PG_USER=postgres
PG_PASSWORD=postgres
PG_DATABASE=ebp
PG_POOL_SIZE=5
SMTP_HOST=smtp.example.com
SMTP_PORT=465
SMTP_USER=<sender email address>
SMTP_PASS="sender email password here"
SMTP_FROM=<sender email address>
SMTP_SECURE=true
PUBLIC_BASE_URL=<base url of ebp key server>EBP uses quantum secure schemes approved by NIST. More information on NISTs post quantum cryptography standards can be found here
- SLH-DSA (SPHINCS+)
- ML-DSA (Dilithium)
- FN-DSA (Falcon) (Planned)
- ML-KEM (Kyber)
| Name | Varient Used | Public Key Size | Purpose |
|---|---|---|---|
| ML-KEM (Kyber) | ML-KEM-1024 | 1,568 bytes | KEM |
| SLH-DSA (SPHINCS+) | SLH-DSA SHA2-256s | 64 bytes | Auth |
| ML-DSA (Dilithium) | ml_dsa87 | 2,592 bytes | Auth |
| FN-DSA (Falcon) (Planned) | NA | NA | Auth |
Unlike RSA or ECC, the new post quantum schemes support either encryption or message signing but not both in the same scheme. Therefore we insist signing and encryption (or rather KEM) keys never appear in isolation but always come in pairs; a signing key and an encryption key. The resulting object is called an Identity. The fingerprint of an identity is the hash of the two keys.
At the moment we treat KEMs like regular asymmetric encryption. When we send an encrypted message to an identity we always generate a fresh AES key and use it to encrypt the message, then we encapsulate the AES key with the recipients KEM key, then we send the encapsulated key along with the ciphertext to the recipient. Responses are encrypted with a new AES key, not the one initially provided by the first sender.
I am open to changing this in the future. This approach has been easiest for me, and I don’t see changing it as a priority. It’s straightforward and versatile, but I do acknowledge it is less efficient than it could be.”
- Generate an identity (creates a signing key + encryption key pair)
- Share your public identity with others (fingerprint + public keys)
- Import contacts' public identities
- Sign messages — recipients verify using your public signing key
- Encrypt messages — recipients decrypt using their private encryption key
EBP supports revocation of both details and entire identities. All revocations require a valid signature from the identity being revoked, ensuring that only the key holder can revoke their own data.
Remove a specific detail (like an email or name) from an identity. Use this when:
- Information has changed (new email address)
- Information was entered incorrectly
- You no longer want that information associated with your identity
# Revoke a detail locally
ebp revoke-detail email --reason "Changed email address"
# Revoke and push to server
ebp revoke-detail email --reason "Changed email address" --pushMark an entire identity as compromised or invalid. This is irreversible. Use this when:
- Your private key has been compromised
- You're migrating to a new identity
- The identity should no longer be trusted
# Revoke identity (requires --force confirmation)
ebp revoke --reason "Key compromised" --force
# Revoke and push to server
ebp revoke --reason "Key compromised" --force --pushYou can pre-generate an emergency revocation certificate when creating an identity. This certificate can be stored securely (e.g., printed and kept in a safe) and used later if your private key is compromised—even if you lose access to the key itself.
# Generate identity with emergency certificate
ebp generate --revocation-cert --revocation-output emergency-revoke.json
# Generate emergency certificate for existing identity
ebp generate-revocation-cert --output emergency-revoke.jsonImportant: Store emergency certificates securely. Anyone with this certificate can revoke your identity.
-
Signed Certificates: Each revocation creates a signed certificate containing:
- Type (detail or identity)
- Identity fingerprint
- Monotonically increasing nonce (prevents replay attacks)
- Timestamp
- Optional reason
- Target path (for detail revocations)
- Cryptographic signature
-
Verification: Anyone can verify a revocation certificate using the identity's public signing key. The server validates signatures before accepting revocations.
-
Nonce Protection: Revocation nonces must be strictly increasing, preventing attackers from replaying old revocation certificates. Emergency certificates use nonce 0 and can be used once.
-
Server Integration: When pushed to a server, revocations are stored and returned with identity queries. Clients should check revocation status when importing contacts.
When fetching an identity from the server, the response includes:
revoked: Boolean indicating if the identity is revokedrevocationCertificate: The hex-encoded certificate if revokedrevokedDetails: Array of detail paths that have been revoked
Applications should warn users when interacting with revoked identities or details.
Run each of these to ensure everything is working
Core tests
deno task test:core
CLI Tests
deno task test:cli-utils
More CLI tests could be useful
Server tests
deno task test:server
GUI backend tests
deno task test:gui-backend
E2E GUI tests (Playwright)
npm install
npx playwright install --with-deps
In your .env file set
DB_TYPE=sqlite
Then run the tests (this will auto-start the GUI local backend):
deno task test:e2e
To run end to end tests using postgres for the database
DB_TYPE=psql
then run
deno task test:e2e:psql
EBP fingerprints use:
- a merkle root of the two public keys (signing leaf + encryption leaf)
- bech32 encoding with signing-scheme specific HRPs
We use a merkle tree of the two keys as a fingerprint because it allows the fingerprint to be verified without both keys. This could be useful in cases where data costs are high and both keys are not required.
Current prefixes:
ebpdk1...for Dilithium + Kyber identitiesebpsk1...for SPHINCS+ + Kyber identities
Note: Where this section talks about a program called ebp, you will instead use deno task cli
The ebp CLI manages post-quantum identities and secure messaging. You can generate multiple identities (stored under ~/.ebp/<name>.identity.json), switch between them, inspect fingerprints and details, exchange signed/encrypted messages with contacts, and encrypt/decrypt full file payloads.
- create and switch identities (
ebp generate [name],ebp identities,ebp use <name>) - view identity info and attached details (
ebp info,ebp details) - export public identities for sharing (
ebp export-public) - import contacts and list them (
ebp import,ebp contacts) - sign messages (
ebp sign) and verify (ebp verify) - encrypt and decrypt for peers (
ebp encrypt,ebp decrypt) - encrypt and decrypt files (
ebp encrypt-file,ebp decrypt-file) - publish identities to the server and fetch contacts (
ebp server <url>,ebp publish,ebp fetch <fingerprint>) - push attached details to the server when adding them (
ebp detail <path> <value> --push)
- All the features of the CLI but in a graphical format
- Interfaces with the same file system — the GUI and CLI are two interfaces to the same data
- Run the local backend:
deno task gui:local-backend - Navigate to localhost:8787
If you find EBP useful, consider supporting the project:
| Network | Address/Handle | Link |
|---|---|---|
| Ethereum (& more) | williamdoyle.eth |
https://app.ens.domains/williamdoyle.eth |
| Bitcoin | bc1q6crw4wy7jecs05f4ytz68n6evuzlu7k3cnu7zy |
https://blockchair.com/bitcoin/address/bc1q6crw4wy7jecs05f4ytz68n6evuzlu7k3cnu7zy |
| Cardano | $wildoy |
https://handle.me/wildoy |
| QRL | Q02070028dc6ca5f722f9646171cee25eff5d178907d0e05a7c343eeba77ef138fcc0da9a0074db |
https://explorer.theqrl.org/a/Q02070028dc6ca5f722f9646171cee25eff5d178907d0e05a7c343eeba77ef138fcc0da9a0074db |
See PRIVACY.md for the project privacy policy.
MIT — see LICENSE for details.
- ENS Support
- Add support for EBP fingerprints to ENS. This means contributing a small bit of code to the ENS project. I've already tried to do this with QRL but my pull request was never merged. ensdomains/address-encoder#386 . This step is not required to make the system work well with ENS but it will make it a bit nicer for the user. Infact this could be a last step.
- Add support for searching ENS names for EBP fingerprints. Then look up the fingerprint on the EBP server
- Add a provision so that a user can add an ENS name to their EBP identity as a detail but the server must check that the users fingerprint has already been added to the ENS name
- Better db interface layer
- abstract on EBP actions instead of the db connection
- this will allow us to have different SQL for the sqlite and psql implementations. It would also allow use to easily implement non-sql connections.
- end to end tests for the email plugin
- email: enable ebp interface when a user directly replies to an email
- email: select multiple recipients. Encrypt with same AES key. Send json object with one encrypted message and an object mapping the recipients fingerprint to a copy of the AES key encapsulated just for that recipient.
{
"encapsulated_key_map": {
"<recipient fingerprint>": "<ciphertext>"
},
"ciphertext":"<AES ciphertext of M + Sm, where M is a message and Sm is a signature on that message>"
}- Support expiry dates for identities
- Endorse other EBP identities as your own (two-way binding)
- plugin: Make it harder to accidentally send email without first encrypting
- plugin: hide password inputs
- hashed details
- hashed email endorsement
- take hash of your email address
- sign hash
- send hash & email address & signature to public key server
- server sends email for you to confirm your email
- server never makes unhashed email public. Perhaps even deletes raw email address after the user has confirmed it.
- users who receive signed emails from you can still confrim that the email address is associated with the provided EBP identity.
- reduce your exposure to spam
- hashed email endorsement
- Support identity hierarchy
- parent can revoke the relationship
- one pattern might look like this:
graph TD
M[Master Identity] -->|endorses| C[Cold Identity]
C -->|endorses| H[Hot Key]
- when adding a detail to an identity I want to take the input to a details path as a drop down with the first option being "custom" so users can provide thair own details path
- tighten up
core - tighten up
gui/local-backend - create full inventory and plan for hardening
- mobile application
- full feature parity with GUI
- advanced email features
- search the inbox
- write and save drafts (encrypted with the same pin/password)
- render emails: images, layout, font, everything
- what is usually used? HTML? Markdown?
- scheduled send
- more traditional "email inbox" layout for the email page
