How Encrypti0n.com Works: A Browser-Based Encryption Platform
Encrypti0n.com offers robust, browser-based cryptography that ensures client-side encryption of both text and files. This local-first approach keeps your data secure, preventing unauthorized access during data transfer or storage. Below, we outline clearly and technically how our encryption processes for the Main App function internally.
Text Encryption Process
Encrypting text securely involves the following precise steps:
- Retrieve Settings : The app fetches cryptographic settings (rounds, salt length) from encrypted local storage.
- Encode Inputs : Both your text and password are encoded into binary format (UTF-8).
- Generate Salt and Key : A random salt is generated. Using Argon2 and the configured number of rounds, a secure 256-bit key is derived from your password.
- Encrypt with AES-GCM : The binary text data is encrypted using AES-GCM with the derived key and a securely generated 12-byte nonce (
crypto.getRandomValues
). - Output Encrypted Data : The encrypted data is encoded in base64 format for easy copying or storage.
Below is a sample code snippet that shows how AES-GCM encryption is performed on text using a javscript-ish pseudo-code:
settings = getEncryptedStorageSettings();
encodedText = utf8Encode(text);
encodedPassword = utf8Encode(password);
salt = crypto.getRandomValues(settings.saltLength);
key = deriveArgon2Key(encodedPassword, salt, settings.rounds);
iv = crypto.getRandomValues(12);
ciphertext = AES_GCM_Encrypt(encodedText, key, iv);
outputBase64(ciphertext);
File Encryption Process
Encrypting files follows a similar core logic with additional file-specific enhancements for improved security and manageability:
If you’re uploading a sensitive PDF, the file-chunking approach makes sure that each chunk is encrypted independently, maximizing security and performance
- Initial Steps : Retrieve settings and encode the password as above, deriving a 256-bit key.
- Chunk Splitting : The file is split into 64 KiB chunks, each encrypted individually to ensure efficiency and security.
- Individual Chunk Encryption : Each chunk receives a newly generated 12-byte nonce for AES-GCM encryption.
- File Header Creation : Each chunk’s length information and encryption metadata (such as nonce and salt) are included in the file header.
- Blob Generation and Download : The encrypted chunks are combined into a Blob object, and a secure download link is generated for the user.
Below is a sample code snippet that explains how AES-GCM encryption is performed on files using a javscript-ish pseudo-code:
settings = getEncryptedStorageSettings();
encodedPassword = utf8Encode(password);
salt = crypto.getRandomValues(settings.saltLenght);
key = deriveArgon2Key(encodedPassword, salt, settings.rounds);
chunks = splitFileIntoChunks(file, 65536);
for each chunk:
iv = crypto.getRandomValues(12);
encryptedChunk = AES_GCM_Encrypt(chunk, key, iv);
storeInBlob(encryptedChunk, iv, chunk.length);
createDownloadLink(blob);
Decryption Process
Decryption meticulously reverses the encryption, ensuring data integrity:
- Header Verification : Check that the file or text header begins with the identifier byte
0x01
to confirm it was encrypted with Encrypti0n.com. - Retrieve Encryption Parameters : Extract the salt and the Argon2 round count from the header.
- Key Derivation : Using extracted parameters, derive the correct 256-bit key.
- AES-GCM Decryption : Perform decryption using AES-GCM with the derived key and nonce included within each chunk or encrypted text segment.
Below is a sample code snippet that illustrates how AES-GCM decryption is generally performed on this site using a javscript-ish pseudo-code:
header = readFileHeader(encryptedData);
verify(header.startsWith(0x01));
salt, rounds = extractHeaderParameters(header);
key = deriveArgon2Key(encodedPassword, salt, rounds);
decryptedData = AES_GCM_Decrypt(encryptedChunks, key, iv);
outputOriginalData(decryptedData);
Encrypt Application (App Data Protection)
Envelope-Encryption Stack:
DEK (Data-Encryption-Key)
- Random 256-bit AES-GCM key
- Generated once per browser profile for encryption/decryption of local data
KEK (Key-Encryption-Key)
Two modes:
- Password-less: non-extractable, origin-bound WebCrypto key (
DeviceKeyProvider
) - Master-password: Argon2id-derived key from user password
CryptoKey
handle.- Password-less: non-extractable, origin-bound WebCrypto key (
Authenticated Encryption
AES-GCM (96-bit IV, 128-bit tag) with integrity check on every read.
Key Lifetimes
- Non-exportable DEK (usable just for
encrypt/decrypt
) in RAM only while unlocked - KEK handle only during DEK-unwrapping
- No raw key material exportable to JS
- Non-exportable DEK (usable just for
Code Examples:
{
"header": {
"v": 2,
"salt": "",
"rounds": 1,
"iv": "Zhg/WsALMJYanZsW",
"wrappedKey": "AAAA…=="
},
"data": {
"iv": "V0hzptZKrwI5wHbJ",
"ciphertext": "xxxxxx__secured_data"
}
}
{
"header": {
"v": 2,
"salt": "FtBVivCpev4+G0uqAn7Z5w==",
"rounds": 20,
"iv": "TQ5fMPx4cx5y5Yoi",
"wrappedKey": "BBBB…=="
},
"data": {
"iv": "2E1P2gN9rtRfTmcR",
"ciphertext": "xxxxxx__secured_data"
}
}
1. First run / reset
// generate a fresh DEK
dek = crypto.generateAesGcmKey(256);
// pick a KEK
if (userSetsMasterPassword) {
salt = randomSalt(); // crypto.getRandomValues(16-bytes)
rounds = randomRounds(); // 20-21
kek = argon2id(masterPassword, salt, rounds); // 64MiB memory used
} else {
kek = DeviceKeyProvider.getKey(); // IndexedDB
salt = ""; rounds = 1;
}
// wrap DEK + store
ivWrap, wrappedKey = AES_GCM_Wrap(dek, kek);
storeHeader({ v:2, salt, rounds, iv:ivWrap, wrappedKey });
storeData({ iv:"", ciphertext:"" });
2. Unlock session
header = readHeader();
if (header.rounds > 1) {
kek = argon2id(promptPassword(), header.salt, header.rounds);
} else {
kek = DeviceKeyProvider.getKey();
}
dek = AES_GCM_Unwrap(header.wrappedKey, kek, header.iv);
3. Encrypt / decrypt data
// save
ivData, cipher = AES_GCM_Encrypt(plainData, dek);
storeData({ iv:ivData, ciphertext:cipher });
// load
{ iv, ciphertext } = readData();
plainData = AES_GCM_Decrypt(ciphertext, dek, iv);
Key Rotation & Password Management:
- Set / Change password:
DEK is temporarily unwrapped (extractable:true
), re-wrapped under the new KEK, then re-imported as non-extractable. - Remove password:
Reverse flow: re-wrap DEK with device key, update header.
With this layered approach, an attacker needs both the encrypted payload AND either your master password or physical access to the device key store.