📜 ⬆️ ⬇️

Encryption / decryption of data on the client in web-based systems

Nowadays, more and more programs are translated into the so-called “web-oriented” view, that is, the client-server principle is used, which allows storing data remotely and accessing them through a thin client (browser).
At the same time with the ease of use, there is an acute question about the security of this data. Confidential information may be available to other people in several ways. Firstly, physical measures can be applied to the user to retrieve. Secondly, during transmission, data can be intercepted by various sniffers. And, thirdly, hacker attacks can be made to the server, which will allow attackers to steal information, or an unscrupulous server administrator will use it for personal purposes.

Task


Some time ago I had a task to develop a prototype of the program for encrypting / decrypting data on the client side in web-oriented systems.

That is, it was necessary to develop a program that will allow not only to store data on the server, but also provide an opportunity to work with them through the web interface and at the same time ensure their uselessness for attackers in case of theft, which is achieved by encrypting / decrypting exclusively on the client side.
For a typical use case, it is possible to work with three types of data:


Implementation


The fact that data processing should be done exclusively on the client side, limited the choice of means for implementation. At the initial stage of development, a bunch of “Java applet - Java servlet” was tested, but after some time I had to find another way, because there were difficulties in debugging and transferring data between the applet and the servlet.
I dwelled on using the features of HTML5 and the JavaScript object “XmlHttpRequest Level 2” in particular, because they made it possible to implement the necessary functionality with less effort.
')
Work with text

Encryption Algorithm:

Reverse process:


Work with files

The process of encrypting / decrypting files occurs in a slightly different way.
Encryption Algorithm:

Reverse process:


Work with images

Encryption Algorithm:

Reverse process:


Some key source code for working with files:
<script type="text/javascript"> /** *        * XMLHttpRequest level 2 */ function upload(blobOrFile) { var xhr = new XMLHttpRequest(); //    POST,  URL  true=  xhr.open('POST', '/File/UploadFile/', true); //   -   xhr.responseType = "arraybuffer"; //    xhr.setRequestHeader("Content-type", "multipart/form-data"); xhr.onload = function(e) { // ... }; xhr.send(blobOrFile); //   } //      document.querySelector('input[type="file"]').addEventListener('change', function(e) { var file = this.files[0]; //      var reader = new FileReader(); reader.onloadend = function(e) { var result = this.result; //    var arr = new Int8Array(result); var i; //   var newResult = new ArrayBuffer(arr.byteLength); var newRes = new Int8Array(newResult); var keyForEncrypt = $('#keyForEncrypt').val(); for(i = 0; i < arr.byteLength; i++) { //    newRes[i] = arr[i] + parseInt(keyForEncrypt, 10); } //   upload(newRes.buffer); }; //      //   Chrome 11.0.696.68,    FireFox 4.0.1 reader.readAsArrayBuffer(file); }, false); /*** *         , *        Java  *      */ function download() { var xhr = new XMLHttpRequest(); xhr.open('POST', '/File/DownloadFile/', false); xhr.responseType = 'arraybuffer'; xhr.onload = function(e) { var arr = new Int8Array(this.response); // this.response == arr.buffer //     upload(arr.buffer); var result = new Array(arr.byteLength); var keyForDecrypt = $('#keyForDecrypt').val(); for(var i = 0; i < arr.byteLength; i++) { result[i] = arr[i] - parseInt(keyForDecrypt, 10); } saveFileByApplet(result); }; xhr.send(); } function saveFileByApplet(data) { //     var cryptApplet = document.CryptApplet; cryptApplet.saveFile(data); } $(document).ready(function() { $('#saveFileButton').click(function() { download(); }); }); </script> 


Source code for working with images:
 <script type="text/javascript"> var selectedFile = null; //     document.querySelector('input[type="file"]').addEventListener('change', function(e) { selectedFile = this.files[0];//      }, false); $(document).ready(function() { $('#uploadPictureButton').click(function() { //    -  if(selectedFile != null) { var reader = new FileReader(); reader.onload = function(e) { //    var result = this.result; //   Base64 var base64Result = Base64.encode(result); //   XOR   var keyForEncrypt = $('#keyForEncrypt').val(); var encryptedData = XOREncrypt(base64Result, keyForEncrypt); //   uploadPicture(encryptedData); }; //      reader.readAsBinaryString(selectedFile); } }); $('#downloadPictureButton').click(function() { downloadPicture(); }); }); /** *         5   */ function buildExtension() { if(selectedFile != null) { var ext = ""; var fullName = selectedFile.name; for(var i = fullName.length - 1; i >= 0; i--) { if(fullName[i] == '.') break; else ext += fullName[i]; } ext = ext.split('').reverse().join(''); if(ext.length < 5) { for(var i = 0; i <= 5-ext.length; i++) { ext += " "; } } return ext; } } /** *        * XMLHttpRequest level 2 */ function uploadPicture(picture) { var xhr = new XMLHttpRequest(); //    POST,  URL  true=  xhr.open('POST', '/Picture/UploadPicture/', true); xhr.onload = function(e) { // ... }; var sentData = "jpg " + picture; //   xhr.send(sentData); } /*** *      ,  XOR,  , *        SRC  IMG */ function downloadPicture() { var xhr = new XMLHttpRequest(); xhr.open('POST', '/Picture/DownloadPicture/', true); xhr.onload = function(e) { //  -  Base64,  XOR var result = this.response; //  5  -  var ext = rtrim(result.substr(0, 5)); //   Base64 var base64Data = result.substr(5); var keyForDecrypt = $('#keyForDecrypt').val(); var decryptedData = XORDecrypt(base64Data, keyForDecrypt); //  MIME      var mime = ""; switch (ext) { case "jpeg" : case "jpg" : case "jpe" : mime = "image/jpeg"; break; case "gif" : mime = "image/gif"; break; case "png" : mime = "image/png"; break; default: mime = "image/jpeg"; break; } $('#pict').attr('src', "data:" + mime + ";base64," + decryptedData); }; xhr.send(); } /** *  PHP- rtrim -    */ function rtrim ( str, charlist ) { charlist = !charlist ? ' \\s\u00A0' : (charlist + '').replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '\\$1'); var re = new RegExp('[' + charlist + ']+$', 'g'); return (str + '').replace(re, ''); } </script> 


I did not give here the implementation of the XOREncrypt, XORDecrypt and Base64 functions, so as not to clutter an already long listing. They can be viewed in the attached archive with the source code.

Java applet code to display the file save dialog.
 package ExtPackage; import java.applet.*; import java.io.*; import java.io.FileOutputStream; import javax.swing.JFileChooser; import javax.swing.*; public class CryptApplet extends Applet{ public void saveFile(byte[] data) throws FileNotFoundException, IOException { //     final JFileChooser fc = new JFileChooser(); fc.showSaveDialog(CryptApplet.this); //    ,   File file = fc.getSelectedFile(); OutputStream out = new FileOutputStream(file); //      out.write(data); out.flush(); out.close(); } } 


Summary


I hope the results I received will save some time for those who are faced with the task of encrypting / decrypting data on the client in web-based systems. Source code - in the attached archive.

Source: https://habr.com/ru/post/130085/


All Articles