Rijndael crypto and TransformBlock?

  • Thread starter William Stacey [MVP]
  • Start date
W

William Stacey [MVP]

The Decypt2() method below does not work. It completes, but does not do the
right thing. The first transform request returns 0 bytes. The first
Decypt() method works as we work on a stream instead of blocks. I would
like to know how to get the block method working. TIA.

using System;
using System.IO;
using System.Security.Cryptography;

namespace SocketServers.Crypto
{
/// <summary>
/// Summary description for MyCrypto.
/// </summary>
public class MyCrypto
{
const string s_plaintext = @"c:\mytext.txt";
const string s_ciphertext = @"c:\mytext.bin";
const string s_decrypted = @"c:\mytext2.txt";

public void RunTest()
{
using(SymmetricAlgorithm algo = SymmetricAlgorithm.Create("Rijndael"))
{
algo.Padding = PaddingMode.PKCS7;
algo.BlockSize = 256; // 32 bytes;
Console.WriteLine("Block size:"+algo.BlockSize);
KeySizes[] blockSizes = algo.LegalBlockSizes;
foreach(KeySizes keysize in blockSizes)
{
Console.WriteLine("Max size:"+keysize.MaxSize);
Console.WriteLine("Min size:"+keysize.MinSize);
}
Encrypt(algo);
Decrypt2(algo);
}
}

public void Encrypt(SymmetricAlgorithm algo)
{
using( Stream cipherText = GetWriteableFileStream(s_ciphertext) )
using( ICryptoTransform enc = algo.CreateEncryptor() )
using( CryptoStream crypt = GetWriteCryptoStream(cipherText, enc) )
using( Stream input = GetReadOnlyFileStream(s_plaintext) )
{
Pump(input, crypt);
crypt.Close(); //have to call, not called by Dispose
}
}

public void Decrypt(SymmetricAlgorithm algo)
{
using( Stream cipherText = GetReadOnlyFileStream(s_ciphertext) )
using( ICryptoTransform enc = algo.CreateDecryptor() )
using( CryptoStream decrypt = GetReadCryptoStream(cipherText, enc) )
using( Stream output = GetWriteableFileStream(s_decrypted) )
{
Pump(decrypt, output);
Console.WriteLine("In File Stream len:"+cipherText.Length);
Console.WriteLine("In Stream Blocks:"+
((double)((double)cipherText.Length / 32)));
decrypt.Close(); // have to call, not called by Dispose
}
}

public void Decrypt2(SymmetricAlgorithm algo)
{
ICryptoTransform dec = algo.CreateDecryptor();
Stream inStream = GetReadOnlyFileStream(s_ciphertext);
Stream outStream = GetWriteableFileStream(s_decrypted);
try
{
byte[] inBlock = new byte[32];
byte[] outBlock = new byte[32];
// Read input stream in blocks (32 bytes) until end, and transform the
blocks
// and write to outStream.
int count = 0;
int outCount = 0;
while ( (count = inStream.Read(inBlock, 0, inBlock.Length)) != 0 )
{
outCount = dec.TransformBlock(inBlock, 0, count, outBlock, 0);
outStream.Write(outBlock, 0, outCount);
Console.WriteLine("OutCount:"+outCount);
}
outStream.Flush();
}
finally
{
outStream.Close();
inStream.Close();
}
}

private static void Pump(Stream input, Stream output)
{
byte[] buffer = new byte[10];
int count = 0;

while( (count = input.Read(buffer, 0, 10)) != 0 )
{
output.Write(buffer, 0, count);
}
}

private static FileStream GetReadOnlyFileStream(string path)
{
return new FileStream(path, FileMode.Open, FileAccess.Read);
}

private static FileStream GetWriteableFileStream(string path)
{
return new FileStream(path, FileMode.Create, FileAccess.Write);
}

private static CryptoStream GetWriteCryptoStream(Stream stream,
ICryptoTransform transform)
{
return new CryptoStream(stream, transform, CryptoStreamMode.Write);
}

private static CryptoStream GetReadCryptoStream(Stream stream,
ICryptoTransform transform)
{
return new CryptoStream(stream, transform, CryptoStreamMode.Read);
}
}
}
 
J

Jon Skeet [C# MVP]

William Stacey said:
The Decypt2() method below does not work. It completes, but does not do the
right thing. The first transform request returns 0 bytes.

That's correct - it's doing the right thing.
The first
Decypt() method works as we work on a stream instead of blocks. I would
like to know how to get the block method working. TIA.

You just need to call TransformFinalBlock once after calling
TransformBlock however many times. You can pass in any buffer and 0 for
the length.

In other words, just before flushing outStream:

byte[] lastBit = dec.TransformFinalBlock (inBlock, 0, 0);
outStream.Write (lastBit, 0, lastBit.Length);
 
W

William Stacey [MVP]

Thanks Jon, that worked. However not clear why. I don't get why the first
transform returns 0 bytes and how the call to transform last takes any
buffer and zero length and returns the balance of bytes. Is the dec is
keeping some internal state? TIA

--
William Stacey, MVP

Jon Skeet said:
William Stacey said:
The Decypt2() method below does not work. It completes, but does not do the
right thing. The first transform request returns 0 bytes.

That's correct - it's doing the right thing.
The first
Decypt() method works as we work on a stream instead of blocks. I would
like to know how to get the block method working. TIA.

You just need to call TransformFinalBlock once after calling
TransformBlock however many times. You can pass in any buffer and 0 for
the length.

In other words, just before flushing outStream:

byte[] lastBit = dec.TransformFinalBlock (inBlock, 0, 0);
outStream.Write (lastBit, 0, lastBit.Length);
 
J

Jon Skeet [C# MVP]

William Stacey said:
Thanks Jon, that worked. However not clear why. I don't get why the first
transform returns 0 bytes and how the call to transform last takes any
buffer and zero length and returns the balance of bytes. Is the dec is
keeping some internal state? TIA

Absolutely. Crypto algorithms work on whole blocks, and you won't
necessarily give it a whole block at a time. If it needs the first
(say) 256 bytes before it can work out what the first byte of output
is, and you only give it a chunk of 32 bytes to start with, it can't
possibly output anything.

At the end, however, telling it that "that's the lot" lets it do any
appropriate end processing, possibly filling in any "missing" data from
the end of the current block with zeroes, or something like that.
 
W

William Stacey [MVP]

Ok thanks. So in this case I did not have to worry about the 32 byte block
size, I could just pump almost any byte[] block of encrypted bytes into the
transform and it will return what it can decrypt at that time?
 
J

Jon Skeet [C# MVP]

William Stacey said:
Ok thanks. So in this case I did not have to worry about the 32 byte block
size, I could just pump almost any byte[] block of encrypted bytes into the
transform and it will return what it can decrypt at that time?

Exactly. TransformBlock is slightly badly named, IMO. Of course, I
could be misunderstanding everything, but that's the way I see it...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top