-2

I have the following code that uses Crypto-JS to encrypt any file.

It works fine and as it should.

However, the produced encrypted file is HUGE in comparison with the original file!

Example: if I use a file that is 2.99MB and encrypt it, the produced encrypted file will be 5.3MB.

Is there anything i can do to keep the encrypted file as small as possible?

This is my entire code:

<!DOCTYPE html>
<html>
<head>
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
    <title>Get Directory</title>
    <!-- Update your jQuery version??? -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>


      <!--
  https://cdnjs.com/libraries/crypto-js
  -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>


  <!--[if lt IE 9]>
    <script src="https://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  <![endif]-->

    <script> // type="text/javascript" is unnecessary in html5

    // Short version of doing `$(document).ready(function(){`
    // and safer naming conflicts with $
    jQuery(function($) { 

        $('#file-input').on('change', function() {

            // You can't use the same reader for all the files
            // var reader = new FileReader

            $.each(this.files, function(i, file) {

                // Uses different reader for all files
                var reader = new FileReader

                reader.onload = function() {
                    // reader.result refer to dataUrl
                    // theFile is the blob... CryptoJS wants a string...

                   var encrypted = CryptoJS.AES.encrypt(reader.result, '12334');




                    var ecr = encrypted.toString();


                    var blob = new Blob([ecr], {
                    "type": "text/plain"

                    });

                    var link = document.createElement("a");
                    link.download = "Encrypteddocument";
                    link.href = URL.createObjectURL(blob);


                    document.body.appendChild(link);
                    link.click();
                    document.body.removeChild(link);

                    //alert(encrypted);



                }

                reader.readAsDataURL(file)
                $('#thelist').append('FILES: ' + file.name + '<br>')
            })
        })
    });

    </script>
</head>
<body>
    <input type="file" id="file-input">
    <div id="thelist"></div>


    <input type="button" id="button" value="Save" />
</body>
</html>

any help would be appreciated.

This question might be a duplicated of another question that was asked ages ago but the other question does not have a valid or 'accepted' answer. so this question still stands.

How can we reduce the size of the encrypted file?

David Hope
  • 1,426
  • 4
  • 21
  • 50
  • Possible duplicate of [CryptoJS AES Increase File Size](https://stackoverflow.com/questions/31299236/cryptojs-aes-increase-file-size) – James Aug 24 '17 at 15:50
  • @James, the questions might be the same but that question doesn't have an accepted answer and the answer that is given is not complete at all. – David Hope Aug 24 '17 at 16:47
  • The .toString method accepts an encoding type, which is by default Hex. Depending on your use-case you might try one of the other supported encoders (as a parameter to .toString) for example `CryptoJS.enc.Base64`, `CryptoJS.enc.Latin1`, `CryptoJS.enc.Utf8`. But this is just parroting of the [documentation](https://code.google.com/archive/p/crypto-js) – James Aug 24 '17 at 17:25
  • @James, that's the thing. most of the answers and specifically the one you pointed as duplicated of this one is just parroting the documentation without actually resolving the issue mentioned in the question. – David Hope Aug 24 '17 at 17:52
  • If you want an answer you will need to provide some data, say hex data dumps on a small file, say 70 bytes might be a nice size. – zaph Aug 24 '17 at 19:43
  • 2
    The output from `var encrypted = CryptoJS.AES.encrypt(reader.result, '12334');` is in **base64** .. inflating the output with 33%. You need to figure out how to get the output into the file in binary format if you don't want the 33% inflation. How you do that i don't know, as I ain't into javascript ..but that IS the problem. – Ebbe M. Pedersen Aug 24 '17 at 20:57

2 Answers2

2

Encryption does not change the size of the data other than perhaps adding padding of the block size or less (AES has a 16-byte block size), prepending an IV of the block size aqnd/or authentication (probably up to 100 bytes).

So there is something else going on other than the encryption that is increasing the file size, perhaps:

  1. A change in the encoding of the encrypted data, possibly Base64 encoding the encrypoted data, note that is not necessary for saving to a file.

  2. A change in the encoding of the data passed to the encryption function.

var ecr = encrypted.toString(); is suspect because in general arbitrary binary data (encrypted data appears as random bytes) can not be converted to a displayable string. When that is necessary Base64 encoding is generally used. Base64 encoding will expand the data by 33% (4 Base64 characters for each 3 bytes.

zaph
  • 111,848
  • 21
  • 189
  • 228
  • No true. it doesn't matter what type of file I encrypt... The size of the encrypted file is always much bigger than the original file. be it an image, an audio, a php file, an html file or even a text file. so it has nothing to do with base64 as suggested. – David Hope Aug 24 '17 at 16:52
  • 1
    @DavidHope What is "no true?" I stated: "there is **something else** going on other than the encryption" and provided two possibilities but did not limit to those two. You do understand that encryption does not change the size of the data, right? It is not the type of file, it is about handling the data, either on in or output in such a was as to increase the size. Have you examined the output data, if so does it look like completely random 8-bit data bytes? – zaph Aug 24 '17 at 19:53
  • You are keep saying there is something else... I have provided the working code so if there is "something else" then it might be helpful if you just tell us all what that 'something else' is! lol.. Side note, helping never pays.. ;) – David Hope Aug 24 '17 at 20:11
  • 1
    Do you understand that encryption does not change the size of the data, right? It is 16-bytes as a time for AES, that is a block in, a block out, that is encryption. – zaph Aug 24 '17 at 20:17
  • I don't do JavaScript but I do understand encryption. You can help by providing a [mcve] that includes hex data dumps on a small file input and output, say 70 bytes might be a nice size. – zaph Aug 24 '17 at 20:19
  • @DavidHope With due respect, you have no idea what you are talking about. Zaph, on the other hand, definitely knows what he's talking about. I can almost guarantee that your output is in UTF8 encoded base64 characters. The image, audio file etc. is simply not relevant. – Luke Joshua Park Aug 24 '17 at 20:21
  • @LukePark, well done Sherlock. :D. Of course i have no idea what I'm talking about thus asking this question. but evidently zaph doesn't either and he even said and I quote, he doesn't do javascript. ;) thanks for chipping in. – David Hope Aug 25 '17 at 06:35
  • @DavidHope I can't wait for the moment you realize that it is just base64 bloating, going to be such a "duhh!" moment for you. Don't feel like you have to reply when you do, I'll sense the humiliation from here :) – Luke Joshua Park Aug 25 '17 at 06:38
  • @LukePark, hahahaaa.... I just did realize that its UTF8 encoded base64 characters. So thanks for pointing that out.. and no, i don't feel humiliation.. its a learning curve. ;) the question still stands though.. how to reduce the size of the encrypted data. – David Hope Aug 25 '17 at 06:41
  • @DavidHope Heh, oh well. You'll need to explicitly set the output encoding to like "raw" or null or something like that. I don't know the particular library you are using but that `toString` part is very suspicious. I'd start there, you don't ever want to convert binary data to a string. – Luke Joshua Park Aug 25 '17 at 06:53
  • @zaph, i did not downvote your answer and I didn't quite understand your answer if I'm honest. But thanks mate.. appreciate your help and answer. wasn't trying to come across as a knob or anything... – David Hope Aug 25 '17 at 17:43
1

From the old Google code archive:

The ciphertext you get back after encryption isn't a string yet. It's a CipherParams object. A CipherParams object gives you access to all the parameters used during encryption. When you use a CipherParams object in a string context, it's automatically converted to a string according to a format strategy. The default is an OpenSSL-compatible format.

Example is below that:

var encrypted = CryptoJS.AES.encrypt("Message", "Secret Passphrase");
alert(encrypted.key);        // 74eb593087a982e2a6f5dded54ecd96d1fd0f3d44a58728cdcd40c55227522223
alert(encrypted.iv);         // 7781157e2629b094f0e3dd48c4d786115
alert(encrypted.salt);       // 7a25f9132ec6a8b34
alert(encrypted.ciphertext); // 73e54154a15d1beeb509d9e12f1e462a0
alert(encrypted);            // U2FsdGVkX1+iX5Ey7GqLND5UFUoV0b7rUJ2eEvHkYqA=

Which shows in the last line that the OpenSSL compatible format is also base 64 encoded.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263