Skip to content
This repository was archived by the owner on May 29, 2025. It is now read-only.

Commit 1243897

Browse files
authored
Update index.html
Signed-off-by: Blake Arnold <[email protected]>
1 parent 79a0229 commit 1243897

File tree

1 file changed

+105
-45
lines changed

1 file changed

+105
-45
lines changed

index.html

Lines changed: 105 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<html>
22
<head>
33
<style>
4-
/* Add basic styles for tabs */
54
.tab {
65
background: #f7f7f7;
76
border: 1px solid #bbb;
@@ -17,41 +16,34 @@
1716
top: 1px;
1817
transition: background 0.2s;
1918
}
20-
2119
#tabs {
2220
display: flex;
2321
flex-direction: row;
24-
margin-bottom: -1px; /* aligns with tab borders */
22+
margin-bottom: -1px;
2523
}
26-
2724
.tab.active {
2825
background: #fff;
2926
font-weight: bold;
3027
border-color: #888 #888 #fff #888;
3128
z-index: 1;
3229
}
33-
3430
.tab:not(.active):hover {
3531
background: #ececec;
3632
}
37-
38-
.tab-content {
39-
display: none;
40-
border: 1px solid #ccc;
41-
padding: 15px;
42-
margin-top: 10px;
43-
}
44-
45-
.tab-content.active {
46-
display: block !important;
47-
}
33+
.tab-content {
34+
display: none;
35+
border: 1px solid #ccc;
36+
padding: 15px;
37+
margin-top: 10px;
38+
}
39+
.tab-content.active {
40+
display: block !important;
41+
}
4842
</style>
4943
</head>
5044
<body>
5145
<input type="text" placeholder="encryption key" id="key">
5246
<input type="number" placeholder="message number" id="num">
53-
54-
<!-- Tabs -->
5547
<div id="tabs">
5648
<div class="tab" onclick="showTabContent('tab1')">Encrypt</div>
5749
<div class="tab" onclick="showTabContent('tab2')">Decrypt</div>
@@ -60,6 +52,9 @@
6052
Plaintext:
6153
<textarea id="plaintext"></textarea>
6254
<button type="button" onclick="encrypt()">Encrypt</button>
55+
<input type="file" id="fileInput" style="display:none" />
56+
<button type="button" onclick="document.getElementById('fileInput').click()">Attach File</button>
57+
<button type="button" id="downloadAttachedBtn" style="display:none" onclick="downloadAttachedFile()">Download Attached File</button>
6358
</div>
6459
<div id="tab2" class="tab-content">
6560
Ciphertext:
@@ -69,7 +64,6 @@
6964
</body>
7065
<script>
7166
showTabContent('tab1')
72-
// Helper: Convert a string to ArrayBuffer
7367
function strToBuf(str) {
7468
return new TextEncoder().encode(str);
7569
}
@@ -82,23 +76,17 @@
8276
function b64ToBuf(b64) {
8377
return Uint8Array.from(atob(b64), c => c.charCodeAt(0));
8478
}
85-
86-
// Helper: SHA-256 as hex string
8779
async function sha256(message) {
8880
const data = strToBuf(message);
8981
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
9082
return Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join('');
9183
}
92-
93-
// Derive AES key from SHA-256 hex (finalHash)
9484
async function hashToKey(hashHex) {
9585
const raw = Uint8Array.from(hashHex.match(/.{2}/g).map(b => parseInt(b, 16)));
9686
return crypto.subtle.importKey(
9787
"raw", raw, "AES-GCM", false, ["encrypt", "decrypt"]
9888
);
9989
}
100-
101-
// Compute finalHash using your logic
10290
async function getFinalHash(key, num) {
10391
const keyHash = await sha256(key);
10492
const numHash = await sha256(num);
@@ -108,26 +96,72 @@
10896
return sha256(multiplied.toString());
10997
}
11098

99+
let attachedFile = null;
100+
let attachedFilename = "";
101+
let lastDecryptedFile = null;
102+
let lastDecryptedFilename = "";
103+
104+
document.getElementById('fileInput').addEventListener('change', function(evt) {
105+
if (evt.target.files.length > 0) {
106+
attachedFile = evt.target.files[0];
107+
attachedFilename = attachedFile.name;
108+
document.getElementById('downloadAttachedBtn').style.display = "none";
109+
} else {
110+
attachedFile = null;
111+
attachedFilename = "";
112+
}
113+
});
114+
115+
function fileToBase64(file) {
116+
return new Promise((resolve, reject) => {
117+
const reader = new FileReader();
118+
reader.onload = e => resolve(btoa(e.target.result));
119+
reader.onerror = reject;
120+
reader.readAsBinaryString(file);
121+
});
122+
}
123+
function base64ToUint8Array(b64) {
124+
var binary = atob(b64);
125+
var len = binary.length;
126+
var bytes = new Uint8Array(len);
127+
for (var i = 0; i < len; i++) {
128+
bytes[i] = binary.charCodeAt(i);
129+
}
130+
return bytes;
131+
}
132+
111133
async function encrypt() {
112134
const keyStr = document.getElementById('key').value;
113135
let num = document.getElementById('num').value;
114136
const plaintext = document.getElementById('plaintext').value;
115137
if (!keyStr || !plaintext) return alert("Provide key and plaintext.");
116-
117138
if (!num || num === "0") {
118139
num = Math.floor(Math.random() * 1000000);
119140
document.getElementById('num').value = num;
120141
}
121-
142+
let envelope = null;
143+
if (attachedFile) {
144+
const fileDataB64 = await fileToBase64(attachedFile);
145+
envelope = JSON.stringify({
146+
t: plaintext,
147+
f: attachedFilename,
148+
d: fileDataB64
149+
});
150+
} else {
151+
envelope = JSON.stringify({ t: plaintext });
152+
}
122153
const finalHash = await getFinalHash(keyStr, num);
123154
const aesKey = await hashToKey(finalHash);
124155
const iv = crypto.getRandomValues(new Uint8Array(12));
125156
const ctBuf = await crypto.subtle.encrypt(
126-
{ name: "AES-GCM", iv }, aesKey, strToBuf(plaintext)
157+
{ name: "AES-GCM", iv }, aesKey, strToBuf(envelope)
127158
);
128-
// Output: base64(iv + ciphertext)
129159
const full = new Uint8Array([...iv, ...new Uint8Array(ctBuf)]);
130160
document.getElementById('ciphertext').value = bufToB64(full);
161+
attachedFile = null;
162+
attachedFilename = "";
163+
document.getElementById('fileInput').value = "";
164+
document.getElementById('downloadAttachedBtn').style.display = "none";
131165
showTabContent('tab2');
132166
}
133167

@@ -136,37 +170,63 @@
136170
const num = document.getElementById('num').value;
137171
const b64 = document.getElementById('ciphertext').value;
138172
if (!keyStr || !num || !b64) return alert("Provide key, message number, and ciphertext.");
139-
140-
const full = b64ToBuf(b64);
173+
const full = b64ToBuf(b64.trim());
141174
const iv = full.slice(0, 12);
142175
const ct = full.slice(12);
143176
const finalHash = await getFinalHash(keyStr, num);
144177
const aesKey = await hashToKey(finalHash);
145-
146178
try {
147179
const ptBuf = await crypto.subtle.decrypt(
148180
{ name: "AES-GCM", iv }, aesKey, ct
149181
);
150-
document.getElementById('plaintext').value = bufToStr(ptBuf);
182+
const envelopeStr = bufToStr(ptBuf);
183+
let envelope;
184+
try {
185+
envelope = JSON.parse(envelopeStr);
186+
} catch {
187+
throw new Error('Corrupted decrypted data');
188+
}
189+
document.getElementById('plaintext').value = envelope.t || "";
190+
if (envelope.f && envelope.d) {
191+
lastDecryptedFile = base64ToUint8Array(envelope.d);
192+
lastDecryptedFilename = envelope.f;
193+
document.getElementById('downloadAttachedBtn').style.display = "inline";
194+
} else {
195+
lastDecryptedFile = null;
196+
lastDecryptedFilename = "";
197+
document.getElementById('downloadAttachedBtn').style.display = "none";
198+
}
151199
showTabContent('tab1');
152200
} catch {
153201
alert("Decryption failed! (wrong key/message number or data corrupted)");
154202
}
155203
}
156204

157-
// Tab logic
205+
function downloadAttachedFile() {
206+
if (!lastDecryptedFile || !lastDecryptedFilename) return;
207+
const blob = new Blob([lastDecryptedFile]);
208+
const url = URL.createObjectURL(blob);
209+
const a = document.createElement('a');
210+
a.href = url;
211+
a.download = lastDecryptedFilename;
212+
document.body.appendChild(a);
213+
a.click();
214+
setTimeout(() => {
215+
document.body.removeChild(a);
216+
URL.revokeObjectURL(url);
217+
}, 100);
218+
}
219+
158220
function showTabContent(tabId) {
159-
document.querySelectorAll('.tab-content').forEach(
160-
c => c.classList.remove('active'));
161-
document.getElementById(tabId).classList.add('active');
162-
// Add this to update tab styling
163-
document.querySelectorAll('#tabs .tab').forEach(tab => tab.classList.remove('active'));
164-
if (tabId === 'tab1') {
165-
document.querySelectorAll('#tabs .tab')[0].classList.add('active');
166-
} else {
167-
document.querySelectorAll('#tabs .tab')[1].classList.add('active');
221+
document.querySelectorAll('.tab-content').forEach(
222+
c => c.classList.remove('active'));
223+
document.getElementById(tabId).classList.add('active');
224+
document.querySelectorAll('#tabs .tab').forEach(tab => tab.classList.remove('active'));
225+
if (tabId === 'tab1') {
226+
document.querySelectorAll('#tabs .tab')[0].classList.add('active');
227+
} else {
228+
document.querySelectorAll('#tabs .tab')[1].classList.add('active');
229+
}
168230
}
169-
}
170231
</script>
171232
</html>
172-

0 commit comments

Comments
 (0)