Skip to content

Instantly share code, notes, and snippets.

@Ayms
Last active July 30, 2023 13:06
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save Ayms/6451926 to your computer and use it in GitHub Desktop.
Save Ayms/6451926 to your computer and use it in GitHub Desktop.
WebCrypto code example - Upload a file, encrypt it, calculate the hash and store the results using indexedDB

Code example using WebCrypto, File API, indexedDB, createObjectURL and Workers.

<input type="file" onsubmit="process_upload">
var workerjs=' \
  onmessage=function(evt) { \
		var encrypt=crypto.workersubtle.encrypt({name:"AES-CBC",iv:new Uint8Array(16)},evt.data[0]); \
		var buffer=evt.data[1]; \
		var block=XXX; \
		while (buffer.length) { \
			encrypt.process(buffer.subarray(0,block)).done(function(result) { \
				postMessage(result) \
			}); \
			buffer=buffer.subarray(Math.min(buffer.length,block)); \
		}; \
		encrypt.finish().done(function(result) { \
			postMessage([result]); \
		}); \
	} \
';

var process_upload=function() {
	var file=this.files[0];
	var process=function(key) {
		var reader=new FileReader();
		var readed=function() {
			var request={};
			var file_enc=[];
			var size=reader.result.byteLength;
			var tsize=0;
			var worker=new Worker(URL.createObjectURL(new Blob([workerjs])));
			var h=crypto.subtle.digest('SHA-256'); 
			worker.onmessage=function(evt) {
				var res=(evt.data instanceof Array)?evt.data[0]:evt.data;
				tsize +=res.length;//display a progress bar (tsize/size)*100%
				file_enc.push(res);
				h.process(res).then(function() {
					if (evt.data instanceof Array) { //end
						request.blob=new Blob(file_enc,{type:'application/octet-binary'});
						request.type=file.type;
						this.finish(res).done(function(result) {
							request.file_hash=result;
							store_DB(request);
						});
					};
				});
			};
			worker.postMessage([key,new Uint8Array(reader.result)]);
		};
		reader.addEventListener("loadend",readed,false);
		reader.readAsArrayBuffer(file);
	};
	crypto.importKey("raw",TextToArrayBufferView('00112233445566778899aabbccddeeff'),'AES-CBC',false,['encrypt','decrypt']).done(function(result) {process(result)});
};

var open_db=function() {
	var db=demoDB.db;
	return db.transaction(['encrypted_files'],'readwrite').objectStore('encrypted_files');
};

var store_DB=function(request) {
	var objectStore=open_db();
	objectStore.put({hash:request.file_hash,type:request.type,blob:request.blob});
};

var demoDB=indexedDB.open('demo',1);

demoDB.onupgradeneeded=function(evt) {
	var db=evt.target.result;
	db.createObjectStore('encrypted_files',{keyPath:'hash'});
};

demoDB.onsuccess=function (evt) {
	demoDB.db=evt.target.result;
};
@monscamus
Copy link

monscamus commented Jul 14, 2020

Really helpful - thanks Ayms! Is TextToArrayBufferView something that you've wrote - I don't see it in the File API?

@Ayms
Copy link
Author

Ayms commented Jul 15, 2020

Thanks but sorry I hardly reminded this gist so can't tell what TexToArrayBufferView was, probably a simple function to transform the text format of the key to WebCrypto ArrayBuffer format

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment