PGP, Autocrypt, SecureJoin, and related advanced behavior in madcore.
Also see: Examples · Architecture · Core parity
Madcore is a PGP-first messenger library. Every account has an associated OpenPGP keypair used for end-to-end encryption.
The SDK uses OpenPGP.js to generate ECC (Curve25519) keys. This provides high security with small key sizes, perfect for mobile and web environments.
// Internal call within SDK when initializing or restoring
const { privateKey, publicKey, fingerprint } = await generateKeys(email, displayName);Delta Chat follows the Autocrypt standard for opportunistic encryption. Key exchange happens automatically in the headers of every outgoing email:
- Header Construction: Every message sent via the SDK includes an
Autocryptheader containing the sender's public key data. - Opportunistic Import: When the SDK receives a message, it checks for an
Autocryptheader. If found, it automatically imports the sender's public key into the local contact registry. - Encryption Level: Once a peer's key is known, the SDK automatically switches to encrypted messaging for all subsequent communications with that peer.
To protect against surreptitious forwarding and to keep keys synchronized across multi-device setups, the SDK implements Autocrypt-Gossip:
- In group chats, the sender "gossips" the public keys of all other group members inside the encrypted MIME structure.
- This allows new members or secondary devices to discover peer keys securely.
While Autocrypt provides opportunistic encryption, SecureJoin provides verified end-to-end encryption. It uses a QR-code/URI-based handshake to ensure no Man-in-the-Middle (MITM) can intercept the key exchange.
-
Phase 1:
vc-request(Joiner → Inviter)- The Joiner scans a QR code/URI containing the Inviter's fingerprint, an
inviteNumber, and asecret. - The Joiner sends an unencrypted message to the Inviter with the
Secure-Join: vc-requestheader and theinviteNumber.
- The Joiner scans a QR code/URI containing the Inviter's fingerprint, an
-
Phase 2:
vc-auth-required(Inviter → Joiner)- The Inviter verifies the
inviteNumber. - The Inviter responds with
Secure-Join: vc-auth-required. This message also includes the Inviter'sAutocryptheader, allowing the Joiner to import the Inviter's key.
- The Inviter verifies the
-
Phase 3:
vc-request-with-auth(Joiner → Inviter)- The Joiner now has the Inviter's key.
- The Joiner sends a PGP-encrypted message to the Inviter containing the
secretfrom the QR code and their own PGP fingerprint.
-
Phase 4:
vc-contact-confirm(Inviter → Joiner)- The Inviter decrypts the message and verifies the
secret. - If valid, the Inviter sends an encrypted
vc-contact-confirm. Both parties now mark each other as Verified.
- The Inviter decrypts the message and verifies the
Madcore is designed to work in a multi-device environment.
When you send a message from one device, the relay typically places a copy in the Sent folder. Other devices connected to the same account can see these messages.
- Deduplication: The SDK uses the RFC 724
Message-IDto ensure that messages sent by the local device aren't processed as incoming "new" messages. - State Sync: By observing your own outgoing messages (from other devices), the SDK can synchronize chat state, group memberships, and settings across all your instances.
The SDK monitors the INBOX for incoming messages. In future versions, it can be configured to monitor other IMAP folders or use the IMAP METADATA extension for cross-device configuration syncing.
Handling large attachments in a web environment requires careful memory management.
The SDK handles attachments (Images, Videos, Voice) primarily as Base64 strings:
- Sending: You provide a Base64 string to
.send(). The SDK wraps this in a MIME structure. - Receiving: The SDK parses the multipart MIME, extracts the Base64 data, and provides it in the
attachmentsarray of aParsedMessage.
The lib/mime.ts module handles the complex task of building and deconstructing RFC 2822 structures:
- Multipart/Mixed: For messages with attachments.
- Multipart/Encrypted: For PGP/MIME encrypted payloads.
- Protected Headers: Delta Chat protects metadata (Subject, From, To) by including them inside the encrypted PGP block.
- Private keys and chat history live in IndexedDB (browser default) under a per-account database.
- Passwords are not written to IndexedDB. On cold start call
restoreAccount(email, password, serverUrl)with a password from your app’s secure storage or a re-login prompt. - Call
flushPersist()onpagehideif you need a hard guarantee the latest account snapshot is on disk. exportBackup/importBackupcan optionally passphrase-encrypt a full portable blob for multi-device transfer.
- Fundamentals & Core Messaging — Account lifecycle, SecureJoin, IndexedDB restore
- Architecture & Protocol Internals — Storage layout, UID cursor, modules