Encrypt / Decrypt
Encrypts and decrypts text or files in your browser using a passphrase you choose.
Content type
Keep it somewhere safe — lost, the content is unrecoverable — 0/256
Up to 2.00 MB
What this tool is
Encrypts and decrypts text or files entirely in your browser, using a passphrase only you know — nothing is sent to any server, not even Nexinon's own. It's the equivalent of GPG or a password-protected 7-Zip, without installing anything: paste a text or drop a file, type a passphrase, and get a copyable encrypted block or a .nex file to download. The reverse direction works with the same passphrase, here or anywhere that reimplements the open format described at the end of this page.
How it works
The passphrase is never used directly as a key — it goes through PBKDF2-SHA-256 with 1,000,000 iterations and a random salt, producing a 256-bit AES-256-GCM key. Every operation draws a fresh salt and IV, so encrypting the same content twice with the same passphrase produces different results. AES-GCM is authenticated: any bit changed in the encrypted content — by accident or tampering — makes decryption fail on purpose, instead of silently returning a corrupted result.
About the passphrase
The passphrase is the only way to recover the content — there's no account, no "forgot my password", by design: Nexinon never stores anything. Lose the passphrase and the encrypted content is unrecoverable forever, even for whoever built Nexinon. The encryption is only as strong as the passphrase that derives the key — prefer a long, unpredictable phrase over a short password, or generate one with the Password Generator.
Frequently asked questions
The encrypted content is unrecoverable forever — there's no recovery process, not even through Nexinon. That's the tool's security guarantee, not a limitation: if there were a way to recover without the passphrase, it would also be a way for someone else to access the content without it.
AES-GCM is an authenticated cipher — it checks a cryptographic seal before returning any byte. A wrong passphrase and tampered content land on the exact same error, on purpose: telling the two apart would give an attacker a faster way to test passphrases.
It's an identifiable prefix — it makes clear, at a glance, that the block is an Encrypt/Decrypt envelope, and already embeds the format version (the "1"). The rest is the full binary envelope, encoded as Base64url to fit a single-line text field.
Yes — that's this tool's central commitment. The format is documented byte by byte at the bottom of this page, along with a dependency-free Node.js reference implementation, just to prove it works outside Nexinon.
Because execution is 100% local — Nexinon never sees the content, encrypted or not, so there would be nothing to keep without also sending something to a server, which would contradict the whole point of the tool. Every operation starts from scratch.
Yes — every operation draws a fresh salt and IV, so two files encrypted with the same passphrase have no visible relationship to each other, even if the original content is identical.
The tool refuses with a warning — the format internally records whether the original content was text or a file, so a wrong-mode attempt is caught before showing any result.
Yes: 2 MB for text and 100 MB for files (both ways, encrypting and decrypting). It's not a limit of AES-GCM itself — the Web Crypto API processes everything in memory in this version, so the real ceiling is your device's memory; 100 MB was chosen as a generous yet conservative value, to avoid risking a freeze on a more modest device. Worth revisiting if a legitimate case runs into it.
By default, it doesn't — the file name alone can reveal what the content is about (e.g. "diagnosis.pdf") to anyone who sees the encrypted file in a shared Drive or email, even without being able to decrypt anything. The "Keep the original name on the downloaded file" option, in File mode, turns this on when organizing multiple files matters more than hiding the name. Either way, the original name always comes back when decrypting — it lives inside the encrypted content itself, not in the downloaded file's name.
Format specification
This tool's central commitment: anything encrypted here can be decrypted without Nexinon, today or years from now. Below is the complete binary envelope layout and a minimal, dependency-free reference implementation you can review, adapt, or reimplement in any language.
Envelope layout
Envelope (binary .nex file, or the same content as Base64url inside a "nex1:<...>" text block): offset size field description 0 4 bytes magic ASCII "NXEC" — format signature 4 1 byte version 0x01 in this version 5 4 bytes kdf_iterations uint32 big-endian — PBKDF2-SHA-256 iteration count 9 16 bytes salt PBKDF2 salt, random per operation 25 12 bytes iv AES-GCM nonce, random per operation 37 rest ciphertext+tag AES-256-GCM(plaintext), with the 16-byte tag already appended at the end Key: PBKDF2-SHA-256(passphrase, salt, kdf_iterations, 32 bytes) → AES-256-GCM key. plaintext (the field above, only after decryption): offset size field description 0 1 byte kind 0x00 = text · 0x01 = file --- kind = 0x00 (text) --- 1 rest text the original text, UTF-8 --- kind = 0x01 (file) --- 1 2 bytes name_length uint16 big-endian — name size in bytes 3 name_length name original file name, UTF-8 3+name_length rest file_bytes original file content, with no transformation at all
Reference implementation (Node.js, no dependencies)
Decrypts a "nex1:..." block or a .nex file from the command line: node decrypt-nex.js <file> <passphrase>.
#!/usr/bin/env node
// Decrypts a .nex file or a "nex1:..." text block from Encrypt/Decrypt
// (NXEC v1 format) without depending on Nexinon — just Node's built-in
// "crypto" module, no external dependency at all.
// Usage: node decrypt-nex.js <file.nex or block.txt> <passphrase>
const fs = require('fs')
const crypto = require('crypto')
const [, , inputPath, passphrase] = process.argv
const raw = fs.readFileSync(inputPath)
const asText = raw.toString('utf8')
// A "nex1:<Base64url>" text block or a plain binary .nex file — the
// same envelope in both cases, only the outer encoding changes.
const envelope = asText.startsWith('nex1:')
? Buffer.from(asText.slice(5).trim().replace(/-/g, '+').replace(/_/g, '/'), 'base64')
: raw
if (envelope.subarray(0, 4).toString('ascii') !== 'NXEC') {
throw new Error('Missing NXEC signature')
}
if (envelope[4] !== 1) {
throw new Error('Unsupported format version')
}
const iterations = envelope.readUInt32BE(5)
const salt = envelope.subarray(9, 25)
const iv = envelope.subarray(25, 37)
const ciphertextAndTag = envelope.subarray(37)
// The Web Crypto API appends the 16-byte authentication tag to the end
// of the ciphertext — Node requires the two apart.
const tag = ciphertextAndTag.subarray(-16)
const ciphertext = ciphertextAndTag.subarray(0, -16)
const key = crypto.pbkdf2Sync(passphrase, salt, iterations, 32, 'sha256')
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv)
decipher.setAuthTag(tag)
// Throws if the passphrase is wrong or the envelope was tampered with.
const inner = Buffer.concat([decipher.update(ciphertext), decipher.final()])
const kind = inner[0]
if (kind === 0) {
// Text.
process.stdout.write(inner.subarray(1).toString('utf8') + '\n')
} else {
// File — original name embedded right before the content.
const nameLength = inner.readUInt16BE(1)
const fileName = inner.subarray(3, 3 + nameLength).toString('utf8')
fs.writeFileSync(fileName, inner.subarray(3 + nameLength))
console.error(`Restored file: ${fileName}`)
}