Bouncy Castle AES Encryption - providing input in blocks

Federinik

I'm using Bouncy Castle library to encrypt some data in my Windows Store App. My EncryptHelper class:

public static class EncryptHelper
{
    private const string KEY = "chiaveAES";
    private const int SIZE = 16;
    private enum CipherMode
    { 
        Encrypt,
        Decrypt
    }

    private static PaddedBufferedBlockCipher InitCipher(CipherMode mode)
    {
        PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(new AesLightEngine()), new ZeroBytePadding());

        var key = new byte[32];
        var keyArray = KEY.ToCharArray();
        Buffer.BlockCopy(keyArray, 0, key, 0, Math.Min(keyArray.Length, key.Length));
        cipher.Init(mode == CipherMode.Encrypt, new KeyParameter(key));
        return cipher;
    }

    public static async Task Encrypt(Stream sourceStream, Stream destinationStream, bool autoSeekStart = true, bool autoSeekEnd = true)
    {
        //await Process(InitCipher(CipherMode.Encrypt), sourceStream, destinationStream, autoSeekStart, autoSeekEnd);
        await ProcessBlocks(InitCipher(CipherMode.Encrypt), sourceStream, destinationStream, autoSeekStart, autoSeekEnd);
    }


    public static async Task Decrypt(Stream sourceStream, Stream destinationStream, bool autoSeekStart = true, bool autoSeekEnd = true)
    {
        //await Process(InitCipher(CipherMode.Decrypt), sourceStream, destinationStream, autoSeekStart, autoSeekEnd);
        await ProcessBlocks(InitCipher(CipherMode.Decrypt), sourceStream, destinationStream, autoSeekStart, autoSeekEnd);
    }

    private static async Task Process(PaddedBufferedBlockCipher cipher, Stream sourceStream, Stream destinationStream, bool autoSeekStart, bool autoSeekEnd)
    {
        if (autoSeekStart)
        {
            sourceStream.ToBegin();
            destinationStream.ToBegin();
        }

        var size = Convert.ToInt16(sourceStream.Length);
        byte[] inBuffer = new byte[size];
        byte[] outBuffer = new byte[cipher.GetOutputSize(size)];
        int inCount = 0;
        int outCount = 0;

        try
        {
            inCount = await sourceStream.ReadAsync(inBuffer, 0, inBuffer.Length);

            outCount = cipher.ProcessBytes(inBuffer, 0, inCount, outBuffer, 0);
            outCount += cipher.DoFinal(outBuffer, outCount);

            await destinationStream.WriteAsync();

            await destinationStream.FlushAsync();
        }
        catch { }

        if (autoSeekEnd)
        {
            sourceStream.ToBegin();
            destinationStream.ToBegin();
        }
    }

    private static async Task ProcessBlocks(PaddedBufferedBlockCipher cipher, Stream sourceStream, Stream destinationStream, bool autoSeekStart, bool autoSeekEnd)
    {
        if (autoSeekStart)
        {
            sourceStream.ToBegin();
            destinationStream.ToBegin();
        }

        byte[] inBuffer = new byte[SIZE];
        byte[] outBuffer = new byte[cipher.GetOutputSize(SIZE)];
        int inCount = 0;
        int outCount = 0;

        try
        {
            while ((inCount = await sourceStream.ReadAsync(inBuffer, 0, inBuffer.Length)) > 0)
            {
                outCount += cipher.ProcessBytes(inBuffer, 0, inCount, outBuffer, 0);
                await destinationStream.WriteAsync(outBuffer, 0, outBuffer.Length);
            }

            outBuffer = ?
            outCount += cipher.DoFinal(outBuffer, outCount);

            await destinationStream.WriteAsync(outBuffer, 0, outCount);

            await destinationStream.FlushAsync();
        }
        catch { }

        if (autoSeekEnd)
        {
            sourceStream.ToBegin();
            destinationStream.ToBegin();
        }
    }
}

My Process() method works fine, but when on the instruction

inCount = await sourceStream.ReadAsync(inBuffer, 0, inBuffer.Length);

I'm afraid it may occurr an OutOfMemoryException if the stream has too much data. So, I was trying to build the ProcessBlocks() method, which should read from the stream progressively, one block per time, without overcharging the RAM. I have some doubts on how to behave with outBuffer: it should be overwritten in every cycle in which cipher.ProcessBytes() gets executed, but of which size should it be just before the cipher.DoFinal() invocation?

Thank you

UPDATE 30/07/2015

I modified the Main in the answer to handle a zip file and the outcoming zip file is no more a valid ZIP, could someone explain me why?

 public static void Main(string[] args)
    {
            var plainPath = @"C:\Users\Federico\Desktop\0abed72d-defc-4c9a-a8ae-3fec43f01224.zip";
            var decryptPath = @"C:\Users\Federico\Desktop\0abed72d-defc-4c9a-a8ae-3fec43f01224 - decrypted.zip";

            var plainStream = new FileStream(plainPath, FileMode.Open, FileAccess.Read);
            var cipherStream = new MemoryStream();
            EncryptHelper.Encrypt(plainStream, cipherStream);
            cipherStream.Seek(0, SeekOrigin.Begin);
            FileStream fs = new FileStream(decryptPath, FileMode.Create);
            EncryptHelper.Decrypt(cipherStream, fs);

            fs.Flush();
            fs.Close();
        }
President James K. Polk

cipher.DoFinal() will produce as many as 2 * Cipher.GetBlockSize() bytes. The actual number of bytes produced is returned by the method.

Here is an example that is loosely based on your example.

using System;
using System.IO;

using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Engines;
using System.Text;

namespace PaddedBufferedBlockCipherExample
{
    public class EncryptHelper
    {
        private const string KEY = "chiaveAES";
        private const int BufferSize = 1024;
        private PaddedBufferedBlockCipher cipher;

        public enum CipherMode
        {
            Encrypt,
            Decrypt
        }

        public EncryptHelper (CipherMode mode)
        {
            cipher = new PaddedBufferedBlockCipher (new CbcBlockCipher (new AesLightEngine ()), new Pkcs7Padding ());

            var key = new byte[32];
            var keyArray = KEY.ToCharArray ();
            Buffer.BlockCopy (keyArray, 0, key, 0, Math.Min (keyArray.Length, key.Length));
            cipher.Init (mode == CipherMode.Encrypt, new KeyParameter (key));
        }

        public static void Encrypt (Stream sourceStream, Stream destinationStream)
        {
            var helper = new EncryptHelper (CipherMode.Encrypt);
            helper.ProcessBlocks (sourceStream, destinationStream);
        }


        public static void Decrypt (Stream sourceStream, Stream destinationStream)
        {
            var helper = new EncryptHelper (CipherMode.Decrypt);
            helper.ProcessBlocks (sourceStream, destinationStream);
        }


        private void ProcessBlocks (Stream sourceStream, Stream destinationStream)
        {


            // inBuffer is sized for efficient I/O
            var inBuffer = new byte[BufferSize];

            // outBuffer should be large enough to not require further resizing
            var outBuffer = new byte[cipher.GetBlockSize() +  cipher.GetOutputSize (inBuffer.Length)];
            int inCount = 0;
            int outCount = 0;

            // Process data using the cipher.ProcessBytes method, until we reach EOF

            while ((inCount = sourceStream.Read (inBuffer, 0, inBuffer.Length)) > 0) {
                outCount = cipher.ProcessBytes (inBuffer, 0, inCount, outBuffer, 0);
                destinationStream.Write (outBuffer, 0, outCount);
            }

            // Now "flush" the cipher instance by calling the DoFinal method. This
            // will finish the en/de-cryption by ciphering any buffered data and processing any
            // encryption padding.

            outCount = cipher.DoFinal (outBuffer, 0);

            destinationStream.Write (outBuffer, 0, outCount);
        }

        public static void Main (string[] args)
        {
            var plainPath = "/Users/robert/src/csharp_toys/toy1/Program.cs";
            var plainStream = new FileStream (plainPath, FileMode.Open, FileAccess.Read);
            var cipherStream = new MemoryStream ();
            EncryptHelper.Encrypt (plainStream, cipherStream);
            cipherStream.Seek (0, SeekOrigin.Begin);
            var decryptedStream = new MemoryStream ();
            EncryptHelper.Decrypt (cipherStream, decryptedStream);
            var decryptedString = Encoding.ASCII.GetString (decryptedStream.ToArray ());
            Console.Write (decryptedString);
        }
    }
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

AES-256 encryption workflow in scala with bouncy castle: salt and IV usage and transfer/storage

From Dev

AES encryption error: The input data is not a complete block?

From Dev

OSX RSA Decryption from Bouncy Castle

From Dev

Generating keyPair using Bouncy Castle

From Dev

Bouncy Castle scrypt implementation

From Dev

Which of these "Safe" ECC curves are available in Bouncy Castle?

From Dev

Implementing E Voting System using Bouncy Castle

From Dev

Bouncy Castle jar confusion?

From Dev

Bouncy castle GNUPG decryption

From Dev

AES cbc padding encryption/decryption on cross platform (.net c# and codename one bouncy castle)

From Dev

bundle will not start when bouncy castle is imported

From Dev

Explore a bouncy castle store object

From Dev

Encryption AES 256 Input Plaintext Length Issue

From Dev

EncryptionOperationNotPossibleException by Jasypt with Bouncy Castle

From Dev

Bouncy Castle issue and Triple DES

From Dev

Library JAR with Bouncy Castle

From Dev

Bouncy Castle - Obsolete LegacyTlsClient

From Dev

Android to server communication using SSL with Bouncy Castle

From Dev

sign file with bouncy castle in java

From Dev

Bouncy Castle as provider v/s Bouncy Castle API

From Dev

Bouncy Castle ECIES compressed format

From Dev

Read Certificate in android by bouncy castle

From Dev

AES encryption error: The input data is not a complete block?

From Dev

Bouncy Castle DataLengthException not being caught

From Dev

java RSA encryption using bouncy castle and python PKCS1-OAEP

From Dev

Bouncy castle GNUPG decryption

From Dev

Android AES/ECB/PKCS7PADDING generate key bouncy castle

From Dev

Convert Bouncy castle aes key to UTF-8 string

From Dev

Why stepping over the SCrypt.generate() (Bouncy Castle Java API) line using breakpoint(Eclipse) blocks the debugging process?

Related Related

  1. 1

    AES-256 encryption workflow in scala with bouncy castle: salt and IV usage and transfer/storage

  2. 2

    AES encryption error: The input data is not a complete block?

  3. 3

    OSX RSA Decryption from Bouncy Castle

  4. 4

    Generating keyPair using Bouncy Castle

  5. 5

    Bouncy Castle scrypt implementation

  6. 6

    Which of these "Safe" ECC curves are available in Bouncy Castle?

  7. 7

    Implementing E Voting System using Bouncy Castle

  8. 8

    Bouncy Castle jar confusion?

  9. 9

    Bouncy castle GNUPG decryption

  10. 10

    AES cbc padding encryption/decryption on cross platform (.net c# and codename one bouncy castle)

  11. 11

    bundle will not start when bouncy castle is imported

  12. 12

    Explore a bouncy castle store object

  13. 13

    Encryption AES 256 Input Plaintext Length Issue

  14. 14

    EncryptionOperationNotPossibleException by Jasypt with Bouncy Castle

  15. 15

    Bouncy Castle issue and Triple DES

  16. 16

    Library JAR with Bouncy Castle

  17. 17

    Bouncy Castle - Obsolete LegacyTlsClient

  18. 18

    Android to server communication using SSL with Bouncy Castle

  19. 19

    sign file with bouncy castle in java

  20. 20

    Bouncy Castle as provider v/s Bouncy Castle API

  21. 21

    Bouncy Castle ECIES compressed format

  22. 22

    Read Certificate in android by bouncy castle

  23. 23

    AES encryption error: The input data is not a complete block?

  24. 24

    Bouncy Castle DataLengthException not being caught

  25. 25

    java RSA encryption using bouncy castle and python PKCS1-OAEP

  26. 26

    Bouncy castle GNUPG decryption

  27. 27

    Android AES/ECB/PKCS7PADDING generate key bouncy castle

  28. 28

    Convert Bouncy castle aes key to UTF-8 string

  29. 29

    Why stepping over the SCrypt.generate() (Bouncy Castle Java API) line using breakpoint(Eclipse) blocks the debugging process?

HotTag

Archive