3

I have an encryption and decryption code which I use to encrypt and decrypt video files (mp4). I'm trying to speed up the decryption process as the encryption one is not that relevant for my case. This is the code that I have for the decryption process:

private static void  decryptFile() throws IOException, ShortBufferException, IllegalBlockSizeException, BadPaddingException
    {

        //int blockSize = cipher.getBlockSize();
        int blockSize = cipher.getBlockSize();
        int outputSize = cipher.getOutputSize(blockSize);
        System.out.println("outputsize: " + outputSize);
        byte[] inBytes = new byte[blockSize];
        byte[] outBytes = new byte[outputSize];
        in= new FileInputStream(inputFile);
        out=new FileOutputStream(outputFile);

        BufferedInputStream inStream = new BufferedInputStream(in);
        int inLength = 0;;
        boolean more = true;
        while (more)
          {
             inLength = inStream.read(inBytes);
             if (inLength == blockSize)
             {
                int outLength 
                   = cipher.update(inBytes, 0, blockSize, outBytes);
                out.write(outBytes, 0, outLength);

             }
             else more = false;         
          }
          if (inLength > 0)
             outBytes = cipher.doFinal(inBytes, 0, inLength);
          else
             outBytes = cipher.doFinal();

          out.write(outBytes);

}

My question is how to speed up the decryption process in this code. I've tried decrypting a 10MB mp4 file and it decrypts in 6-7 seconds. However, I'm aiming for < 1 seconds. Another thing I would like to know is if my writing to the FileOutputStream out is actually slowing the process down rather than the decryption process itself. Any suggestions on how to go about speeding things up here.

I'm using AES for encryption/decryption.

Until I find a solution, I will be using a ProgressDialog which tells the user to wait until the video has been decrypted (Obviously, I'm not going to use the word: decrypted).

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
bytebiscuit
  • 3,446
  • 10
  • 33
  • 53
  • Writing output to file really might be a bottleneck. What hardware are you using? Is output file located in device memory or on storage card? – Sergey Kudriavtsev Oct 10 '11 at 13:07
  • Currently I'm testing on my Laptop computer (old Toshiba laptop - Centrino Duo 1 Ghz). I haven't tested the code yet on my android device but I'm assuming it would be the same thing. – bytebiscuit Oct 10 '11 at 13:12
  • 2
    Could you try using CipherInputStream and CipherOutputStream classes and post how fast are these compared to your code? – Mister Smith Oct 10 '11 at 13:15
  • Mister Smith, thnx for the suggestion. I will try that later and will provide the results here. – bytebiscuit Oct 10 '11 at 13:24
  • 1
    @user967232: you should _really_ make benchmarks on an actual device. This is not the same JVM with a distinct internal code generator for a distinct CPU architecture. The CPU frequency is not a better indicator of actual performance than counting the number of wheels to guess how fast a car can go. – Thomas Pornin Oct 10 '11 at 13:30
  • Mister Smith just tried it using CipherInputStream and CipherOutputStream, the encryption process works pretty fast < 1 second. However, when decrypting it gives me a BadPaddingException. I'm using 8129 bytes as the buffer size as was suggested below. In the encryption process the in.read(inBytes) reads 8129 bytes at a time however when decrypting the encrypted file the in.read(inBytes) starts reading with 496 bytes. Why is this happening. – bytebiscuit Oct 11 '11 at 18:39
  • I guess CipherInputStream and CipherOutputStream won't help either, as when decrypting an encrypted file would require to create a normal file using, in this case, a FileOutputStream, now if there is any faster way to create a file other than using FileOutputStream, would like to know!!! – bytebiscuit Oct 11 '11 at 19:22
  • bytebiscuit, your question gave me the solution which I am trying from past 6 days. I just modified your code little bit, and my 52 mb video file is getting decrypted in just 4 seconds. Previous decrypting technique took 45 seconds. Thats a massive difference. The only modification which i have done is – user1923551 Oct 16 '15 at 13:18
  • @bytebiscuit I wanted if your are using .mp4 or you are encoding it into other alternative formats and then encrypting it?. if you are using other encoding format please tell which one because i am implementing something similar. – Ron Astle Lobo Dec 28 '18 at 11:42

5 Answers5

4

Why are you decrypting data only by blockSize increments ? You do not show what type of object cipher is, but I am guessing this is a javax.crypto.Cipher instance. It can handle update() calls over arrays of arbitrary length, and you will have much less overhead if you use longer arrays. You should process data by blocks of, say, 8192 bytes (that's the traditional length for a buffer, it interacts reasonably well with CPU inner caches).

Thomas Pornin
  • 72,986
  • 14
  • 147
  • 189
  • thnx, I increased the buffer to 8129. It works very good with encryption, however, when decrypting the in.read() method is reading 496 bytes which is very strange. I'm guessing it has to do with CipherInputStream. I'm using InputStream's read() in encryption while in decryption i'm using CipherInputStream's read() method which maybe the cause this difference in bytes. – bytebiscuit Oct 11 '11 at 18:47
1

bytebiscuit, your question gave me the solution which I am trying from past 6 days. I just modified your code little bit, and my 52 mb video file is getting decrypted in just 4 seconds. Previous decrypting technique took 45 seconds which was a different logic (not yours) . Thats a massive difference 45 seconds to 4 seconds. Where ever I have done modification I am putting //modified comment lines. I am sure if your video is 10mb video, it will get decrypted in 1 second for sure. Try applying this, it should work out.

private static void  decryptFile() throws IOException, ShortBufferException, IllegalBlockSizeException, BadPaddingException
    {

        //int blockSize = cipher.getBlockSize();
        int blockSize = cipher.getBlockSize();
        int outputSize = cipher.getOutputSize(blockSize);
        System.out.println("outputsize: " + outputSize);
        byte[] inBytes = new byte[blockSize*1024]; //modified
        byte[] outBytes = new byte[outputSize * 1024]; //modified
        in= new FileInputStream(inputFile);
        out=new FileOutputStream(outputFile);

        BufferedInputStream inStream = new BufferedInputStream(in);
        int inLength = 0;;
        boolean more = true;
        while (more)
          {
             inLength = inStream.read(inBytes);
             if (inLength/1024 == blockSize) //modified
             {
                int outLength 
                   = cipher.update(inBytes, 0, blockSize*1024, outBytes);//modified
                out.write(outBytes, 0, outLength);

             }
             else more = false;         
          }
          if (inLength > 0)
             outBytes = cipher.doFinal(inBytes, 0, inLength);
          else
             outBytes = cipher.doFinal();

          out.write(outBytes);

}
user1923551
  • 4,684
  • 35
  • 29
  • Be Aware: This could cause problems if the input stream has a buffer < blockSize*1024 . E.g. this could happen if you load content from the network. – StaticBR Feb 25 '16 at 14:41
-1

Instead of spending efforts to improve an inadequate architecture, you should consider a streaming solution: it has the great advantage to spread the computation time for the decryption so that it becomes no more noticeable. I mean: do not produce another file from your video source but rather a stream, with a local http server. Unfortunately there is no such component in the SDK, you have to make your own implementation or search for an existing one.

libeasy
  • 379
  • 2
  • 11
-1

I suggest you use the profiling tool provided in the android sdk. it will tell you where you spend the most time (i.e. : file writing or decoding).

see http://developer.android.com/guide/developing/debugging/debugging-tracing.html

This work on the emulator as well as on an actual device.

njzk2
  • 38,969
  • 7
  • 69
  • 107
-1

Consider using the NDK. On devices before Froyo (and even Froyo itself), it would be really slow due to the lack of JIT (or a very simple one in Froyo). Even with the JIT, native architecture-optimized crypto code will always outrun Dalvik.

See also this question.

As an aside, if you're using AES directly, you're probably doing something wrong. If this is part of an effort to do DRM, make sure you realize the full extent of the fact that decompiling an Android app is trivial. Your key will not be secure, which by definition defeats the encryption.

Community
  • 1
  • 1
Delyan
  • 8,881
  • 4
  • 37
  • 42
  • I'm not looking for a full-proof secured app. As long as it keeps the video files safe from ordinary users it's fine by me. I could encrypt and decrypt the files everytime the user uses the app through some random generator but that would add be inefficient. Alternatively, I could get the key from a web server but that would require internet access. So, for now I'm just obfuscating the key within the app. – bytebiscuit Oct 11 '11 at 18:43
  • Using the NDK seems like a good thing to try out. I'm going to try that out later. – bytebiscuit Oct 11 '11 at 18:51