CryptographicException when closing XmlTextReader

G

Guest

I am using a CryptoStream to encrypt and then save an xml file. However,
when reading it back in, I am getting a CryptographicException. I am hitting
this because I have some large xml files ( > 10MB) and I only need a certain
node...I use an XmlTextReader to find the node I need, and then attempt to
abort reading in the rest of the xml, but when I close the XmlTextReader I
get the exception. I've included some sample code and xml that should
exhibit the behavior.

Note: If I use Skip() to get to the end of the xml, then I don't get
exceptions, but as I mentioned, the files I'm dealing with can be large and
Skip() takes quite a while to skip over nodes that I don't care about which
really hurts performance. Any ideas?

--------- SAMPLE SOURCE CODE ---------

using System;
using System.Security.Cryptography;
using System.Text;
using System.IO;
using System.Xml;

private const string MY_PASSWORD = "test"; private const string
SOURCE_XML_FILE_PATH = @"C:\Sample.xml"; private const string
ENCRYPTED_FILE_PATH = @"C:\Sample.xmle";

static void Main(string[] args)
{
EncryptFile(SOURCE_XML_FILE_PATH, ENCRYPTED_FILE_PATH, MY_PASSWORD);
ReadEncryptedXml(ENCRYPTED_FILE_PATH, MY_PASSWORD); }

private static void ReadEncryptedXml(string encryptedFilePath, string
password) {
FileStream fileStreamSrc = null;
CryptoStream cstream = null;
StreamReader streamReader = null;
XmlTextReader xmlReader = null;

try {
fileStreamSrc = new FileStream(encryptedFilePath, FileMode.Open,
FileAccess.Read);
cstream = CreateEncryptedStream(fileStreamSrc, password,
CryptoStreamMode.Read);

streamReader = new StreamReader(cstream, Encoding.UTF8);
xmlReader = new XmlTextReader(streamReader);

xmlReader.WhitespaceHandling = WhitespaceHandling.None;
xmlReader.MoveToContent();

bool breakOut = false;
while (xmlReader.NodeType != XmlNodeType.EndElement) {
switch (xmlReader.Name) {
case "States":
xmlReader.Read();
break;
case "State":
xmlReader.Read();
break;
case "Name":
xmlReader.Skip();
break;
case "Population":
XmlDocument retValue1 = new
XmlDocument();
retValue1.AppendChild(
retValue1.ReadNode( xmlReader ));
breakOut = true;
break;
default:
xmlReader.Skip();
break;
}

if (breakOut) {
break;
}
}

xmlReader.Close();
streamReader.Close();
cstream.Close();
fileStreamSrc.Close();
}
catch (CryptographicException ex) {
Console.WriteLine(ex.ToString());
}
catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
}

private static void EncryptFile(string sourceXmlFilePath, string
destEncryptedFilePath, string password) {
FileStream fileStreamSrc = null;
FileStream fileStreamDest = null;
CryptoStream cstream = null;

try {
fileStreamSrc = new FileStream(sourceXmlFilePath, FileMode.Open,
FileAccess.Read);
fileStreamDest = new FileStream(destEncryptedFilePath, FileMode.Create,
FileAccess.Write);

long rdlen = 0;
long totlen = fileStreamSrc.Length;
int len;

cstream = CreateEncryptedStream(fileStreamDest, password,
CryptoStreamMode.Write);

// Read from input file, encrypt and write to output file
byte[] b = new byte[1024];
while(rdlen < totlen) {
len = fileStreamSrc.Read(b, 0, b.Length);
cstream.Write(b, 0, len);
rdlen = rdlen + len;
}

cstream.Close();
fileStreamDest.Close();
fileStreamSrc.Close();
}
catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
}

private static CryptoStream CreateEncryptedStream( Stream baseStream, string
password, CryptoStreamMode streamMode ) {
CryptoStream retValue = null;
SymmetricAlgorithm cryptoAlgorithm = Rijndael.Create();
PasswordDeriveBytes pdb = new PasswordDeriveBytes( password,
new byte[]{
0x12, 0x34, 0x56,
0x78, 0x90,
0xAB,
0xCD, 0xEF,
0x10,
0x11, 0x22,
0x33,
0x44 });
cryptoAlgorithm.Key = pdb.GetBytes( 32 );
cryptoAlgorithm.IV = pdb.GetBytes( 16 );

if( streamMode == CryptoStreamMode.Read ) {
retValue = new CryptoStream( baseStream,
cryptoAlgorithm.CreateDecryptor(), streamMode );
}
else {
retValue = new CryptoStream( baseStream,
cryptoAlgorithm.CreateEncryptor(), streamMode );
}

return retValue;
}

private static void DecryptFile(string encryptedFilePath, string
destinationFilePath, string password) {
FileStream fileStreamSrc = null;
CryptoStream cstream = null;

try {
fileStreamSrc = new FileStream(encryptedFilePath, FileMode.Open,
FileAccess.Read);
cstream = CreateEncryptedStream(fileStreamSrc, password,
CryptoStreamMode.Read);

StreamWriter fsDecrypted = new
StreamWriter(destinationFilePath);
fsDecrypted.Write(new StreamReader(cstream).ReadToEnd());
fsDecrypted.Flush();
fsDecrypted.Close();

cstream.Close();
fileStreamSrc.Close();
}
catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
}

--------- SAMPLE XML ---------

<States>
<State>
<Name>Illinois</Name>
<Population>Unknown</Population>
<Data>
<Item type="MyType" number="1">
<SubItem utcTime="2004-09-12 17:00:00Z" timeTicks="632306052000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-12 17:00:00Z" timeTicks="632306052000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-12 20:15:00Z" timeTicks="632306169000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-12 20:15:00Z" timeTicks="632306169000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-12 20:15:00Z" timeTicks="632306169000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-13 00:30:00Z" timeTicks="632306322000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-14 01:00:00Z" timeTicks="632307204000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 20:05:00Z" timeTicks="632312211000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 20:15:00Z" timeTicks="632312217000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 20:15:00Z" timeTicks="632312217000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 20:15:00Z" timeTicks="632312217000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 20:15:00Z" timeTicks="632312217000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-20 00:30:00Z" timeTicks="632312370000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-21 01:00:00Z" timeTicks="632313252000000000"
attr1="False" attr2="False" />
</Item>
<Item type="MyType" number="2">
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 17:00:00Z" timeTicks="632312100000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 20:05:00Z" timeTicks="632312211000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 20:15:00Z" timeTicks="632312217000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 20:15:00Z" timeTicks="632312217000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 20:15:00Z" timeTicks="632312217000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-19 20:15:00Z" timeTicks="632312217000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-20 00:30:00Z" timeTicks="632312370000000000"
attr1="False" attr2="False" />
<SubItem utcTime="2004-09-21 01:00:00Z" timeTicks="632313252000000000"
attr1="False" attr2="False" />
</Item>
</Data>
</State>
</States>
 
J

Jon Skeet [C# MVP]

Tim Barg said:
I am using a CryptoStream to encrypt and then save an xml file. However,
when reading it back in, I am getting a CryptographicException. I am hitting
this because I have some large xml files ( > 10MB) and I only need a certain
node...I use an XmlTextReader to find the node I need, and then attempt to
abort reading in the rest of the xml, but when I close the XmlTextReader I
get the exception. I've included some sample code and xml that should
exhibit the behavior.

Note: If I use Skip() to get to the end of the xml, then I don't get
exceptions, but as I mentioned, the files I'm dealing with can be large and
Skip() takes quite a while to skip over nodes that I don't care about which
really hurts performance. Any ideas?

It would really help if:

a) you could post a short but *complete* program - one we can actually
compile and run, without having to fix up a load of the code

b) you could tell us what the exception message is
 
J

Jon Skeet [C# MVP]

Tim Barg said:
I am using a CryptoStream to encrypt and then save an xml file. However,
when reading it back in, I am getting a CryptographicException. I am hitting
this because I have some large xml files ( > 10MB) and I only need a certain
node...I use an XmlTextReader to find the node I need, and then attempt to
abort reading in the rest of the xml, but when I close the XmlTextReader I
get the exception. I've included some sample code and xml that should
exhibit the behavior.

Note: If I use Skip() to get to the end of the xml, then I don't get
exceptions, but as I mentioned, the files I'm dealing with can be large and
Skip() takes quite a while to skip over nodes that I don't care about which
really hurts performance. Any ideas?

<snip>

Having looked at this for a few minutes (after fixing up the code you
posted) you can reproduce this without any XML, or even any files. The
problem is that closing a CryptoStream half way through tries to flush
the final buffer, which causes the exception.

It looks like a bug in the framework to me - I suggest you report it to
Microsoft at
http://lab.msdn.microsoft.com/productfeedback/
 
G

Guest

It would really help if:
a) you could post a short but *complete* program - one we can actually
compile and run, without having to fix up a load of the code

What exactly did you have to "fix up"? I copied the code into a new console
project and it ran fine without any modification.
 
J

Jon Skeet [C# MVP]

Matt said:
What exactly did you have to "fix up"? I copied the code into a new console
project and it ran fine without any modification.

Sorry, but you really didn't. Your code doesn't declare a class, to
start with...

In fact, putting the code in a class was all that needed doing - but
that was made fairly unclear due to the formatting of the code. For
instance, the first code block:

private const string MY_PASSWORD = "test"; private const string
SOURCE_XML_FILE_PATH = @"C:\Sample.xml"; private const string
ENCRYPTED_FILE_PATH = @"C:\Sample.xmle";

would have been rather clearer as:

private const string MY_PASSWORD = "test";
private const string SOURCE_XML_FILE_PATH = @"C:\Sample.xml";
private const string ENCRYPTED_FILE_PATH = @"C:\Sample.xmle";

Similarly, at first sight Main (as posted) doesn't appear to have any
closing brace - it's "hidden" at the end of the line.

It's worth considering how the code will appear to someone else when
posted, bearing in mind that that person will never have seen the code
before.
 
G

Guest

Sorry, but you really didn't. Your code doesn't declare a class, to
start with...

In fact, putting the code in a class was all that needed doing - but
that was made fairly unclear due to the formatting of the code. For
instance, the first code block:

private const string MY_PASSWORD = "test"; private const string
SOURCE_XML_FILE_PATH = @"C:\Sample.xml"; private const string
ENCRYPTED_FILE_PATH = @"C:\Sample.xmle";

would have been rather clearer as:

private const string MY_PASSWORD = "test";
private const string SOURCE_XML_FILE_PATH = @"C:\Sample.xml";
private const string ENCRYPTED_FILE_PATH = @"C:\Sample.xmle";

Similarly, at first sight Main (as posted) doesn't appear to have any
closing brace - it's "hidden" at the end of the line.

It's worth considering how the code will appear to someone else when
posted, bearing in mind that that person will never have seen the code
before.

Ah, you're talking formatting issues. Yes, I agree. We posted the message
through the msdn newsgroup site (http://msdn.microsoft.com/newsgroups) which
appears to have thrown off the line breaks in some weird way.

Also, for reference, we would have preferred to attach a complete program,
but did not see any obvious way to attach files to a post using the msdn site.

Anyway, we suspected it was a bug in the framework (we're using .NET 1.1
Framework). Thanks for taking a look.

Matt
 
J

Jon Skeet [C# MVP]

Matt said:
Ah, you're talking formatting issues.

Only partly - even without the formatting issues, your code still
didn't declare any classes, going straight from the using directives to
a member declaration.
Yes, I agree. We posted the message
through the msdn newsgroup site (http://msdn.microsoft.com/newsgroups) which
appears to have thrown off the line breaks in some weird way.

It's generally a better idea to use a "real" newsreader IMO, pointing
at news.microsoft.com.
Also, for reference, we would have preferred to attach a complete program,
but did not see any obvious way to attach files to a post using the msdn site.

Anyway, we suspected it was a bug in the framework (we're using .NET 1.1
Framework). Thanks for taking a look.

Yup, it does look like 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