14440

Progressive Upload and Encryption with CryptoJS

Question:

The goal here is to upload a file, encrypt it at the client side, and send the file and its attributes via AJAX to myphpscript.php. To allow larger files, I want to upload in slices using the FileReader slice method and progressively encrypt the slices using the methods described on the CryptoJS site (<a href="https://code.google.com/p/crypto-js/" rel="nofollow">https://code.google.com/p/crypto-js/</a>). My code below runs, but only ends up storing a a small portion of the intended entire encrypted file. Can I progressively upload and encrypt in the way I am describing?

<script type="text/javascript" src="js/jquery-1.11.0.min.js"></script> <script src="js/aes.js"></script> <script> function readBlob(opt_startByte, opt_stopByte) { var files = document.getElementById('fileinput').files; if (!files.length) { alert('Please select a file!'); return; } var file = files[0]; var start = parseInt(opt_startByte) || 0; var stop = parseInt(opt_stopByte) || file.size - 1; var reader = new FileReader(); // If we use onloadend, we need to check the readyState. reader.onloadend = function(evt) { if (evt.target.readyState == FileReader.DONE) { // DONE == 2 window.bits.push(aesEncryptor.process(evt.target.result)); } }; var blob = file.slice(start, stop + 1); reader.readAsBinaryString(blob); } function handling(evt) { // INITIALIZE PROGRESSIVE ENCRYPTION var key = CryptoJS.enc.Hex.parse(document.getElementById('pass').value); var iv = CryptoJS.lib.WordArray.random(128 / 8); window.bits = []; window.aesEncryptor = CryptoJS.algo.AES.createEncryptor(key, {iv: iv}); // LOOP THROUGH BYTES AND PROGRESSIVELY ENCRYPT var startByte = 0; var endByte = 0; while(startByte < document.querySelector('input[type=file]').files[0].size - 1){ endByte = startByte + 1000000; readBlob(startByte, endByte); startByte = endByte; } // FINALIZE ENCRYPTION AND UPLOAD var encrypted = aesEncryptor.finalize(); encrypted = encodeURIComponent(encrypted); var filename = document.getElementById('fileinput').value; var file_type = document.getElementById('fileinput').files[0].type; var url = 'data=' + encrypted + '&filename=' + filename + '&filetype=' + file_type; $.ajax({ url: 'myphpscript.php', type: 'POST', data: url }).success(function(data){ // Display encrypted data document.getElementById('status').innerHTML = 'Upload Complete.'; }); alert(encrypted); } </script>

Answer1:

So your problem is the line var encrypted = aesEncryptor.finalize();

This is not the encrypted file, but the final 'chunk' produced by the CryptoJS.AES finalizer.

you need to append that to the end of the window.bits buffer to yield the fully encrypted file.

Also, you shouldn't be using window.bits.push, you should keep hold of a reference to each chunk like this (psuedocode):

var prog; //then in the loop, if chunk is null assign to chunk or else concat: loop: if(!prog) prog = cipher.process() else prog.concat(cipher.process()) //then finalize prog.concat(cipher.finalize()) //now you're free to do whatever with the encrypted file: var ciphertext = prog.toString()

Answer2:

One important thing to keep in mind is that <em>the chunks may arrive to the encryptor out of order</em> so you either have to keep track of the order that chunks went into aesEncryptor.process so that you can decrypt in the proper order later <em>or</em> queue the chunks and encrypt them in the proper order to begin with.

Recommend

  • VB.NET XML Serialization Repeat third child Element
  • OdbcConnection.GetSchema(“TABLES”); not working
  • Rpmbuild copying folders specified by a mapping file
  • Rails - Passing Arrays as Params in Model Function
  • How can I get the same/to pass parameters between decorator and decorated function?
  • How to convert all *.potx files to *.pptx files with VBA?
  • Aptana 3 Github Clone Repository Fail
  • OnChange event handler not working
  • Sending HTML Form Multiple box via POST request with AJAX?
  • Merge HTML Element object with a custom object
  • Android Chrome input onkeydown
  • HTML5 canvas draw multiple rectangles that move in the canvas
  • Double.parseDouble is not working on my webpage
  • Rendering a google line chart, curveType not setting and animation not working as expected
  • How to get the position of a click event relative to its layer in KineticJS?
  • Get highlight text in current window and send it in a popup
  • Socket io in node app on google app engine
  • button in popup.html not working
  • Remove previous Directions Route Google Maps
  • $_POST for text in DIV elements
  • Making Google Visualization - Annotation Chart to work in GWT
  • Update Google Maps traffic layer without page reloading
  • How to use JavaScript to determine whether a file exists in a directory?
  • Chart.js Multiple dataset
  • How do I get HTML corresponding to current DOM tree?
  • JQuery Internet Explorer and ajaxstop
  • JSON response opens as a file, but I can't access it with JavaScript
  • Functions in global context
  • FileReader+canvas image loading problem
  • Can a Chrome extension content script make an jQuery AJAX request for an html file that is itself a
  • Change an a tag attribute in JavaScript based on screen width
  • Compare two NSDates in iPhone
  • retrieve vertices with no linked edge in arangodb
  • How to delete a row from a dynamic generate table using jquery?
  • using HTMLImports.whenReady not working in chrome
  • FormattedException instead of throw new Exception(string.Format(…)) in .NET
  • Change div Background jquery
  • Authorize attributes not working in MVC 4
  • apache spark aggregate function using min value
  • EntityFramework adding new object to nested object collection