RSA Encryption + LZMA Compression

I developed a tool in C# to do RSA encryption way back, but I didn’t like the giant file size of encrypted data. The main cause is that RSA encryption takes just around max 80 bytes as input due to the limitation or Algorithm, so it almost always requires multiple blocks of encryption.

So, I’m planning to integrate the LZMA compression and RSA encryption. Once everything done, I will post a chart of file-compression ratio.

The candidate encoding Sequence will be: File Input -> LZMA -> RSA -> LZMA -> Base64 in XML format
* LZMA will be done twice because the RSA is not compression algorithm but it makes larger.

Anybody done the similar task?
I’m also interested in AES encryption.

Advertisements

In-Memory Compression by LZMA in C#

I found that LZMA SDK is a powerful compression library.
The SDK doesn’t provide the in-memory compression sample but it can be done so easily.
I chose MemoryStream for IO data type, and I plan to compress small XML files with this.

* Note that there are hard-coded endian issues in the original SDK. I will check it back when I have access to big endian PowerBook.
* Remember everything goes to heap, so it’s not suitable for large data ( I guess more than 10MB.)

Partial code looks like below.
Comment if you need a complete set of source.

using System;
using System.IO;
using SevenZip;
using SevenZip.Compression;

namespace SevenZip.Compression
{
  class LZMACoder : IDisposable
  {
    private bool isDisposed = false;

    //These properties are straight copy from the SDK.
    //Actually, I don't know what these mean.

    private static Int32 dictionary = 1 << 21; //No dictionary
    private static Int32 posStateBits = 2;
    private static Int32 litContextBits = 3;   // for normal files  // UInt32 litContextBits = 0; // for 32-bit data                                             
    private static Int32 litPosBits = 0;       // UInt32 litPosBits = 2; // for 32-bit data
    private static Int32 algorithm = 2;
    private static Int32 numFastBytes = 128;
    private static bool eos = false;
    private static string mf = "bt4";

    private static CoderPropID[] propIDs = 
    {
        CoderPropID.DictionarySize,
        CoderPropID.PosStateBits,  
        CoderPropID.LitContextBits,
        CoderPropID.LitPosBits,
        CoderPropID.Algorithm,
        CoderPropID.NumFastBytes,
        CoderPropID.MatchFinder,
        CoderPropID.EndMarker
    };
    private static object[] properties = 
    {
        (Int32)(dictionary),
        (Int32)(posStateBits),  
        (Int32)(litContextBits),
        (Int32)(litPosBits),
        (Int32)(algorithm),
        (Int32)(numFastBytes),
        mf,
        eos
    };

    public LZMACoder()
    {
      if (BitConverter.IsLittleEndian == false)
      {
        Dispose();
        throw new Exception("Not implemented");        
      }
    }

    public MemoryStream decompress(MemoryStream inStream)
    {
      return decompress(inStream, false);
    }

    public MemoryStream decompress(MemoryStream inStream, bool closeInStream)
    {
      inStream.Position = 0;
      MemoryStream outStream = new MemoryStream();

      byte[] properties = new byte[5];
      if (inStream.Read(properties, 0, 5) != 5)
        throw (new Exception("input .lzma is too short"));

      SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();
      decoder.SetDecoderProperties(properties);

      long outSize = 0;

      if (BitConverter.IsLittleEndian)
      {
        for (int i = 0; i < 8; i++)
        {
          int v = inStream.ReadByte();
          if (v < 0)
            throw (new Exception("Can't Read 1"));

          outSize |= ((long)(byte)v) << (8 * i);
        }
      }

      long compressedSize = inStream.Length - inStream.Position;
      decoder.Code(inStream, outStream, compressedSize, outSize, null);

      if (closeInStream)
        inStream.Close();

      return outStream;
    }

    public MemoryStream compress(MemoryStream inStream)
    {
      return compress(inStream, false);
    }

    public MemoryStream compress(MemoryStream inStream, bool closeInStream)
    {
      inStream.Position = 0;
      Int64 fileSize = inStream.Length;
      MemoryStream outStream = new MemoryStream();

      SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();
      encoder.SetCoderProperties(propIDs, properties);
      encoder.WriteCoderProperties(outStream);

      if (BitConverter.IsLittleEndian)
      {
        byte[] LengthHeader = BitConverter.GetBytes(fileSize);
        outStream.Write(LengthHeader, 0, LengthHeader.Length);
      }

      encoder.Code(inStream, outStream, -1, -1, null);

      if (closeInStream)
        inStream.Close();

      return outStream;
    }

    ~LZMACoder()
    {
      Dispose();
    }

    public void Dispose()
    {
      Dispose(true);
      GC.SuppressFinalize(this); 
    }

    private void Dispose(bool disposing)
    {
      if (this.isDisposed == false)
      {
        if (disposing)
        {
          //Console.WriteLine("dispose"); 
          GC.SuppressFinalize(this);
        }
      }
      this.isDisposed = true;      
    }
  }
}