Re: FlushFinalBlock method was called twice on a CryptoStream ERROR MESSAGE

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



Lets back up and slow down. Based on what you have said, the last code I
gave you should work. Please look at it again below. Your *not* decrypting
the entire file at once, your only decrypting the 32 bytes at a time as you
walk down the stream. The br.ReadBytes(32) reads 32 bytes from the
cryptostream. You can then process those bytes as you need and loop around
again until you process all the bytes (ReadBytes returns 0). Simple, fast,
and only requires the one CryptoStream object (one for encrypt and one for
decrypt). It does not matter if your processing 30 records or 300 million,
this will handle any amount of records. I just tested this with 2 million
records in about 8.5 on my Laptop with not noticeable diff in PageFile
usage.

private static void DoEncrypt(string path)
{
byte[] key = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 };
byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 };
RijndaelManaged rm = new RijndaelManaged();
rm.Key = key;
rm.IV = iv;
ICryptoTransform encryptor = rm.CreateEncryptor();
int i = 0;
using ( FileStream fs = new FileStream(path, FileMode.Create))
using ( CryptoStream cs = new CryptoStream(fs, encryptor,
CryptoStreamMode.Write))
{
RNGCryptoServiceProvider rng = new
RNGCryptoServiceProvider();
byte[] buf = new byte[32];
while ( i < 30 ) // millions of records
{
rng.GetBytes(buf);
cs.Write(buf, 0, buf.Length);
i++;
}
}
}

private static void DoDecrypt(string path)
{
byte[] key = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 };
byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 };
RijndaelManaged rm = new RijndaelManaged();
rm.Key = key;
rm.IV = iv;
ICryptoTransform decryptor = rm.CreateDecryptor();

using ( FileStream fs = File.OpenRead(path) )
using ( CryptoStream cs = new CryptoStream(fs, decryptor,
CryptoStreamMode.Read) )
using ( BinaryReader br = new BinaryReader(cs) )
{
int i = 0;
while(true)
{
byte[] rec = br.ReadBytes(32);
if ( rec == null || rec.Length == 0 )
break;

Console.WriteLine("Rec {0}: {1}", i++,
BitConverter.ToString(rec));
}
}
}

--
William Stacey [MVP]

"Caroline" <Caroline@xxxxxxxxxx> wrote in message
news:%238xM4LVxFHA.2076@xxxxxxxxxxxxxxxxxxxxxxx
> So that's what you guys mean by the "using clause". I've never seem that
> before. Will try this code. What I meant before is each 32 bytes string
> has to be encrypted separately, this is a requirement.
>
> This requirement is because this output file that I am generating on the
> desktop with the encrypted strings will be read on a PPC, and that will
> avoid the initial loading time to unencrypt the entire file at once (will
> do string by string as needed).
>
> Today I am trying to not using the CryptoStream at all, just using
> TransformBlock to encrypt but haven't had much success unencrypting on the
> PPC. I am using a certain Rijndael algorithm implementation on the Pocket
> PC that does not allow setting the Padding property.
>
> Any advice would be appreciated. I really need to figure this out.
>
>
>
>
> "William Stacey [MVP]" <staceyw@xxxxxxxx> wrote in message
> news:urV1qQSxFHA.4032@xxxxxxxxxxxxxxxxxxxxxxx
>> In your case, you don't need to create a new cryptostream each write
>> (unless I missed something in your requirements). We can also get rid of
>> things like the memorystream and do this a bit more directly like so:
>>
>> private static void DoEncrypt(string path)
>> {
>> int i = 0;
>> byte[] key = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
>> 6 };
>> byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
>> 6 };
>> RijndaelManaged rm = new RijndaelManaged();
>> rm.Key = key;
>> rm.IV = iv;
>> ICryptoTransform encryptor = rm.CreateEncryptor();
>>
>> using ( FileStream fs = new FileStream(path, FileMode.Create,
>> FileAccess.ReadWrite, FileShare.ReadWrite) )
>> using ( CryptoStream cs = new CryptoStream(fs, encryptor,
>> CryptoStreamMode.Write))
>> using ( StreamWriter sw = new StreamWriter(cs))
>> {
>> string s = null;
>> while ( (i < 30) ) // millions of records
>> {
>> i++;
>> s = "12345678901234567890123456789012";
>> sw.WriteLine(s);
>> }
>> sw.Flush();
>> cs.FlushFinalBlock();
>> }
>> }
>>
>> private static void DoDecrypt(string path)
>> {
>> byte[] key = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
>> 6 };
>> byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
>> 6 };
>> RijndaelManaged rm = new RijndaelManaged();
>> rm.Key = key;
>> rm.IV = iv;
>> ICryptoTransform decryptor = rm.CreateDecryptor();
>>
>> using ( FileStream fs = File.OpenRead(path) )
>> using ( CryptoStream cs = new CryptoStream(fs, decryptor,
>> CryptoStreamMode.Read) )
>> using ( StreamReader sr = new StreamReader(cs) )
>> {
>> while(true)
>> {
>> string s = sr.ReadLine();
>> if ( s == null )
>> break;
>> Console.WriteLine(s);
>> }
>> }
>> }
>>
>> Do this help your speed? If your data is binary, you could also get rid
>> of the streamReader/writer to save another stream indirection. hth
>>
>> --
>> William Stacey [MVP]
>>
>> "Caroline" <Caroline@xxxxxxxxxx> wrote in message
>> news:upCl1OQxFHA.1028@xxxxxxxxxxxxxxxxxxxxxxx
>>> Thank you again Jon. I just wanted to know if it was possible to re-use
>>> the stream (more efficient), but since you are saying no I will believe
>>> it
>>> Thank you,
>>> Caroline
>>>
>>> "Jon Skeet [C# MVP]" <skeet@xxxxxxxxx> wrote in message
>>> news:MPG.1da5a9bcf137114398c800@xxxxxxxxxxxxxxxxxxxxxxx
>>>> Caroline <Caroline@xxxxxxxxxx> wrote:
>>>>> I need to encrypt millions of records (32 bytes each single record),
>>>>> and
>>>>> would like to reuse the CryptoStream object without recreating it
>>>>> every time
>>>>> inside the loop. Can anybody point to why I am getting this error on
>>>>> the
>>>>> second loop iteration:
>>>>>
>>>>> FlushFinalBlock() method was called twice on a CryptoStream. This
>>>>> method can
>>>>> only be called once.
>>>>
>>>> Yes - as it says, you can only call it once. It signifies the end of
>>>> the data for that stream. You should create a new stream on each
>>>> iteration of the loop.
>>>>
>>>> --
>>>> Jon Skeet - <skeet@xxxxxxxxx>
>>>> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
>>>> If replying to the group, please do not mail me too
>>>
>>>
>>
>>
>
>


.



Relevant Pages

  • Re: Encrypt and Decrypt a file using .NET 2.0?
    ... public static string GenerateKey() ... using (CryptoStream cryptoStream = new CryptoStream(outFile, ... // Distribute this key to the user who will decrypt this file. ... // Get the Key for the file to Encrypt. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: FlushFinalBlock method was called twice on a CryptoStream ERROR MESSAGE
    ... What I meant before is each 32 bytes string has ... TransformBlock to encrypt but haven't had much success unencrypting on the ... you could also get rid ... > of the streamReader/writer to save another stream indirection. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: HOW? Capture output stream as byte array
    ... An alternate option is to just pass a NetworkStream to the CryptoStream ... constructor instead of a memory stream. ... > My thought was a stateful call to my own Encrypt and Decrypt routines. ... > That I would pass a MemoryStream to the CryptoStream constructor. ...
    (microsoft.public.dotnet.languages.vb)
  • Re: HOW? Capture output stream as byte array
    ... An alternate option is to just pass a NetworkStream to the CryptoStream ... constructor instead of a memory stream. ... > My thought was a stateful call to my own Encrypt and Decrypt routines. ... > That I would pass a MemoryStream to the CryptoStream constructor. ...
    (microsoft.public.dotnet.framework)
  • Re: HOW? Capture output stream as byte array
    ... An alternate option is to just pass a NetworkStream to the CryptoStream ... constructor instead of a memory stream. ... > My thought was a stateful call to my own Encrypt and Decrypt routines. ... > That I would pass a MemoryStream to the CryptoStream constructor. ...
    (microsoft.public.dotnet.security)