|
47 | 47 | <button type="button" onclick="decrypt()">Decrypt</button> |
48 | 48 | </div> |
49 | 49 | </body> |
50 | | - <script> |
51 | | - // JavaScript to handle tab switching |
52 | | - function showTabContent(tabId) { |
53 | | - // Hide all tab content |
54 | | - const contents = document.querySelectorAll('.tab-content'); |
55 | | - contents.forEach(content => content.classList.remove('active')); |
56 | | - |
57 | | - // Show the selected tab content |
58 | | - const selectedTab = document.getElementById(tabId); |
59 | | - selectedTab.classList.add('active'); |
60 | | - } |
61 | | - |
62 | | - // Convert a string to BigInt using fixed-width (5 digits) encoding |
63 | | - function stringToBigInt(str) { |
64 | | - // Pad each char code to 5 digits to ensure unambiguous decoding |
65 | | - let charCodes = Array.from(str).map(char => char.charCodeAt(0).toString().padStart(5, '0')).join(''); |
66 | | - return BigInt(charCodes); |
| 50 | +<script> |
| 51 | + // Helper: Convert a string to ArrayBuffer |
| 52 | + function strToBuf(str) { |
| 53 | + return new TextEncoder().encode(str); |
67 | 54 | } |
68 | | - |
69 | | - // Convert a BigInt back to a string, decoding in fixed-width (5 digits) |
70 | | - function bigIntToString(bigInt) { |
71 | | - let strRepresentation = bigInt.toString(); |
72 | | - // Pad left if string length is not a multiple of 5 |
73 | | - if (strRepresentation.length % 5 !== 0) { |
74 | | - strRepresentation = strRepresentation.padStart(Math.ceil(strRepresentation.length / 5) * 5, '0'); |
75 | | - } |
76 | | - const charCodes = []; |
77 | | - for (let i = 0; i < strRepresentation.length; i += 5) { |
78 | | - let code = parseInt(strRepresentation.slice(i, i+5), 10); |
79 | | - charCodes.push(code); |
80 | | - } |
81 | | - return charCodes.map(code => String.fromCharCode(code)).join(''); |
| 55 | + function bufToStr(buf) { |
| 56 | + return new TextDecoder().decode(buf); |
| 57 | + } |
| 58 | + function bufToB64(buf) { |
| 59 | + return btoa(String.fromCharCode(...new Uint8Array(buf))); |
| 60 | + } |
| 61 | + function b64ToBuf(b64) { |
| 62 | + return Uint8Array.from(atob(b64), c => c.charCodeAt(0)); |
82 | 63 | } |
83 | 64 |
|
84 | | - // Helper function to compute SHA-256 hash |
85 | | - async function sha256(message) { |
86 | | - const encoder = new TextEncoder(); |
87 | | - const data = encoder.encode(message); |
88 | | - const hashBuffer = await crypto.subtle.digest('SHA-256', data); |
89 | | - const hashArray = Array.from(new Uint8Array(hashBuffer)); |
90 | | - return hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); |
91 | | - } |
92 | | - |
93 | | - // Function to handle Encrypt button click |
94 | | - async function encrypt() { |
95 | | - const key = document.getElementById('key').value; // Get the encryption key |
96 | | - let num = document.getElementById('num').value; // Get the message number |
97 | | - const plaintext = document.getElementById('plaintext').value; // Get the plaintext |
98 | | - |
99 | | - // Validate inputs |
100 | | - if (!key || !plaintext) { |
101 | | - alert("Please provide both an encryption key and plaintext."); |
102 | | - return; |
103 | | - } |
104 | | - |
105 | | - // Set the message number to a random number if it is 0 or not set |
106 | | - if (!num || num === "0") { |
107 | | - num = Math.floor(Math.random() * 1000000); // Generate a random number (e.g., between 0 and 999999) |
108 | | - document.getElementById('num').value = num; // Update the input field with the random number |
109 | | - } |
110 | | - |
111 | | - const bigintplaintext = stringToBigInt(plaintext); |
112 | | - |
113 | | - // Compute hashes |
114 | | - const keyHash = await sha256(key); |
115 | | - const numHash = await sha256(num); |
116 | | - |
117 | | - // Convert hexadecimal hash values to BigInt for multiplication |
118 | | - const keyBigInt = BigInt('0x' + keyHash); |
119 | | - const numBigInt = BigInt('0x' + numHash); |
120 | | - |
121 | | - // Multiply the two hashes |
122 | | - const multipliedHashBigInt = keyBigInt * numBigInt; |
123 | | - |
124 | | - // Take the hash of the result |
125 | | - const finalHash = await sha256(multipliedHashBigInt.toString()); |
126 | | - |
127 | | - console.log('Final Hash:', finalHash); |
| 65 | + // Helper: SHA-256 as hex string |
| 66 | + async function sha256(message) { |
| 67 | + const data = strToBuf(message); |
| 68 | + const hashBuffer = await crypto.subtle.digest('SHA-256', data); |
| 69 | + return Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join(''); |
| 70 | + } |
128 | 71 |
|
129 | | - // `finalHash` is for encryption logic |
130 | | - const bigintciphertext = bigintplaintext * BigInt('0x' + finalHash); |
| 72 | + // Derive AES key from SHA-256 hex (finalHash) |
| 73 | + async function hashToKey(hashHex) { |
| 74 | + const raw = Uint8Array.from(hashHex.match(/.{2}/g).map(b => parseInt(b, 16))); |
| 75 | + return crypto.subtle.importKey( |
| 76 | + "raw", raw, "AES-GCM", false, ["encrypt", "decrypt"] |
| 77 | + ); |
| 78 | + } |
131 | 79 |
|
132 | | - const ciphertext = bigIntToString(bigintciphertext); |
| 80 | + // Compute finalHash using your logic |
| 81 | + async function getFinalHash(key, num) { |
| 82 | + const keyHash = await sha256(key); |
| 83 | + const numHash = await sha256(num); |
| 84 | + const keyBigInt = BigInt('0x' + keyHash); |
| 85 | + const numBigInt = BigInt('0x' + numHash); |
| 86 | + const multiplied = keyBigInt * numBigInt; |
| 87 | + return sha256(multiplied.toString()); |
| 88 | + } |
133 | 89 |
|
134 | | - document.getElementById('ciphertext').value = ciphertext; |
| 90 | + async function encrypt() { |
| 91 | + const keyStr = document.getElementById('key').value; |
| 92 | + let num = document.getElementById('num').value; |
| 93 | + const plaintext = document.getElementById('plaintext').value; |
| 94 | + if (!keyStr || !plaintext) return alert("Provide key and plaintext."); |
135 | 95 |
|
136 | | - showTabContent('tab2'); |
| 96 | + if (!num || num === "0") { |
| 97 | + num = Math.floor(Math.random() * 1000000); |
| 98 | + document.getElementById('num').value = num; |
137 | 99 | } |
138 | 100 |
|
139 | | - // Function to handle Decrypt button click |
140 | | - async function decrypt() { |
141 | | - const key = document.getElementById('key').value; // Get the encryption key |
142 | | - const num = document.getElementById('num').value; // Get the message number |
143 | | - const ciphertext = document.getElementById('ciphertext').value; // Get the ciphertext |
144 | | - |
145 | | - // Validate inputs |
146 | | - if (!key || !ciphertext) { |
147 | | - alert("Please provide both an encryption key and ciphertext."); |
148 | | - return; |
149 | | - } |
150 | | - |
151 | | - // Compute hashes |
152 | | - const keyHash = await sha256(key); |
153 | | - const numHash = await sha256(num); |
154 | | - |
155 | | - // Convert hexadecimal hash values to BigInt for multiplication |
156 | | - const keyBigInt = BigInt('0x' + keyHash); |
157 | | - const numBigInt = BigInt('0x' + numHash); |
158 | | - |
159 | | - // Multiply the two hashes |
160 | | - const multipliedHashBigInt = keyBigInt * numBigInt; |
161 | | - |
162 | | - // Take the hash of the result |
163 | | - const finalHash = await sha256(multipliedHashBigInt.toString()); |
164 | | - |
165 | | - console.log('Final Hash for Decryption:', finalHash); |
166 | | - |
167 | | - // `finalHash` is for decryption logic |
168 | | - const bigintciphertext = stringToBigInt(ciphertext); |
169 | | - |
170 | | - const bigintplaintext = bigintciphertext / BigInt('0x' + finalHash); |
171 | | - |
172 | | - const plaintext = bigIntToString(bigintplaintext); |
173 | | - |
174 | | - document.getElementById('plaintext').value = plaintext; |
| 101 | + const finalHash = await getFinalHash(keyStr, num); |
| 102 | + const aesKey = await hashToKey(finalHash); |
| 103 | + const iv = crypto.getRandomValues(new Uint8Array(12)); |
| 104 | + const ctBuf = await crypto.subtle.encrypt( |
| 105 | + { name: "AES-GCM", iv }, aesKey, strToBuf(plaintext) |
| 106 | + ); |
| 107 | + // Output: base64(iv + ciphertext) |
| 108 | + const full = new Uint8Array([...iv, ...new Uint8Array(ctBuf)]); |
| 109 | + document.getElementById('ciphertext').value = bufToB64(full); |
| 110 | + showTabContent('tab2'); |
| 111 | + } |
175 | 112 |
|
| 113 | + async function decrypt() { |
| 114 | + const keyStr = document.getElementById('key').value; |
| 115 | + const num = document.getElementById('num').value; |
| 116 | + const b64 = document.getElementById('ciphertext').value; |
| 117 | + if (!keyStr || !num || !b64) return alert("Provide key, message number, and ciphertext."); |
| 118 | + |
| 119 | + const full = b64ToBuf(b64); |
| 120 | + const iv = full.slice(0, 12); |
| 121 | + const ct = full.slice(12); |
| 122 | + const finalHash = await getFinalHash(keyStr, num); |
| 123 | + const aesKey = await hashToKey(finalHash); |
| 124 | + |
| 125 | + try { |
| 126 | + const ptBuf = await crypto.subtle.decrypt( |
| 127 | + { name: "AES-GCM", iv }, aesKey, ct |
| 128 | + ); |
| 129 | + document.getElementById('plaintext').value = bufToStr(ptBuf); |
176 | 130 | showTabContent('tab1'); |
| 131 | + } catch { |
| 132 | + alert("Decryption failed! (wrong key/message number or data corrupted)"); |
177 | 133 | } |
178 | | - </script> |
| 134 | + } |
| 135 | + |
| 136 | + // Tab logic (unchanged) |
| 137 | + function showTabContent(tabId) { |
| 138 | + document.querySelectorAll('.tab-content').forEach( |
| 139 | + c => c.classList.remove('active')); |
| 140 | + document.getElementById(tabId).classList.add('active'); |
| 141 | + } |
| 142 | +</script> |
179 | 143 | </html> |
180 | 144 | |
0 commit comments