<!-- Crypto-Text US
With this tool you can securely encrypt open texts. Everything remains strictly local, both the text and the key. You can then save the encrypted text in for example Simplenote and access and decrypt it on all connected devices. The easiest way to save and use it:
Select and copy this note completely on PC with Ctrl plus A and Ctrl plus C. Open a text editor (Notepad is best or WORD etc). Paste the code and save the file under any name with the extension .html, for example Crypto.html or Crypto\_hint.html (hint: clue to the password): the filename will be displayed in the tool for your guidance!
Attention with Word and LibreOffice: Normal saving often destroys the code. When saving, choose the file type Plain Text (.txt), and manually rename the file extension to .html. Alternatively, save in Word as Web Page, Filtered (.html).
Double-click the file. It opens immediately securely and offline in any web browser. Save as a bookmark.
Mobile phone: If you know how to create a text file, great. If not: Send the finished file from your PC to yourself as an email attachment or save it in a cloud. Download, done.
Security notice for shipping to third parties: This tool uses the worldwide industry standard AES-256-GCM. If you send the encrypted text by email, you must use a different path for the password, for example Signal or WhatsApp. Send the password there without text or reference to the email. Since attackers would have to crack two completely separate systems at the same time, this procedure is extremely secure.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Text-crypt</title>
<style>
body { font-family: sans-serif; max-width: 600px; margin: 15px auto; padding: 10px; background: #f9f9f9; }
.layout-wrapper { max-width: 550px; margin-right: auto; position: relative; }
h2 { margin-bottom: 2px; font-size: 22px; }
.filename-display { font-size: 13px; color: #555; font-style: italic; margin-bottom: 15px; display: block; }
.grid-row { display: flex; align-items: center; gap: 10px; margin: 5px 0 15px 0; width: 100%; }
.pw-input-wrap { position: relative; flex: 1; display: flex; align-items: center; }
.pw-input-wrap input { width: 100%; padding: 10px; padding-right: 40px; box-sizing: border-box; font-size: 14px; }
.eye-btn { position: absolute; right: 10px; cursor: pointer; background: none; border: none; font-size: 18px; padding: 0; color: #555; }
textarea { flex: 1; height: 150px; box-sizing: border-box; font-family: monospace; font-size: 14px; padding: 10px; display: block; resize: vertical; }
.trash-btn { cursor: pointer; background: #e0e0e0; border: 1px solid #b5b5b5; padding: 6px 9px; border-radius: 4px; display: flex; align-items: center; justify-content: center; min-width: 38px; height: 38px; box-sizing: border-box; }
.trash-btn:hover { background: #d0d0d0; border-color: #999; }
.trash-btn svg { width: 20px; height: 20px; fill: none; stroke: #000000; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.textarea-row .trash-btn { height: 150px; align-self: flex-start; }
.btn-group { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; width: calc(100% - 48px); }
button.action-btn { padding: 12px; cursor: pointer; color: white; border: none; border-radius: 4px; font-weight: bold; font-size: 14px; text-align: center; }
.btn-paste { background: #6c757d; }
.btn-encrypt { background: #007BFF; }
.btn-decrypt { background: #28A745; }
.btn-copy { background: #17a2b8; }
button:active { opacity: 0.8; }
</style>
</head>
<body>
<div class="layout-wrapper">
<h2>Text-crypt (AES)</h2>
<span id="filename" class="filename-display">(loading filename...)</span>
<label>Password:</label>
<div class="grid-row">
<div class="pw-input-wrap">
<input type="text" id="password" placeholder="Enter your password">
<button class="eye-btn" onclick="togglePasswordVisibility()">👁</button>
</div>
<button class="trash-btn" onclick="clearField('password')" title="Clear password">
<svg viewBox="0 0 24 24"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>
</button>
</div>
<label>Plaintext or Cryptotext:</label>
<div class="grid-row textarea-row">
<textarea id="textData" placeholder="Insert text here..."></textarea>
<button class="trash-btn" onclick="clearField('textData')" title="Clear text">
<svg viewBox="0 0 24 24"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>
</button>
</div>
<div class="btn-group">
<button class="action-btn btn-paste" onclick="pasteText()">[ Paste ]</button>
<button class="action-btn btn-encrypt" onclick="process(true)">Encrypt</button>
<button class="action-btn btn-decrypt" onclick="process(false)">Decrypt</button>
<button class="action-btn btn-copy" onclick="copyText()">[ Copy ]</button>
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", () => {
try {
const urlParts = window.location.href.split('/');
let filename = urlParts[urlParts.length - 1];
filename = filename.split('#')[0].split('?')[0];
filename = decodeURIComponent(filename);
if (filename && filename.includes('.')) {
document.getElementById("filename").innerText = filename;
} else {
document.getElementById("filename").innerText = "local_file.html";
}
} catch (e) {
document.getElementById("filename").innerText = "crypt.html";
}
});
function clearField(id) {
const field = document.getElementById(id);
field.value = "";
field.focus();
}
async function deriveKey(passwordStr, salt) {
const enc = new TextEncoder();
const keyMaterial = await crypto.subtle.importKey("raw", enc.encode(passwordStr), "PBKDF2", false, ["deriveKey"]);
return crypto.subtle.deriveKey(
{ name: "PBKDF2", salt: salt, iterations: 100000, hash: "SHA-256" },
keyMaterial, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]
);
}
async function process(isEncrypt) {
const password = document.getElementById("password").value;
const textArea = document.getElementById("textData");
if (!password) { alert("Please enter a password!"); return; }
if (!textArea.value) { alert("Please enter text!"); return; }
try {
if (isEncrypt) {
const salt = crypto.getRandomValues(new Uint8Array(16));
const iv = crypto.getRandomValues(new Uint8Array(12));
const key = await deriveKey(password, salt);
const encodedText = new TextEncoder().encode(textArea.value);
const encrypted = await crypto.subtle.encrypt({ name: "AES-GCM", iv: iv }, key, encodedText);
const combined = new Uint8Array(salt.length + iv.length + encrypted.byteLength);
combined.set(salt, 0); combined.set(iv, salt.length); combined.set(new Uint8Array(encrypted), salt.length + iv.length);
let binary = "";
for (let i = 0; i < combined.length; i++) binary += String.fromCharCode(combined[i]);
textArea.value = btoa(binary);
} else {
const binary = atob(textArea.value.trim());
const combined = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) combined[i] = binary.charCodeAt(i);
const salt = combined.slice(0, 16); const iv = combined.slice(16, 28); const encrypted = combined.slice(28);
const key = await deriveKey(password, salt);
const decrypted = await crypto.subtle.decrypt({ name: "AES-GCM", iv: iv }, key, encrypted);
textArea.value = new TextDecoder().decode(decrypted);
}
autoSelectText();
} catch (e) {
alert("Error! Wrong password or corrupted cryptotext.");
}
}
function autoSelectText() { const t = document.getElementById("textData"); t.focus(); t.select(); t.setSelectionRange(0, 99999); }
function togglePasswordVisibility() { const p = document.getElementById("password"); p.type = (p.type === "password") ? "text" : "password"; }
async function pasteText() {
const textArea = document.getElementById("textData");
try { textArea.value = await navigator.clipboard.readText(); } catch (err) { textArea.value = ""; textArea.focus(); }
}
async function copyText() {
try { await navigator.clipboard.writeText(document.getElementById("textData").value); autoSelectText(); } catch (err) { alert("Copy failed."); }
}
</script>
</body>
</html>