// Import our WebAssembly module
import init, {
create_key_space,
encrypt_key_space,
decrypt_key_space,
logout,
create_keypair,
select_keypair,
list_keypairs,
keypair_pub_key,
keypair_sign,
keypair_verify,
derive_public_key,
verify_with_public_key,
encrypt_asymmetric,
decrypt_asymmetric,
generate_symmetric_key,
derive_key_from_password,
encrypt_symmetric,
decrypt_symmetric,
encrypt_with_password,
decrypt_with_password,
// KVS functions
kv_store_init,
kv_store_put,
kv_store_get,
kv_store_delete,
kv_store_exists,
kv_store_list_keys,
kv_store_put_object,
kv_store_get_object
} from '../../pkg/webassembly.js';
// Helper function to convert ArrayBuffer to hex string
function bufferToHex(buffer) {
return Array.from(new Uint8Array(buffer))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
}
// Helper function to convert hex string to Uint8Array
function hexToBuffer(hex) {
const bytes = new Uint8Array(hex.length / 2);
for (let i = 0; i < hex.length; i += 2) {
bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
}
return bytes;
}
// Session management
let lastActivity = Date.now();
let logoutTimer = null;
const AUTO_LOGOUT_TIME = 15 * 60 * 1000; // 15 minutes
// Update last activity timestamp
function updateActivity() {
lastActivity = Date.now();
}
// Check for inactivity and logout if needed
function checkInactivity() {
const inactiveTime = Date.now() - lastActivity;
if (inactiveTime > AUTO_LOGOUT_TIME) {
performLogout();
alert('You have been logged out due to inactivity.');
}
}
// Setup auto-logout timer
function setupAutoLogout() {
logoutTimer = setInterval(checkInactivity, 60000); // Check every minute
}
// Clear auto-logout timer
function clearAutoLogout() {
if (logoutTimer) {
clearInterval(logoutTimer);
logoutTimer = null;
}
}
// KVS setup and functions
const DB_NAME = 'CryptoSpaceDB';
const STORE_NAME = 'keySpaces';
// Initialize the database
async function initDatabase() {
try {
await kv_store_init(DB_NAME, STORE_NAME);
console.log('KV store initialized successfully');
return true;
} catch (error) {
console.error('Error initializing KV store:', error);
return false;
}
}
// Save encrypted space to KV store
async function saveSpaceToStorage(spaceName, encryptedData) {
try {
// Create a space object with metadata
const space = {
name: spaceName,
encryptedData: encryptedData,
created: new Date().toISOString(),
lastAccessed: new Date().toISOString()
};
// Convert to JSON string
const spaceJson = JSON.stringify(space);
// Store in KV store
await kv_store_put(DB_NAME, STORE_NAME, spaceName, spaceJson);
console.log('Space saved successfully:', spaceName);
return true;
} catch (error) {
console.error('Error saving space:', error);
throw error;
}
}
// Get encrypted space from KV store
async function getSpaceFromStorage(spaceName) {
try {
// Get from KV store
const spaceJson = await kv_store_get(DB_NAME, STORE_NAME, spaceName);
if (!spaceJson) {
console.log('Space not found:', spaceName);
return null;
}
// Parse JSON
const space = JSON.parse(spaceJson);
// Update last accessed timestamp
updateLastAccessed(spaceName).catch(console.error);
// Debug what we're getting back
console.log('Retrieved space from KV store with type:', {
type: typeof space.encryptedData,
length: space.encryptedData ? space.encryptedData.length : 0,
isString: typeof space.encryptedData === 'string'
});
return space.encryptedData;
} catch (error) {
console.error('Error retrieving space:', error);
return null;
}
}
// Update last accessed timestamp
async function updateLastAccessed(spaceName) {
try {
// Get the current space data
const spaceJson = await kv_store_get(DB_NAME, STORE_NAME, spaceName);
if (spaceJson) {
// Parse JSON
const space = JSON.parse(spaceJson);
// Update timestamp
space.lastAccessed = new Date().toISOString();
// Save back to KV store
await kv_store_put(DB_NAME, STORE_NAME, spaceName, JSON.stringify(space));
}
} catch (error) {
console.error('Error updating last accessed timestamp:', error);
}
}
// List all spaces in KV store
async function listSpacesFromStorage() {
try {
// Get all keys with empty prefix (all keys)
const keys = await kv_store_list_keys(DB_NAME, STORE_NAME, "");
return keys;
} catch (error) {
console.error('Error listing spaces:', error);
return [];
}
}
// Remove space from KV store
async function removeSpaceFromStorage(spaceName) {
try {
await kv_store_delete(DB_NAME, STORE_NAME, spaceName);
console.log('Space removed successfully:', spaceName);
return true;
} catch (error) {
console.error('Error removing space:', error);
return false;
}
}
// Session state
let isLoggedIn = false;
let currentSpace = null;
let selectedKeypair = null;
// Update UI based on login state
async function updateLoginUI() {
const loginForm = document.getElementById('login-form');
const logoutForm = document.getElementById('logout-form');
const loginStatus = document.getElementById('login-status');
const currentSpaceName = document.getElementById('current-space-name');
if (isLoggedIn) {
loginForm.classList.add('hidden');
logoutForm.classList.remove('hidden');
loginStatus.textContent = 'Status: Logged in';
loginStatus.className = 'status logged-in';
currentSpaceName.textContent = currentSpace;
} else {
loginForm.classList.remove('hidden');
logoutForm.classList.add('hidden');
loginStatus.textContent = 'Status: Not logged in';
loginStatus.className = 'status logged-out';
currentSpaceName.textContent = '';
}
// Update the spaces list
try {
await updateSpacesList();
} catch (e) {
console.error('Error updating spaces list in UI:', e);
}
}
// Update the spaces dropdown list
async function updateSpacesList() {
const spacesList = document.getElementById('space-list');
// Clear existing options
while (spacesList.options.length > 1) {
spacesList.remove(1);
}
try {
// Get spaces list
const spaces = await listSpacesFromStorage();
// Add options for each space
spaces.forEach(spaceName => {
const option = document.createElement('option');
option.value = spaceName;
option.textContent = spaceName;
spacesList.appendChild(option);
});
} catch (e) {
console.error('Error updating spaces list:', e);
}
}
// Login to a space
async function performLogin() {
const spaceName = document.getElementById('space-name').value.trim();
const password = document.getElementById('space-password').value;
if (!spaceName || !password) {
document.getElementById('space-result').textContent = 'Please enter both space name and password';
return;
}
try {
// Show loading state
document.getElementById('space-result').textContent = 'Loading...';
// Get encrypted space from IndexedDB
console.log('Fetching space from IndexedDB:', spaceName);
const encryptedSpace = await getSpaceFromStorage(spaceName);
if (!encryptedSpace) {
console.error('Space not found in IndexedDB:', spaceName);
document.getElementById('space-result').textContent = `Space "${spaceName}" not found`;
return;
}
console.log('Retrieved space from IndexedDB:', {
spaceName,
encryptedDataLength: encryptedSpace.length,
encryptedDataType: typeof encryptedSpace
});
try {
// Decrypt the space - this is a synchronous WebAssembly function
console.log('Attempting to decrypt space with password...');
const result = decrypt_key_space(encryptedSpace, password);
console.log('Decrypt result:', result);
if (result === 0) {
isLoggedIn = true;
currentSpace = spaceName;
// Save the password in session storage for later use (like when saving)
sessionStorage.setItem('currentPassword', password);
// Update UI and wait for it to complete
console.log('Updating UI...');
await updateLoginUI();
console.log('Updating keypairs list...');
updateKeypairsList();
document.getElementById('space-result').textContent = `Successfully logged in to space "${spaceName}"`;
// Setup auto-logout
updateActivity();
setupAutoLogout();
// Add activity listeners
document.addEventListener('click', updateActivity);
document.addEventListener('keypress', updateActivity);
} else {
console.error('Failed to decrypt space:', result);
document.getElementById('space-result').textContent = `Error logging in: ${result}`;
}
} catch (decryptErr) {
console.error('Decryption error:', decryptErr);
document.getElementById('space-result').textContent = `Decryption error: ${decryptErr}`;
}
} catch (e) {
console.error('Login error:', e);
document.getElementById('space-result').textContent = `Error: ${e}`;
}
}
// Create a new space
async function performCreateSpace() {
const spaceName = document.getElementById('space-name').value.trim();
const password = document.getElementById('space-password').value;
if (!spaceName || !password) {
document.getElementById('space-result').textContent = 'Please enter both space name and password';
return;
}
try {
// Show loading state
document.getElementById('space-result').textContent = 'Loading...';
// Check if space already exists
const existingSpace = await getSpaceFromStorage(spaceName);
if (existingSpace) {
document.getElementById('space-result').textContent = `Space "${spaceName}" already exists`;
return;
}
try {
// Create new space
console.log('Creating new space:', spaceName);
const result = create_key_space(spaceName);
console.log('Create space result:', result);
if (result === 0) {
try {
// Encrypt and save the space
console.log('Encrypting space with password');
const encryptedSpace = encrypt_key_space(password);
console.log('Encrypted space length:', encryptedSpace.length);
// Save to IndexedDB
console.log('Saving to IndexedDB');
await saveSpaceToStorage(spaceName, encryptedSpace);
console.log('Save completed');
isLoggedIn = true;
currentSpace = spaceName;
await updateLoginUI();
updateKeypairsList();
document.getElementById('space-result').textContent = `Successfully created space "${spaceName}"`;
// Setup auto-logout
updateActivity();
setupAutoLogout();
// Add activity listeners
document.addEventListener('click', updateActivity);
document.addEventListener('keypress', updateActivity);
} catch (encryptError) {
console.error('Error encrypting or saving space:', encryptError);
document.getElementById('space-result').textContent = `Error saving space: ${encryptError}`;
}
} else {
document.getElementById('space-result').textContent = `Error creating space: ${result}`;
}
} catch (createError) {
console.error('Error in WebAssembly create_key_space:', createError);
document.getElementById('space-result').textContent = `Error creating key space: ${createError}`;
}
} catch (e) {
console.error('Error checking existing space:', e);
document.getElementById('space-result').textContent = `Error: ${e}`;
}
}
// Logout from current space
function performLogout() {
logout();
isLoggedIn = false;
currentSpace = null;
selectedKeypair = null;
updateLoginUI();
clearKeypairsList();
document.getElementById('space-result').textContent = 'Logged out successfully';
// Clear auto-logout
clearAutoLogout();
// Remove activity listeners
document.removeEventListener('click', updateActivity);
document.removeEventListener('keypress', updateActivity);
}
// Update the keypairs dropdown list
function updateKeypairsList() {
const selectKeypair = document.getElementById('select-keypair');
// Clear existing options
while (selectKeypair.options.length > 1) {
selectKeypair.remove(1);
}
try {
// Get keypairs list
const keypairs = list_keypairs();
// Add options for each keypair
keypairs.forEach(keypairName => {
const option = document.createElement('option');
option.value = keypairName;
option.textContent = keypairName;
selectKeypair.appendChild(option);
});
// If there's a selected keypair, select it in the dropdown
if (selectedKeypair) {
selectKeypair.value = selectedKeypair;
}
} catch (e) {
console.error('Error updating keypairs list:', e);
}
}
// Clear the keypairs dropdown list
function clearKeypairsList() {
const selectKeypair = document.getElementById('select-keypair');
// Clear existing options
while (selectKeypair.options.length > 1) {
selectKeypair.remove(1);
}
// Clear selected keypair display
document.getElementById('selected-pubkey-display').textContent = '';
}
// Create a new keypair
async function performCreateKeypair() {
if (!isLoggedIn) {
document.getElementById('keypair-management-result').textContent = 'Please login first';
return;
}
const keypairName = document.getElementById('keypair-name').value.trim();
if (!keypairName) {
document.getElementById('keypair-management-result').textContent = 'Please enter a keypair name';
return;
}
try {
// Create new keypair
const result = create_keypair(keypairName);
if (result === 0) {
document.getElementById('keypair-management-result').textContent = `Successfully created keypair "${keypairName}"`;
// Update keypairs list
updateKeypairsList();
// Select the new keypair
selectedKeypair = keypairName;
document.getElementById('select-keypair').value = keypairName;
// Display public key
displaySelectedKeypairPublicKey();
// Save the updated space to IndexedDB
saveCurrentSpace();
} else {
document.getElementById('keypair-management-result').textContent = `Error creating keypair: ${result}`;
}
} catch (e) {
document.getElementById('keypair-management-result').textContent = `Error: ${e}`;
}
}
// Select a keypair
async function performSelectKeypair() {
if (!isLoggedIn) {
document.getElementById('keypair-management-result').textContent = 'Please login first';
return;
}
const keypairName = document.getElementById('select-keypair').value;
if (!keypairName) {
document.getElementById('keypair-management-result').textContent = 'Please select a keypair';
return;
}
try {
// Select keypair
const result = select_keypair(keypairName);
if (result === 0) {
selectedKeypair = keypairName;
document.getElementById('keypair-management-result').textContent = `Selected keypair "${keypairName}"`;
// Display public key
displaySelectedKeypairPublicKey();
} else {
document.getElementById('keypair-management-result').textContent = `Error selecting keypair: ${result}`;
}
} catch (e) {
document.getElementById('keypair-management-result').textContent = `Error: ${e}`;
}
}
// Display the public key of the selected keypair
function displaySelectedKeypairPublicKey() {
try {
const pubKey = keypair_pub_key();
const pubKeyHex = bufferToHex(pubKey);
// Create a more user-friendly display with copy button
const pubKeyDisplay = document.getElementById('selected-pubkey-display');
pubKeyDisplay.innerHTML = `
Public Key (hex):
${pubKeyHex}
`;
// Add event listener for the copy button
document.getElementById('copy-pubkey-button').addEventListener('click', () => {
const pubKeyText = document.getElementById('pubkey-hex-value').textContent;
navigator.clipboard.writeText(pubKeyText)
.then(() => {
alert('Public key copied to clipboard!');
})
.catch(err => {
console.error('Could not copy text: ', err);
});
});
// Also populate the public key field in the verify with public key section
document.getElementById('pubkey-verify-pubkey').value = pubKeyHex;
// And in the asymmetric encryption section
document.getElementById('asymmetric-encrypt-pubkey').value = pubKeyHex;
} catch (e) {
document.getElementById('selected-pubkey-display').textContent = `Error getting public key: ${e}`;
}
}
// Save the current space to IndexedDB
async function saveCurrentSpace() {
if (!isLoggedIn || !currentSpace) return;
try {
// Get password from session storage (saved during login)
const password = sessionStorage.getItem('currentPassword');
if (!password) {
console.error('Password not available in session storage');
// Fallback to the password field
const inputPassword = document.getElementById('space-password').value;
if (!inputPassword) {
console.error('Password not available for saving space');
alert('Please re-enter your password to save changes');
return;
}
// Use the input password if session storage isn't available
const encryptedSpace = encrypt_key_space(inputPassword);
console.log('Saving space with input password');
await saveSpaceToStorage(currentSpace, encryptedSpace);
return;
}
// Use the password from session storage
console.log('Encrypting space with session password');
const encryptedSpace = encrypt_key_space(password);
console.log('Saving encrypted space to IndexedDB:', currentSpace);
await saveSpaceToStorage(currentSpace, encryptedSpace);
console.log('Space saved successfully');
} catch (e) {
console.error('Error saving space:', e);
alert('Error saving space: ' + e);
}
}
// Delete a space from IndexedDB
async function deleteSpace(spaceName) {
if (!spaceName) return false;
try {
// Check if space exists
const existingSpace = await getSpaceFromStorage(spaceName);
if (!existingSpace) {
return false;
}
// Remove from IndexedDB
await removeSpaceFromStorage(spaceName);
// If this was the current space, logout
if (isLoggedIn && currentSpace === spaceName) {
performLogout();
}
return true;
} catch (e) {
console.error('Error deleting space:', e);
return false;
}
}
async function run() {
// Initialize the WebAssembly module
await init();
console.log('WebAssembly crypto module initialized!');
// Set up the login/space management
document.getElementById('login-button').addEventListener('click', performLogin);
document.getElementById('create-space-button').addEventListener('click', performCreateSpace);
document.getElementById('logout-button').addEventListener('click', performLogout);
document.getElementById('delete-space-button').addEventListener('click', async () => {
if (confirm(`Are you sure you want to delete the space "${currentSpace}"? This action cannot be undone.`)) {
document.getElementById('space-result').textContent = 'Deleting...';
try {
const result = await deleteSpace(currentSpace);
if (result) {
document.getElementById('space-result').textContent = `Space "${currentSpace}" deleted successfully`;
} else {
document.getElementById('space-result').textContent = `Error deleting space "${currentSpace}"`;
}
} catch (e) {
console.error('Error during space deletion:', e);
document.getElementById('space-result').textContent = `Error: ${e}`;
}
}
});
document.getElementById('delete-selected-space-button').addEventListener('click', async () => {
const selectedSpace = document.getElementById('space-list').value;
if (!selectedSpace) {
document.getElementById('space-result').textContent = 'Please select a space to delete';
return;
}
if (confirm(`Are you sure you want to delete the space "${selectedSpace}"? This action cannot be undone.`)) {
document.getElementById('space-result').textContent = 'Deleting...';
try {
const result = await deleteSpace(selectedSpace);
if (result) {
document.getElementById('space-result').textContent = `Space "${selectedSpace}" deleted successfully`;
await updateSpacesList();
} else {
document.getElementById('space-result').textContent = `Error deleting space "${selectedSpace}"`;
}
} catch (e) {
console.error('Error during space deletion:', e);
document.getElementById('space-result').textContent = `Error: ${e}`;
}
}
});
// Set up the keypair management
document.getElementById('create-keypair-button').addEventListener('click', performCreateKeypair);
document.getElementById('select-keypair').addEventListener('change', performSelectKeypair);
// Set up the signing example
document.getElementById('sign-button').addEventListener('click', () => {
if (!isLoggedIn) {
document.getElementById('signature-result').textContent = 'Please login first';
return;
}
if (!selectedKeypair) {
document.getElementById('signature-result').textContent = 'Please select a keypair first';
return;
}
const message = document.getElementById('sign-message').value;
const messageBytes = new TextEncoder().encode(message);
try {
const signature = keypair_sign(messageBytes);
const signatureHex = bufferToHex(signature);
document.getElementById('signature-result').textContent = `Signature: ${signatureHex}`;
// Store the signature for verification
document.getElementById('verify-signature').value = signatureHex;
document.getElementById('verify-message').value = message;
} catch (e) {
document.getElementById('signature-result').textContent = `Error signing: ${e}`;
}
});
// Set up the verification example
document.getElementById('verify-button').addEventListener('click', () => {
if (!isLoggedIn) {
document.getElementById('verify-result').textContent = 'Please login first';
return;
}
if (!selectedKeypair) {
document.getElementById('verify-result').textContent = 'Please select a keypair first';
return;
}
const message = document.getElementById('verify-message').value;
const messageBytes = new TextEncoder().encode(message);
const signatureHex = document.getElementById('verify-signature').value;
const signatureBytes = hexToBuffer(signatureHex);
try {
const isValid = keypair_verify(messageBytes, signatureBytes);
document.getElementById('verify-result').textContent =
isValid ? 'Signature is valid!' : 'Signature is NOT valid!';
} catch (e) {
document.getElementById('verify-result').textContent = `Error verifying: ${e}`;
}
});
// Set up the symmetric encryption example
document.getElementById('encrypt-button').addEventListener('click', () => {
try {
// Generate key
const key = generate_symmetric_key();
// Display key
const keyHex = bufferToHex(key);
document.getElementById('sym-key-display').textContent = `Key: ${keyHex}`;
// Store for decryption
document.getElementById('decrypt-key').value = keyHex;
// Encrypt the message
const message = document.getElementById('encrypt-message').value;
const messageBytes = new TextEncoder().encode(message);
try {
const ciphertext = encrypt_symmetric(key, messageBytes);
const ciphertextHex = bufferToHex(ciphertext);
document.getElementById('encrypt-result').textContent = `Ciphertext: ${ciphertextHex}`;
// Store for decryption
document.getElementById('decrypt-ciphertext').value = ciphertextHex;
} catch (e) {
document.getElementById('encrypt-result').textContent = `Error encrypting: ${e}`;
}
} catch (e) {
document.getElementById('encrypt-result').textContent = `Error: ${e}`;
}
});
// Set up the symmetric decryption example
document.getElementById('decrypt-button').addEventListener('click', () => {
try {
const keyHex = document.getElementById('decrypt-key').value;
const ciphertextHex = document.getElementById('decrypt-ciphertext').value;
const key = hexToBuffer(keyHex);
const ciphertext = hexToBuffer(ciphertextHex);
try {
const plaintext = decrypt_symmetric(key, ciphertext);
const decodedText = new TextDecoder().decode(plaintext);
document.getElementById('decrypt-result').textContent = `Decrypted: ${decodedText}`;
} catch (e) {
document.getElementById('decrypt-result').textContent = `Error decrypting: ${e}`;
}
} catch (e) {
document.getElementById('decrypt-result').textContent = `Error: ${e}`;
}
});
// Set up the password-based encryption example
document.getElementById('password-encrypt-button').addEventListener('click', () => {
try {
const password = document.getElementById('password-encrypt-password').value;
if (!password) {
document.getElementById('password-encrypt-result').textContent = 'Please enter a password';
return;
}
const message = document.getElementById('password-encrypt-message').value;
const messageBytes = new TextEncoder().encode(message);
const ciphertext = encrypt_with_password(password, messageBytes);
const ciphertextHex = bufferToHex(ciphertext);
document.getElementById('password-encrypt-result').textContent = `Ciphertext: ${ciphertextHex}`;
// Store for decryption
document.getElementById('password-decrypt-ciphertext').value = ciphertextHex;
document.getElementById('password-decrypt-password').value = password;
} catch (e) {
document.getElementById('password-encrypt-result').textContent = `Error: ${e}`;
}
});
// Set up the password-based decryption example
document.getElementById('password-decrypt-button').addEventListener('click', () => {
try {
const password = document.getElementById('password-decrypt-password').value;
if (!password) {
document.getElementById('password-decrypt-result').textContent = 'Please enter a password';
return;
}
const ciphertextHex = document.getElementById('password-decrypt-ciphertext').value;
const ciphertext = hexToBuffer(ciphertextHex);
const plaintext = decrypt_with_password(password, ciphertext);
const decodedText = new TextDecoder().decode(plaintext);
document.getElementById('password-decrypt-result').textContent = `Decrypted: ${decodedText}`;
} catch (e) {
document.getElementById('password-decrypt-result').textContent = `Error: ${e}`;
}
});
// Set up the public key verification example
document.getElementById('pubkey-verify-button').addEventListener('click', () => {
try {
const publicKeyHex = document.getElementById('pubkey-verify-pubkey').value.trim();
if (!publicKeyHex) {
document.getElementById('pubkey-verify-result').textContent = 'Please enter a public key';
return;
}
const message = document.getElementById('pubkey-verify-message').value;
const messageBytes = new TextEncoder().encode(message);
const signatureHex = document.getElementById('pubkey-verify-signature').value;
const signatureBytes = hexToBuffer(signatureHex);
const publicKeyBytes = hexToBuffer(publicKeyHex);
try {
const isValid = verify_with_public_key(publicKeyBytes, messageBytes, signatureBytes);
document.getElementById('pubkey-verify-result').textContent =
isValid ? 'Signature is valid!' : 'Signature is NOT valid!';
} catch (e) {
document.getElementById('pubkey-verify-result').textContent = `Error verifying: ${e}`;
}
} catch (e) {
document.getElementById('pubkey-verify-result').textContent = `Error: ${e}`;
}
});
// Set up the derive public key example
document.getElementById('derive-pubkey-button').addEventListener('click', () => {
try {
const privateKeyHex = document.getElementById('derive-pubkey-privkey').value.trim();
if (!privateKeyHex) {
document.getElementById('derive-pubkey-result').textContent = 'Please enter a private key';
return;
}
const privateKeyBytes = hexToBuffer(privateKeyHex);
try {
const publicKey = derive_public_key(privateKeyBytes);
const publicKeyHex = bufferToHex(publicKey);
// Create a more user-friendly display with copy button
const pubKeyDisplay = document.getElementById('derive-pubkey-result');
pubKeyDisplay.innerHTML = `
Derived Public Key (hex):
${publicKeyHex}
`;
// Add event listener for the copy button
document.getElementById('copy-derived-pubkey-button').addEventListener('click', () => {
const pubKeyText = document.getElementById('derived-pubkey-hex-value').textContent;
navigator.clipboard.writeText(pubKeyText)
.then(() => {
alert('Public key copied to clipboard!');
})
.catch(err => {
console.error('Could not copy text: ', err);
});
});
// Also populate the public key field in the verify with public key section
document.getElementById('pubkey-verify-pubkey').value = publicKeyHex;
// And in the asymmetric encryption section
document.getElementById('asymmetric-encrypt-pubkey').value = publicKeyHex;
} catch (e) {
document.getElementById('derive-pubkey-result').textContent = `Error deriving public key: ${e}`;
}
} catch (e) {
document.getElementById('derive-pubkey-result').textContent = `Error: ${e}`;
}
});
// Set up the asymmetric encryption example
document.getElementById('asymmetric-encrypt-button').addEventListener('click', () => {
try {
const publicKeyHex = document.getElementById('asymmetric-encrypt-pubkey').value.trim();
if (!publicKeyHex) {
document.getElementById('asymmetric-encrypt-result').textContent = 'Please enter a recipient public key';
return;
}
const message = document.getElementById('asymmetric-encrypt-message').value;
const messageBytes = new TextEncoder().encode(message);
const publicKeyBytes = hexToBuffer(publicKeyHex);
try {
const ciphertext = encrypt_asymmetric(publicKeyBytes, messageBytes);
const ciphertextHex = bufferToHex(ciphertext);
document.getElementById('asymmetric-encrypt-result').textContent = `Ciphertext: ${ciphertextHex}`;
// Store for decryption
document.getElementById('asymmetric-decrypt-ciphertext').value = ciphertextHex;
} catch (e) {
document.getElementById('asymmetric-encrypt-result').textContent = `Error encrypting: ${e}`;
}
} catch (e) {
document.getElementById('asymmetric-encrypt-result').textContent = `Error: ${e}`;
}
});
// Set up the asymmetric decryption example
document.getElementById('asymmetric-decrypt-button').addEventListener('click', () => {
if (!isLoggedIn) {
document.getElementById('asymmetric-decrypt-result').textContent = 'Please login first';
return;
}
if (!selectedKeypair) {
document.getElementById('asymmetric-decrypt-result').textContent = 'Please select a keypair first';
return;
}
try {
const ciphertextHex = document.getElementById('asymmetric-decrypt-ciphertext').value;
const ciphertext = hexToBuffer(ciphertextHex);
try {
const plaintext = decrypt_asymmetric(ciphertext);
const decodedText = new TextDecoder().decode(plaintext);
document.getElementById('asymmetric-decrypt-result').textContent = `Decrypted: ${decodedText}`;
} catch (e) {
document.getElementById('asymmetric-decrypt-result').textContent = `Error decrypting: ${e}`;
}
} catch (e) {
document.getElementById('asymmetric-decrypt-result').textContent = `Error: ${e}`;
}
});
// Initialize UI
updateLoginUI();
}
run().catch(console.error);