212 lines
6.6 KiB
JavaScript
212 lines
6.6 KiB
JavaScript
|
|
const algo = { name: "AES-GCM", iv: Uint8Array.from([120,1,248,135,62,71,87,156,92,67,155,37]) }
|
|
, parseAlgo = str=> ({ name: str.split(' ')[0], iv: Uint8Array.from(str.split(' ').slice(1)) })
|
|
, algos = [ "AES-GCM 120 1 248 135 62 71 87 156 92 67 155 37", 'AES-CBC' ]
|
|
//, algo = parseAlgo(algos[0])
|
|
, $pass = $`pass input`
|
|
, $text = $`ui-data`
|
|
, $filename = $`[filename]`
|
|
|
|
opener && document.documentElement.classList.add('parented')
|
|
// sel=opener.document.getSelection().type=='None'||'Range'
|
|
|
|
const getParentSelection = ()=> opener && opener.document.getSelection().toString()
|
|
const setParentSelection = str=> opener && opener.document.activeElement.setRangeText( str )
|
|
|
|
let key
|
|
const ivLen = 16 // the IV is always 16 bytes
|
|
|
|
$pass.onchange = async e=>
|
|
key = await crypto.subtle.importKey(
|
|
'raw'
|
|
, await crypto.subtle.digest( 'SHA-256', new TextEncoder().encode($pass.value) )
|
|
, algo, false, ['encrypt','decrypt']
|
|
)
|
|
|
|
|
|
const joinIvAndData = (iv, data)=> {
|
|
var buf = new Uint8Array(iv.length + data.length)
|
|
Array.prototype.forEach.call(iv, (byte, i)=> buf[i] = byte )
|
|
Array.prototype.forEach.call(data, (byte, i)=> buf[ivLen + i] = byte )
|
|
return buf
|
|
}
|
|
|
|
const separateIvFromData = buf=> Array.prototype.reduce.call( new Uint8Array(buf),
|
|
( res, byte, i )=>
|
|
i < ivLen
|
|
? ( res.iv[i] = byte, res )
|
|
: ( res.data[i - ivLen] = byte, res )
|
|
, { iv: new Uint8Array(ivLen), data: new Uint8Array(buf.byteLength - ivLen) } )
|
|
|
|
|
|
const encrypt = ()=> {
|
|
return crypto.subtle.digest( 'SHA-256', new TextEncoder().encode($pass.value) )
|
|
.then( pwHash=> crypto.subtle.importKey('raw', pwHash, algo, false, ['encrypt']) )
|
|
.then( key=> crypto.subtle.encrypt(algo, key, new TextEncoder().encode($text.value)) )
|
|
//.then( ctBuffer=> $text.value = new Uint8Array(ctBuffer).toString().replace(/,/g,'O') )
|
|
.then( ctBuffer=> $text.value = uint2String( new Uint8Array(ctBuffer) ) )
|
|
//.then( ctBuffer=> $text.value = new TextDecoder().decode(new Uint8Array(ctBuffer)) )
|
|
|
|
//.catch( e=> pulse('red') )
|
|
}
|
|
const encrypt2 = str=>
|
|
crypto.subtle.encrypt( algo, key, new TextEncoder().encode(str) )
|
|
//.then( ctBuffer=> $text.value = new Uint8Array(ctBuffer).toString().replace(/,/g,'O') )
|
|
// .then( ctBuffer=> uint2String(new Uint8Array(ctBuffer)) )
|
|
.then( ctBuffer=> $text.value = new TextDecoder().decode(new Uint8Array(ctBuffer)) )
|
|
|
|
//.catch( e=> pulse('red') )
|
|
|
|
const encrypt3 = ( data, iv = crypto.getRandomValues(new Uint8Array(ivLen)) )=>
|
|
crypto.subtle.encrypt( {name: 'AES-GCM', iv}, key, data )
|
|
// .then( encrypted=> bufferToBinaryString( joinIvAndData(iv, new Uint8Array(encrypted)).buffer ) )
|
|
.then( encrypted=> joinIvAndData(iv, new Uint8Array(encrypted)).buffer )
|
|
// var base64 = Unibabel.bufferToBase64(ciphered)
|
|
// .replace(/\-/g, '+')
|
|
// .replace(/_/g, '\/')
|
|
// ;
|
|
|
|
// while (base64.length % 4) {
|
|
// base64 += '=';
|
|
// }
|
|
// return base64;
|
|
// })
|
|
|
|
|
|
const decrypt = ()=> {
|
|
return crypto.subtle.digest( 'SHA-256', new TextEncoder().encode($pass.value) )
|
|
.then( pwHash=> crypto.subtle.importKey('raw', pwHash, algo, false, ['decrypt']) )
|
|
//.then( key=> crypto.subtle.decrypt(algo, key, Uint8Array.from($text.value.split('O').map(Number)).buffer ) )
|
|
.then( key=> crypto.subtle.decrypt(algo, key, string2Uint($text.value).buffer ) )
|
|
//.then( key=> crypto.subtle.decrypt(algo, key, new TextEncoder().encode($text.value).buffer ) )
|
|
.then( ptBuffer=> $text.value = new TextDecoder().decode(ptBuffer) )
|
|
|
|
//.catch( e=> pulse('red') )
|
|
}
|
|
|
|
const decrypt3 = buf=> {
|
|
let { iv, data } = separateIvFromData( buf )
|
|
|
|
return crypto.subtle.decrypt(
|
|
{ name: 'AES-GCM', iv }
|
|
, key
|
|
, data
|
|
)
|
|
/*.then(function (decrypted) {
|
|
var base64 = bufferToUtf8(new Uint8Array(decrypted))
|
|
// .replace(/\-/g, '+')
|
|
// .replace(/_/g, '\/')
|
|
// ;
|
|
|
|
// while (base64.length % 4) {
|
|
// base64 += '=';
|
|
// }
|
|
return base64
|
|
})*/
|
|
}
|
|
|
|
var lastSaved
|
|
const save = ( content, filename )=> {
|
|
let link = document.createElement('a')
|
|
link.setAttribute( 'download', filename )
|
|
// If we are replacing a previously generated file we need to
|
|
// manually revoke the object URL to avoid memory leaks.
|
|
lastSaved && URL.revokeObjectURL( lastSaved )
|
|
link.href = lastSaved = URL.createObjectURL( new Blob([content], {type: 'text/plain'}) )
|
|
//link.href = makeTextFile( content )
|
|
document.body.appendChild( link )
|
|
|
|
// wait for the link to be added to the document
|
|
window.requestAnimationFrame( e=> {
|
|
link.dispatchEvent( new MouseEvent('click') )
|
|
document.body.removeChild( link )
|
|
})
|
|
}
|
|
|
|
const read = file=> new Promise( (ok,ko)=> {
|
|
let r = new FileReader()
|
|
r.onload = e=> ok( r.result )
|
|
r.onerror = e=> ko()
|
|
r.readAsArrayBuffer( file )
|
|
})
|
|
|
|
|
|
var textFile
|
|
const makeTextFile = text=> {
|
|
|
|
textFile && URL.revokeObjectURL(textFile)
|
|
textFile = URL.createObjectURL( new Blob([text], {type: 'text/plain'}) )
|
|
|
|
// returns a URL you can use as a href
|
|
return textFile
|
|
}
|
|
|
|
|
|
const save2 = (file, content, type)=> window.open( "data:application/octet-stream," + encodeURIComponent(content), file )
|
|
|
|
//// conversion ////
|
|
|
|
const uint2string = uintArray=> String.fromCharCode.apply( null, uintArray )
|
|
|
|
const string2uint = string=> new Uint8Array(
|
|
btoa( string ).split('')
|
|
.map( l=>l.charCodeAt(0) )
|
|
)
|
|
|
|
const buffer2bin = buf=> Array.prototype.map.call( new Uint8Array(buf), ch=> String.fromCharCode(ch) ).join('')
|
|
|
|
const buffer2base64 = arr=> btoa( buffer2bin(arr) )
|
|
|
|
const bin2buffer = binstr=> new Uint8Array(
|
|
Array.prototype.map.call( new Uint8Array( binstr.length ), (ch, i)=> binstr.charCodeAt(i) )
|
|
)
|
|
|
|
const base642buffer = base64=> bin2buffer( atob(base64) )
|
|
|
|
const bin2utf8 = binstr=> decodeURIComponent(
|
|
binstr.replace(/./g, c=>
|
|
`%${c.charCodeAt(0) < 16 ? '0' : ''}${c.charCodeAt(0).toString(16).toUpperCase()}`
|
|
)
|
|
)
|
|
|
|
const buffer2utf8 = buf=> bin2utf8( buffer2bin(buf) )
|
|
|
|
const utf82bin = str=> encodeURIComponent(str)
|
|
/* replaces any uri escape sequence, such as %0A, */
|
|
/* with binary escape, such as 0x0A */
|
|
.replace(/%([0-9A-F]{2})/g, (s,$1)=> String.fromCharCode(parseInt($1, 16)) )
|
|
|
|
const utf82buffer = str=> bin2buffer(utf82bin(str))
|
|
|
|
|
|
const CC = {
|
|
uint2string
|
|
, string2uint
|
|
, buffer2bin
|
|
, buffer2uint: buf=> new Uint8Array(buf)
|
|
, buffer2utf8
|
|
, buffer2base64
|
|
, bin2buffer
|
|
, base642buffer
|
|
, bin2utf8
|
|
, utf82bin
|
|
, utf82buffer
|
|
}
|
|
|
|
/*const uintToString = (uintArray)=> {
|
|
var encodedString = String.fromCharCode.apply(null, uintArray),
|
|
decodedString = decodeURIComponent(escape(encodedString));
|
|
return decodedString;
|
|
}
|
|
function stringToUint(string) {
|
|
var string = btoa(unescape(encodeURIComponent(string))),
|
|
charList = string.split(''),
|
|
uintArray = [];
|
|
for (var i = 0; i < charList.length; i++) {
|
|
uintArray.push(charList[i].charCodeAt(0));
|
|
}
|
|
return new Uint8Array(uintArray);
|
|
}
|
|
|
|
*/
|