Free privacy tool
Encrypt a file in your browser
Pick a file, choose a passphrase, and download an encrypted copy. AES-256-GCM, with the key derived in your browser. Nothing uploads, and it works offline once loaded. The format is documented byte by byte below, so you don’t have to take our word for anything.
Runs entirely in this tab. Nothing is uploaded, and it works offline once loaded.
Any file. Large files need memory. See the honest limits below.
There is no recovery. A forgotten passphrase means a file that no one, including us, can ever open.
Every parameter, stated
- Cipher
- AES-256-GCM (WebCrypto), 128-bit tag
- Key derivation
- PBKDF2-HMAC-SHA-256, 600,000 iterations
- KDF salt
- 16 bytes, CSPRNG, fresh per file
- GCM nonce
- 12 bytes, CSPRNG, fresh per file
- Authenticated data
- the entire 42-byte header, so tampering with any stated parameter breaks decryption
- Passphrase encoding
- UTF-8, NFC-normalized (so the same phrase typed on any device derives the same key)
Honest limits
This is not the Sealby app’s vault format. The app derives keys with Argon2id calibrated per device, wraps them in the Secure Enclave, and stores content in deniable chunked containers. A web page can do none of that. This page is a standalone utility built on what browsers offer natively.
PBKDF2 is not memory-hard. It is the only key-derivation function browsers ship natively, and 600,000 iterations makes each guess slow, but a GPU rig still attacks it far faster than Argon2id. So the protection lives in your passphrase: four random words or more, not a password.
WebCrypto encrypts in one shot. There is no streaming, so the whole file sits in memory two to three times over while processing. Hundreds of megabytes are fine on most devices. For multi-gigabyte archives, use a desktop tool. The encrypted output also reveals the file’s approximate size. The name is encrypted inside, but the size is not hidden.
The format, byte by byte
Everything a technical reader needs to verify this page’s output independently, or decrypt it in twenty lines of Python:
| bytes | field | contents |
|---|---|---|
| 0–7 | magic | ASCII "SBXF0001" |
| 8 | version | 0x01 |
| 9 | algorithm | 0x01 = AES-256-GCM + PBKDF2-HMAC-SHA-256 |
| 10–13 | iterations | uint32, big-endian (600,000) |
| 14–29 | salt | 16 bytes |
| 30–41 | nonce | 12 bytes |
| 42–end | ciphertext | AES-256-GCM of the payload, AAD = bytes 0–41; final 16 bytes are the GCM tag |
Payload before encryption: [2-byte name length, big-endian][filename, UTF-8][file bytes]. The original filename travels encrypted; on decryption it is restored.
Reference decryptor (Python, cryptography library)
import sys, hashlib, struct, unicodedata
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
raw = open(sys.argv[1], "rb").read()
assert raw[:8] == b"SBXF0001" and raw[8] == 1 and raw[9] == 1
iters = struct.unpack(">I", raw[10:14])[0] # 600000
salt, nonce, ct = raw[14:30], raw[30:42], raw[42:]
phrase = unicodedata.normalize("NFC", sys.argv[2]).encode()
key = hashlib.pbkdf2_hmac("sha256", phrase, salt, iters, 32)
plain = AESGCM(key).decrypt(nonce, ct, raw[:42]) # AAD = header
name_len = struct.unpack(">H", plain[:2])[0]
name = plain[2 : 2 + name_len].decode()
open(name, "wb").write(plain[2 + name_len :])
print("decrypted ->", name)This is the demo. The vault is the product.
One file, one passphrase, one page. That is what a browser can do. Sealby does it properly: Argon2id calibrated to your device, keys in the Secure Enclave, and hidden vaults with no stored list or count.
iPhone & iPad · iOS 17+ · Free