1async function sodium_encrypt(element) { 2 if (typeof tinyMCE !== typeof undefined) { 3 tinyMCE.triggerSave(false,true); 4 } 5 6 const 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/* This (Argon2) is more secure against bruteforce attacks than PBKDF2 but is overkill for javascript according to author 21 * https://github.com/jedisct1/libsodium.js/issues/250#issuecomment-685971738 22 * 23 * It does not work in chromium mobile at all (freezing) 24 * 25 * This functions requires the browser-sumo/sodium.js 26 27 const salt = await sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES); 28 const key = await sodium.crypto_pwhash( 29 sodium.crypto_secretbox_KEYBYTES, 30 password, 31 salt, 32 sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, 33 sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE, 34 sodium.crypto_pwhash_ALG_DEFAULT 35 ); 36*/ 37 38 const salt = crypto.getRandomValues(new Uint8Array(32)); // Generate a random salt (32 bytes) 39 const key = await derivePBKDF2Hash(password, salt); 40 41 const nonce = await sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES); 42 43 // Message can be a string, buffer, array, etc. 44 const ciphertext = await sodium.crypto_secretbox_easy(message, nonce, key); 45 delete message, password, key; 46 47 const payload = { 48 hint: hint, 49 alg: 'XSalsa20', 50 salt: await sodium.to_hex(salt), 51 nonce: await sodium.to_hex(nonce), 52 ciphertext: await sodium.to_hex(ciphertext) 53 }; 54 55 const val = "[crypt]" + window.btoa(JSON.stringify(payload)) + '[/crypt]'; 56 57 $(element).val(val); 58} 59 60async function sodium_decrypt(payload, element) { 61 const arr = JSON.parse(window.atob(payload)); 62 63 if (arr.alg !== 'XSalsa20') { 64 alert('Unsupported algorithm'); 65 return false; 66 } 67 68 const password = prompt((arr.hint.length) ? hex2bin(arr.hint) : aStr['passphrase']); 69 70 if (!password) { 71 return false; 72 } 73 74 const salt = await sodium.from_hex(arr.salt); 75 const nonce = await sodium.from_hex(arr.nonce); 76 const ciphertext = await sodium.from_hex(arr.ciphertext); 77 78/* See sodium_encrypt() 79 const key = await sodium.crypto_pwhash( 80 sodium.crypto_secretbox_KEYBYTES, 81 password, 82 salt, 83 sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, 84 sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE, 85 sodium.crypto_pwhash_ALG_DEFAULT 86 ); 87*/ 88 89 const key = await derivePBKDF2Hash(password, salt); 90 91 const decrypted = await sodium.crypto_secretbox_open_easy(ciphertext, nonce, key); 92 delete password, key; 93 94 if ($(element).css('display') === 'none' && typeof tinyMCE !== typeof undefined) { 95 tinyMCE.activeEditor.setContent(sodium.to_string(decrypted)); 96 } 97 else { 98 $(element).html(sodium.to_string(decrypted)); 99 } 100} 101 102 103async function derivePBKDF2Hash(password, salt) { 104 const encoder = new TextEncoder(); 105 const passwordBuffer = encoder.encode(password); 106 const saltBuffer = encoder.encode(salt); 107 108 const key = await crypto.subtle.importKey( 109 'raw', // key format 110 passwordBuffer, // password as raw data 111 { name: 'PBKDF2' }, // algorithm 112 false, // whether the key can be exported 113 ['deriveBits'] // key usages 114 ); 115 116 const derivedBits = await crypto.subtle.deriveBits( 117 { 118 name: 'PBKDF2', 119 salt: saltBuffer, 120 iterations: 100000, // The higher the more secure should be at least 100000 121 hash: 'SHA-256', // could also be SHA-512 122 }, 123 key, 124 256 // derived key length in bits (32 bytes) 125 ); 126 127 return new Uint8Array(derivedBits); 128}
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.