1async function sodium_encrypt(element) { 2 if (typeof tinyMCE !== typeof undefined) { 3 tinyMCE.triggerSave(false,true); 4 } 5 6 let message = $(element).val(); 7 8 if (!message) { 9 return false; 10 } 11 12 const password = prompt(aStr['passphrase']); 13 14 if (!password) { 15 return false; 16 } 17 18 const hint = bin2hex(prompt(aStr['passhint'])); 19 20 const salt = crypto.getRandomValues(new Uint8Array(32)); // Generate a random salt (32 bytes) 21 const key = await derivePBKDF2Hash(password, salt); 22 23 const nonce = await sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES); 24 25 // Message can be a string, buffer, array, etc. 26 const ciphertext = await sodium.crypto_secretbox_easy(message, nonce, key); 27 delete message, password, key; 28 29 const payload = { 30 hint: hint, 31 alg: 'XSalsa20', 32 salt: await sodium.to_hex(salt), 33 nonce: await sodium.to_hex(nonce), 34 ciphertext: await sodium.to_hex(ciphertext) 35 }; 36 37 const val = "[crypt]" + window.btoa(JSON.stringify(payload)) + '[/crypt]'; 38 39 $(element).val(val); 40} 41 42async function sodium_decrypt(payload, element) { 43 let arr = JSON.parse(window.atob(payload)); 44 45 if (arr.alg !== 'XSalsa20') { 46 alert('Unsupported algorithm'); 47 return false; 48 } 49 50 let password = prompt((arr.hint.length) ? hex2bin(arr.hint) : aStr['passphrase']); 51 52 if (!password) { 53 return false; 54 } 55 56 const salt = await sodium.from_hex(arr.salt); 57 const nonce = await sodium.from_hex(arr.nonce); 58 const ciphertext = await sodium.from_hex(arr.ciphertext); 59 60 61 const key = await derivePBKDF2Hash(password, salt); 62 63 const decrypted = await sodium.crypto_secretbox_open_easy(ciphertext, nonce, key); 64 delete password, key; 65 66 if ($(element).css('display') === 'none' && typeof tinyMCE !== typeof undefined) { 67 tinyMCE.activeEditor.setContent(sodium.to_string(decrypted)); 68 } 69 else { 70 $(element).html(sodium.to_string(decrypted)); 71 } 72} 73 74async function derivePBKDF2Hash(password, salt) { 75 const encoder = new TextEncoder(); 76 const passwordBuffer = encoder.encode(password); 77 const saltBuffer = encoder.encode(salt); 78 79 const key = await crypto.subtle.importKey( 80 'raw', // key format 81 passwordBuffer, // password as raw data 82 { name: 'PBKDF2' }, // algorithm 83 false, // whether the key can be exported 84 ['deriveBits'] // key usages 85 ); 86 87 const derivedBits = await crypto.subtle.deriveBits( 88 { 89 name: 'PBKDF2', 90 salt: saltBuffer, 91 iterations: 100000, // The higher the more secure should be at least 100000 92 hash: 'SHA-256', // could also be SHA-512 93 }, 94 key, 95 256 // derived key length in bits (32 bytes) 96 ); 97 98 return new Uint8Array(derivedBits); 99} 100 101 102
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.