Final Kyber Burner Email WEB v1
Final Kyber Burner Email WEB v1
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Kyber Burner Email Web v1.0</title>
<script src="https://cdn.jsdelivr.net/npm/@pq-crystals/kyber@0.1.0/dist/kyber.js"></script>
<script src="https://cdn.jsdelivr.net/npm/crypto-js@4.1.1/crypto-js.js"></script>
<script src="https://cdn.jsdelivr.net/npm/qrcode@1.5.3/build/qrcode.min.js"></script>
<style>
body { font-family: system-ui; max-width: 600px; margin: 2rem auto; padding: 1rem; background: #f9f9fb; }
h1 { text-align: center; }
.mode { display: flex; gap: 1rem; margin-bottom: 1rem; }
.mode button { flex: 1; padding: 0.8rem; font-weight: bold; border: none; cursor: pointer; background: #eee; }
.mode button.active { background: #007acc; color: white; }
textarea { width: 100%; height: 100px; margin: 1rem 0; padding: 0.5rem; }
#qr-canvas { margin: 1rem 0; text-align: center; }
button { background: #007acc; color: white; border: none; padding: 0.8rem 1.2rem; margin: 0.5rem; border-radius: 6px; cursor: pointer; }
.status { margin-top: 1rem; font-weight: bold; }
#file-input { margin: 1rem 0; }
</style>
</head>
<body>
<h1>Kyber Burner Email Web v1.0</h1>
<p>Send a message that burns in 10 minutes</p>
<div class="mode">
<button class="active" onclick="setMode(true)">Sender</button>
<button onclick="setMode(false)">Receiver</button>
</div>
<div id="sender">
<textarea id="message" placeholder="Type your message..."></textarea>
<button onclick="generateSenderQR()">Generate QR</button>
<div id="qr-canvas"></div>
<button id="send-btn" style="display:none" onclick="encryptAndDownload()">Encrypt & Download</button>
</div>
<div id="receiver" style="display:none;">
<button onclick="generateReceiverQR()">Generate My QR</button>
<div id="receiver-qr"></div>
<input type="file" id="file-input" accept=".bin" style="display:none;" onchange="decryptFile(this.files[0])"/>
<button onclick="document.getElementById('file-input').click()">Choose Message File</button>
<div id="decrypted"></div>
</div>
<div class="status" id="status"></div>
<script>
let isSender = true;
let senderPK, senderSK, receiverPK;
let messageText;
function setMode(sender) {
isSender = sender;
document.querySelectorAll('.mode button').forEach(b => b.classList.remove('active'));
document.querySelector(`.mode button:nth-child(${sender ? 1 : 2})`).classList.add('active');
document.getElementById('sender').style.display = sender ? 'block' : 'none';
document.getElementById('receiver').style.display = sender ? 'none' : 'block';
clearAll();
}
function clearAll() {
document.getElementById('qr-canvas').innerHTML = '';
document.getElementById('receiver-qr').innerHTML = '';
document.getElementById('decrypted').innerHTML = '';
document.getElementById('status').innerHTML = '';
document.getElementById('send-btn').style.display = 'none';
}
async function generateSenderQR() {
const msg = document.getElementById('message').value;
if (!msg) return alert("Enter a message");
messageText = msg;
const kp = await kyber.keypair();
senderPK = kp.publicKey;
senderSK = kp.privateKey;
const qr = await QRCode.toCanvas(document.createElement('canvas'), new Uint8Array(senderPK));
document.getElementById('qr-canvas').innerHTML = '';
document.getElementById('qr-canvas').appendChild(qr);
document.getElementById('status').innerHTML = "Show QR to receiver";
document.getElementById('send-btn').style.display = 'block';
}
async function encryptAndDownload() {
// Assume receiver PK scanned manually or via file
const pkHex = prompt("Paste receiver public key (hex):");
if (!pkHex) return;
receiverPK = hexToBytes(pkHex);
const { ciphertext, sharedSecret } = await kyber.encapsulate(receiverPK);
const key = await deriveKey(sharedSecret);
const encrypted = await encryptAES(key, messageText);
const blob = new Blob([new Uint8Array(ciphertext), encrypted], { type: 'application/octet-stream' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'burnermsg.bin';
a.click();
document.getElementById('status').innerHTML = "Message saved. Burns in 10 min.";
setTimeout(() => URL.revokeObjectURL(url), 600000);
}
async function generateReceiverQR() {
const kp = await kyber.keypair();
const pk = kp.publicKey;
const sk = kp.privateKey;
const qr = await QRCode.toCanvas(document.createElement('canvas'), new Uint8Array(pk));
document.getElementById('receiver-qr').innerHTML = '';
document.getElementById('receiver-qr').appendChild(qr);
document.getElementById('status').innerHTML = "Show QR to sender";
// Store SK in memory
window.receiverSK = sk;
}
async function decryptFile(file) {
if (!window.receiverSK) return alert("Generate your QR first");
const data = new Uint8Array(await file.arrayBuffer());
const ct = data.slice(0, 1184);
const enc = data.slice(1184);
const shared = await kyber.decapsulate(ct, window.receiverSK);
const key = await deriveKey(shared);
const decrypted = await decryptAES(key, enc);
document.getElementById('decrypted').innerHTML = `<p><strong>Message:</strong> ${decrypted}</p>`;
document.getElementById('status').innerHTML = "Message will burn in 10 minutes...";
setTimeout(() => {
document.getElementById('decrypted').innerHTML = '';
document.getElementById('status').innerHTML = "Message burned.";
delete window.receiverSK;
}, 600000);
}
async function deriveKey(shared) {
const hash = await crypto.subtle.digest('SHA-256', shared);
return crypto.subtle.importKey('raw', hash.slice(0, 16), 'AES-GCM', false, ['encrypt', 'decrypt']);
}
async function encryptAES(key, text) {
const iv = crypto.getRandomValues(new Uint8Array(12));
const data = new TextEncoder().encode(text);
const ct = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, data);
const result = new Uint8Array(iv.byteLength + ct.byteLength);
result.set(iv, 0);
result.set(new Uint8Array(ct), iv.byteLength);
return result;
}
async function decryptAES(key, data) {
const iv = data.slice(0, 12);
const ct = data.slice(12);
const pt = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ct);
return new TextDecoder().decode(pt);
}
function hexToBytes(hex) {
return Uint8Array.from(hex.match(/.{1,2}/g).map(b => parseInt(b, 16)));
}
</script>
</body>
</html>
```
---
**FINAL_Web_v1.0.html**
- **Sender**: Type message → **Generate QR** → show → paste receiver PK → download `burnermsg.bin`
- **Receiver**: **Generate My QR** → show → **Choose Message File** → decrypt → auto-burn after 10 min
---
**Next?**
Say: **Make PWA**
→ I’ll give you **FINAL_PWA_v1.0** (installable)
**Go.**