Skip to content

Instantly share code, notes, and snippets.

@viperadnan-git
Created June 21, 2025 19:56
Show Gist options
  • Save viperadnan-git/c046926899438cbf3061d2057a9b8fed to your computer and use it in GitHub Desktop.
Save viperadnan-git/c046926899438cbf3061d2057a9b8fed to your computer and use it in GitHub Desktop.
Encrypt/Decrypt Class for Web and Python
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript Crypt Class</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.container {
background: white;
border-radius: 10px;
padding: 30px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}
h1 {
color: #333;
text-align: center;
margin-bottom: 30px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
color: #555;
}
input, textarea {
width: 100%;
padding: 10px;
border: 2px solid #ddd;
border-radius: 5px;
font-size: 14px;
box-sizing: border-box;
}
textarea {
height: 100px;
resize: vertical;
}
button {
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
border: none;
padding: 12px 24px;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
margin-right: 10px;
margin-bottom: 10px;
transition: transform 0.2s;
}
button:hover {
transform: translateY(-2px);
}
.result {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 5px;
padding: 15px;
margin-top: 20px;
word-break: break-all;
}
.error {
background: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
}
.success {
background: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
}
</style>
</head>
<body>
<div class="container">
<h1>JavaScript Crypt Class Demo</h1>
<div class="form-group">
<label for="passphrase">Passphrase:</label>
<input type="password" id="passphrase" placeholder="Enter your passphrase">
</div>
<div class="form-group">
<label for="plaintext">Text to Encrypt:</label>
<textarea id="plaintext" placeholder="Enter text to encrypt"></textarea>
</div>
<div class="form-group">
<label for="encrypted">Encrypted Text (hex_code-iv):</label>
<textarea id="encrypted" placeholder="Enter encrypted text to decrypt"></textarea>
</div>
<button onclick="encryptText()">Encrypt</button>
<button onclick="decryptText()">Decrypt</button>
<button onclick="testCrypt()">Test Example</button>
<div id="result"></div>
<div style="margin-top: 30px; padding: 20px; background: #f8f9fa; border-radius: 5px;">
<h3>Code:</h3>
<pre style="background: #2d3748; color: #e2e8f0; padding: 15px; border-radius: 5px; overflow-x: auto; font-size: 12px;">
class Crypt {
constructor(passphrase) {
this.passphrase = passphrase;
}
async deriveKey(salt) {
const encoder = new TextEncoder();
const keyMaterial = await crypto.subtle.importKey(
'raw',
encoder.encode(this.passphrase),
{ name: 'PBKDF2' },
false,
['deriveKey']
);
return await crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt: salt,
iterations: 100000,
hash: 'SHA-256'
},
keyMaterial,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt', 'decrypt']
);
}
async encrypt(text) {
const encoder = new TextEncoder();
const data = encoder.encode(text);
const salt = crypto.getRandomValues(new Uint8Array(16));
const iv = crypto.getRandomValues(new Uint8Array(12));
const key = await this.deriveKey(salt);
const encrypted = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv: iv },
key,
data
);
const combined = new Uint8Array(salt.length + encrypted.byteLength);
combined.set(salt);
combined.set(new Uint8Array(encrypted), salt.length);
const hexCode = Array.from(combined)
.map(b => b.toString(16).padStart(2, '0'))
.join('');
const ivHex = Array.from(iv)
.map(b => b.toString(16).padStart(2, '0'))
.join('');
return `${hexCode}-${ivHex}`;
}
async decrypt(encryptedText) {
const [hexCode, ivHex] = encryptedText.split('-');
if (!hexCode || !ivHex) {
throw new Error('Invalid encrypted text format');
}
const combined = new Uint8Array(
hexCode.match(/.{2}/g).map(byte => parseInt(byte, 16))
);
const iv = new Uint8Array(
ivHex.match(/.{2}/g).map(byte => parseInt(byte, 16))
);
const salt = combined.slice(0, 16);
const encrypted = combined.slice(16);
const key = await this.deriveKey(salt);
const decrypted = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv: iv },
key,
encrypted
);
const decoder = new TextDecoder();
return decoder.decode(decrypted);
}
}
</pre>
</div>
</div>
<script>
class Crypt {
constructor(passphrase) {
this.passphrase = passphrase;
}
async deriveKey(salt) {
const encoder = new TextEncoder();
const keyMaterial = await crypto.subtle.importKey(
'raw',
encoder.encode(this.passphrase),
{ name: 'PBKDF2' },
false,
['deriveKey']
);
return await crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt: salt,
iterations: 100000,
hash: 'SHA-256'
},
keyMaterial,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt', 'decrypt']
);
}
async encrypt(text) {
const encoder = new TextEncoder();
const data = encoder.encode(text);
const salt = crypto.getRandomValues(new Uint8Array(16));
const iv = crypto.getRandomValues(new Uint8Array(12));
const key = await this.deriveKey(salt);
const encrypted = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv: iv },
key,
data
);
// Combine salt and encrypted data
const combined = new Uint8Array(salt.length + encrypted.byteLength);
combined.set(salt);
combined.set(new Uint8Array(encrypted), salt.length);
// Convert to hex
const hexCode = Array.from(combined)
.map(b => b.toString(16).padStart(2, '0'))
.join('');
const ivHex = Array.from(iv)
.map(b => b.toString(16).padStart(2, '0'))
.join('');
return `${hexCode}-${ivHex}`;
}
async decrypt(encryptedText) {
const [hexCode, ivHex] = encryptedText.split('-');
if (!hexCode || !ivHex) {
throw new Error('Invalid encrypted text format');
}
// Convert hex back to bytes
const combined = new Uint8Array(
hexCode.match(/.{2}/g).map(byte => parseInt(byte, 16))
);
const iv = new Uint8Array(
ivHex.match(/.{2}/g).map(byte => parseInt(byte, 16))
);
// Extract salt and encrypted data
const salt = combined.slice(0, 16);
const encrypted = combined.slice(16);
const key = await this.deriveKey(salt);
const decrypted = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv: iv },
key,
encrypted
);
const decoder = new TextDecoder();
return decoder.decode(decrypted);
}
}
function showResult(message, isError = false) {
const resultDiv = document.getElementById('result');
resultDiv.className = `result ${isError ? 'error' : 'success'}`;
resultDiv.textContent = message;
}
async function encryptText() {
try {
const passphrase = document.getElementById('passphrase').value;
const plaintext = document.getElementById('plaintext').value;
if (!passphrase || !plaintext) {
showResult('Please enter both passphrase and text to encrypt', true);
return;
}
const crypt = new Crypt(passphrase);
const encrypted = await crypt.encrypt(plaintext);
document.getElementById('encrypted').value = encrypted;
showResult(`Encrypted: ${encrypted}`);
} catch (error) {
showResult(`Encryption error: ${error.message}`, true);
}
}
async function decryptText() {
try {
const passphrase = document.getElementById('passphrase').value;
const encrypted = document.getElementById('encrypted').value;
if (!passphrase || !encrypted) {
showResult('Please enter both passphrase and encrypted text', true);
return;
}
const crypt = new Crypt(passphrase);
const decrypted = await crypt.decrypt(encrypted);
document.getElementById('plaintext').value = decrypted;
showResult(`Decrypted: ${decrypted}`);
} catch (error) {
showResult(`Decryption error: ${error.message}`, true);
}
}
async function testCrypt() {
try {
const testPassphrase = 'my-secret-passphrase-123';
const testText = 'Hello, World! This is a test message.';
document.getElementById('passphrase').value = testPassphrase;
document.getElementById('plaintext').value = testText;
const crypt = new Crypt(testPassphrase);
const encrypted = await crypt.encrypt(testText);
const decrypted = await crypt.decrypt(encrypted);
document.getElementById('encrypted').value = encrypted;
if (decrypted === testText) {
showResult(`Test successful! Encrypted: ${encrypted.substring(0, 50)}...`);
} else {
showResult('Test failed: Decrypted text does not match original', true);
}
} catch (error) {
showResult(`Test error: ${error.message}`, true);
}
}
</script>
</body>
</html>
import hashlib
import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
class Crypt:
def __init__(self, passphrase):
"""
Initialize the Crypt class with a passphrase
Args:
passphrase (str): The passphrase used for encryption/decryption
"""
if not isinstance(passphrase, str):
raise ValueError("Passphrase must be a string")
self.passphrase = passphrase.encode('utf-8')
def _derive_key(self, salt):
"""
Derive a 256-bit key from the passphrase using PBKDF2
Args:
salt (bytes): Salt for key derivation
Returns:
bytes: 32-byte derived key
"""
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32, # 256 bits
salt=salt,
iterations=100000,
backend=default_backend()
)
return kdf.derive(self.passphrase)
def encrypt(self, text):
"""
Encrypt text using AES-256-GCM
Args:
text (str): The text to encrypt
Returns:
str: Encrypted text in format (hex_code)-(iv)
"""
if not isinstance(text, str):
raise ValueError("Text must be a string")
# Generate random salt and IV
salt = os.urandom(16) # 128-bit salt
iv = os.urandom(12) # 96-bit IV for GCM mode
# Derive key from passphrase
key = self._derive_key(salt)
# Create cipher and encrypt
cipher = Cipher(
algorithms.AES(key),
modes.GCM(iv),
backend=default_backend()
)
encryptor = cipher.encryptor()
# Encrypt the text
plaintext = text.encode('utf-8')
ciphertext = encryptor.update(plaintext) + encryptor.finalize()
# Get the authentication tag
auth_tag = encryptor.tag
# Combine salt, ciphertext, and auth_tag
combined = salt + ciphertext + auth_tag
# Convert to hex
hex_code = combined.hex()
iv_hex = iv.hex()
return f"{hex_code}-{iv_hex}"
def decrypt(self, encrypted_text):
"""
Decrypt text that was encrypted with the encrypt method
Args:
encrypted_text (str): Encrypted text in format (hex_code)-(iv)
Returns:
str: Decrypted plaintext
"""
if not isinstance(encrypted_text, str):
raise ValueError("Encrypted text must be a string")
try:
# Split the encrypted text
hex_code, iv_hex = encrypted_text.split('-')
# Convert hex back to bytes
combined = bytes.fromhex(hex_code)
iv = bytes.fromhex(iv_hex)
# Extract components
salt = combined[:16] # First 16 bytes are salt
auth_tag = combined[-16:] # Last 16 bytes are auth tag
ciphertext = combined[16:-16] # Middle part is ciphertext
# Derive key from passphrase
key = self._derive_key(salt)
# Create cipher and decrypt
cipher = Cipher(
algorithms.AES(key),
modes.GCM(iv, auth_tag),
backend=default_backend()
)
decryptor = cipher.decryptor()
# Decrypt the ciphertext
plaintext = decryptor.update(ciphertext) + decryptor.finalize()
return plaintext.decode('utf-8')
except ValueError as e:
raise ValueError(f"Invalid encrypted text format: {e}")
except Exception as e:
raise ValueError(f"Decryption failed: {e}")
# Example usage and testing
if __name__ == "__main__":
# Test the Crypt class
print("Testing Python Crypt Class")
print("=" * 40)
# Initialize with a passphrase
passphrase = "my-secret-passphrase-123"
crypt = Crypt(passphrase)
# Test text
original_text = "Hello, World! This is a test message with special characters: àáâãäåæçèé"
print(f"Original text: {original_text}")
# Encrypt
try:
encrypted = crypt.encrypt(original_text)
print(f"Encrypted: {encrypted}")
print(f"Encrypted length: {len(encrypted)} characters")
# Decrypt
decrypted = crypt.decrypt(encrypted)
print(f"Decrypted: {decrypted}")
# Verify
if original_text == decrypted:
print("✅ Test PASSED: Encryption and decryption successful!")
else:
print("❌ Test FAILED: Decrypted text doesn't match original")
except Exception as e:
print(f"❌ Test FAILED: {e}")
print("\n" + "=" * 40)
print("Testing with different passphrases")
# Test with wrong passphrase
try:
wrong_crypt = Crypt("wrong-passphrase")
wrong_crypt.decrypt(encrypted)
print("❌ Security FAILED: Wrong passphrase should not decrypt")
except ValueError:
print("✅ Security PASSED: Wrong passphrase correctly rejected")
# Test edge cases
print("\nTesting edge cases:")
# Empty string
try:
empty_encrypted = crypt.encrypt("")
empty_decrypted = crypt.decrypt(empty_encrypted)
print(f"✅ Empty string test: '{empty_decrypted}' (length: {len(empty_decrypted)})")
except Exception as e:
print(f"❌ Empty string test failed: {e}")
# Unicode text
try:
unicode_text = "🔒 Encryption test with emojis 🌟 and Unicode: αβγδε"
unicode_encrypted = crypt.encrypt(unicode_text)
unicode_decrypted = crypt.decrypt(unicode_encrypted)
if unicode_text == unicode_decrypted:
print("✅ Unicode test passed")
else:
print("❌ Unicode test failed")
except Exception as e:
print(f"❌ Unicode test failed: {e}")
# Long text
try:
long_text = "A" * 10000 # 10KB of text
long_encrypted = crypt.encrypt(long_text)
long_decrypted = crypt.decrypt(long_encrypted)
if long_text == long_decrypted:
print(f"✅ Long text test passed (10KB encrypted to {len(long_encrypted)} chars)")
else:
print("❌ Long text test failed")
except Exception as e:
print(f"❌ Long text test failed: {e}")
"""
Installation Requirements:
pip install cryptography
Note: This implementation uses the 'cryptography' library which is the recommended
cryptographic library for Python. It provides secure implementations of AES encryption.
Key Features:
- Uses AES-256-GCM for authenticated encryption
- PBKDF2 for key derivation with 100,000 iterations
- Random salt for each encryption (prevents rainbow table attacks)
- Random IV for each encryption (prevents pattern analysis)
- Authentication tag prevents tampering
- Handles Unicode text properly
- Comprehensive error handling
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment