Skip to content

Commit

Permalink
u
Browse files Browse the repository at this point in the history
  • Loading branch information
hadithmv committed Dec 13, 2024
1 parent 08862d9 commit 6c970c2
Show file tree
Hide file tree
Showing 2 changed files with 331 additions and 2 deletions.
165 changes: 163 additions & 2 deletions page-uc/textEditor.html
Original file line number Diff line number Diff line change
Expand Up @@ -2855,17 +2855,178 @@ <h4>🌙 Islamic Night Time Calculator</h4>
possible alternative?: https://github.com/paulgreg/crypttool
for large strings, use this from https://stackoverflow.com/a/49124600
?for large strings, use this from https://stackoverflow.com/a/49124600
...
prompt:
id like to be able encrypt and decrypt text using AES-GCM, here is some sample code on how others have done it, to give you an idea, but you arent restricted to it, and feel free to change it as much as you want:
id like text areas to show what is to be encrypted and decrypted
but i dont want alerts, i want to be able to password without alerts.
encrypted and decrypted text should have a copy button for each that copies the text to the clipboard
there should also be text instructions on how this works, what the user should do
id like the solution to be modern, responsive and nice looking
-->

<h4>🔒 Text Encryption and Decryption</h4>

<style>
.crypt-container {
display: flex;
gap: 2rem;
padding: 1rem;
}

@media (max-width: 768px) {
.crypt-container {
flex-direction: column;
}
}

.crypt-section {
flex: 1;
min-width: 300px;
}

.crypt-section h3 {
margin-bottom: 1rem;
color: #333;
}

.instructions {
font-size: 0.9rem;
color: #666;
margin-bottom: 1rem;
line-height: 1.4;
}

.password-container {
display: flex;
gap: 0.5rem;
margin: 1rem 0;
}

.password-container input {
flex: 1;
padding: 0.5rem;
border: 1px solid #ccc;
border-radius: 4px;
}

.crypt-button {
padding: 0.5rem 1rem;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}

.crypt-button:hover {
background-color: #0056b3;
}

.result-container {
position: relative;
}

.result-container textarea {
width: 100%;
min-height: 100px;
padding: 0.5rem;
margin-bottom: 0.5rem;
border: 1px solid #ccc;
border-radius: 4px;
resize: vertical;
}

.result-container .copy-button {
position: absolute;
right: 0.5rem;
top: 0.5rem;
padding: 0.25rem 0.5rem;
background-color: white;
border: 1px solid #ccc;
border-radius: 4px;
cursor: pointer;
}
</style>

<div class="crypt-container">
<div class="crypt-section">
<h3>Encrypt Text</h3>
<p class="instructions">
1. Enter text to encrypt below<br />
2. Enter a password in the password field<br />
3. Click "Encrypt" to generate encrypted text
</p>
<textarea
id="textToEncrypt"
placeholder="Enter text to encrypt..."
></textarea>
<div class="password-container">
<input
type="password"
id="encryptPassword"
placeholder="Enter password"
/>
<button id="encryptButton" class="crypt-button">Encrypt</button>
</div>
<div class="result-container">
<textarea
id="encryptedText"
readonly
placeholder="Encrypted text will appear here..."
></textarea>
<button id="copyEncrypted" class="copy-button">Copy 📋</button>
</div>
</div>

<div class="crypt-section">
<h3>Decrypt Text</h3>
<p class="instructions">
1. Paste encrypted text below<br />
2. Enter the same password used for encryption<br />
3. Click "Decrypt" to reveal original text
</p>
<textarea
id="textToDecrypt"
placeholder="Enter encrypted text..."
></textarea>
<div class="password-container">
<input
type="password"
id="decryptPassword"
placeholder="Enter password"
/>
<button id="decryptButton" class="crypt-button">Decrypt</button>
</div>
<div class="result-container">
<textarea
id="decryptedText"
readonly
placeholder="Decrypted text will appear here..."
></textarea>
<button id="copyDecrypted" class="copy-button">Copy 📋</button>
</div>
</div>
</div>

<!--
...
file encryption and decryption
https://github.com/hazelfazel/Web-Browser-Based-AES-GCM-File-Encryption-Decryption
possible alternative?, but uses cbc, not gcm: https://github.com/meixler/web-browser-based-file-encryption-decryption
for large strings, use this from https://stackoverflow.com/a/49124600
?for large strings, use this from https://stackoverflow.com/a/49124600
-->

<!-- -->
Expand Down
168 changes: 168 additions & 0 deletions page-uc/textEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -3252,5 +3252,173 @@ two input boxes next to this button, saying "Find" and "Replace" as placeholders

// =====================================================

// Add these utility functions at the top of your file
const buff_to_base64 = (buff) =>
btoa(
new Uint8Array(buff).reduce(
(data, byte) => data + String.fromCharCode(byte),
""
)
);

const base64_to_buf = (b64) =>
Uint8Array.from(atob(b64), (c) => c.charCodeAt(null));

const enc = new TextEncoder();
const dec = new TextDecoder();

// Add these crypto helper functions
const getPasswordKey = (password) =>
window.crypto.subtle.importKey(
"raw",
enc.encode(password),
"PBKDF2",
false,
["deriveKey"]
);

const deriveKey = (passwordKey, salt, keyUsage) =>
window.crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: salt,
iterations: 250000,
hash: "SHA-256",
},
passwordKey,
{ name: "AES-GCM", length: 256 },
false,
keyUsage
);

// Main encryption function
async function encryptData(secretData, password) {
try {
const salt = window.crypto.getRandomValues(new Uint8Array(16));
const iv = window.crypto.getRandomValues(new Uint8Array(12));
const passwordKey = await getPasswordKey(password);
const aesKey = await deriveKey(passwordKey, salt, ["encrypt"]);
const encryptedContent = await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv,
},
aesKey,
enc.encode(secretData)
);

const encryptedContentArr = new Uint8Array(encryptedContent);
let buff = new Uint8Array(
salt.byteLength + iv.byteLength + encryptedContentArr.byteLength
);
buff.set(salt, 0);
buff.set(iv, salt.byteLength);
buff.set(encryptedContentArr, salt.byteLength + iv.byteLength);
const base64Buff = buff_to_base64(buff);
return base64Buff;
} catch (e) {
console.error(`Encryption error: ${e}`);
throw e;
}
}

// Main decryption function
async function decryptData(encryptedData, password) {
try {
const encryptedDataBuff = base64_to_buf(encryptedData);
const salt = encryptedDataBuff.slice(0, 16);
const iv = encryptedDataBuff.slice(16, 16 + 12);
const data = encryptedDataBuff.slice(16 + 12);
const passwordKey = await getPasswordKey(password);
const aesKey = await deriveKey(passwordKey, salt, ["decrypt"]);
const decryptedContent = await window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv,
},
aesKey,
data
);
return dec.decode(decryptedContent);
} catch (e) {
console.error(`Decryption error: ${e}`);
throw e;
}
}

//

// Encryption/Decryption functionality
const encryptButton = document.getElementById("encryptButton");
const decryptButton = document.getElementById("decryptButton");
const copyEncrypted = document.getElementById("copyEncrypted");
const copyDecrypted = document.getElementById("copyDecrypted");

if (encryptButton) {
encryptButton.addEventListener("click", async () => {
const text = document.getElementById("textToEncrypt").value;
const password = document.getElementById("encryptPassword").value;

if (!text || !password) {
showButtonFeedback(encryptButton, "Please fill all fields");
return;
}

try {
const encrypted = await encryptData(text, password);
document.getElementById("encryptedText").value = encrypted;
showButtonFeedback(encryptButton, "Encrypted");
} catch (error) {
console.error("Encryption failed:", error);
showButtonFeedback(encryptButton, "Encryption failed");
}
});
}

if (decryptButton) {
decryptButton.addEventListener("click", async () => {
const text = document.getElementById("textToDecrypt").value;
const password = document.getElementById("decryptPassword").value;

if (!text || !password) {
showButtonFeedback(decryptButton, "Please fill all fields");
return;
}

try {
const decrypted = await decryptData(text, password);
document.getElementById("decryptedText").value =
decrypted || "Decryption failed";
showButtonFeedback(decryptButton, decrypted ? "Decrypted" : "Failed");
} catch (error) {
console.error("Decryption failed:", error);
showButtonFeedback(decryptButton, "Decryption failed");
}
});
}

// Copy buttons
if (copyEncrypted) {
copyEncrypted.addEventListener("click", () => {
const text = document.getElementById("encryptedText").value;
if (text) {
navigator.clipboard.writeText(text);
showButtonFeedback(copyEncrypted, "Copied");
}
});
}

if (copyDecrypted) {
copyDecrypted.addEventListener("click", () => {
const text = document.getElementById("decryptedText").value;
if (text) {
navigator.clipboard.writeText(text);
showButtonFeedback(copyDecrypted, "Copied");
}
});
}

// =====================================================

// END
}); // document.addEventListener("DOMContentLoaded", () => {

0 comments on commit 6c970c2

Please sign in to comment.