C# – MemoryStream to String, and back to MemoryStream without adding any bytes (encodings, etc.)

arrayscencryptionstring

OK, I've come across some articles here and here, but they aren't doing quite what I need to do, and I'm running into some trouble.

I am receiving an encrypted piece of data as a memorystream. I need to somehow write the memorystream to a file (the way I wrote the mockup, as a string would be best), then retrieve the string from the file and send it, as a memorystream, to a service to be decrypted. I was just using a streamreader to store the memorystream as a string, and was reading the string into memory using an encoding.

The problem was I got an error saying that my encrypted data was corrupted. I think this means that I changed the bytes, somehow.

Here is the code reading the memorystream into a string:

using (StreamReader reader = new StreamReader(dataKeyResponse.CiphertextBlob))
{
    encryptedDataKey = reader.ReadToEnd();
}

And here is the code reading the string, retrieved from the file, into a memorystream:

MemoryStream mStream = new MemoryStream(ASCIIEncoding.Default.GetBytes(encryptedKey));

I thought the step that did it was the ASCIIEncoding, but then I implemented the workaround from above, converted the byte array to a memorystream, and got the same error.

byte[] bytes = new byte[encryptedKey.Length*sizeof (char)];
System.Buffer.BlockCopy(encryptedKey.ToCharArray(), 0, bytes, 0, bytes.Length);

string decryptedKey;
using (MemoryStream mStream = new MemoryStream())
{
    mStream.Write(bytes, 0, bytes.Length);
    var decryptRequest = new DecryptRequest()
    {CiphertextBlob = mStream};
    var decryptResponse = client.Decrypt(decryptRequest);
    using (StreamReader reader = new StreamReader(decryptResponse.Plaintext))
    {
        decryptedKey = reader.ReadToEnd();
    }
}

I am assuming (1) that there is something changing the data somehow and not some other error; (2) that it is in the stream -> string or string -> stream transition, and not the string -> file or string <- file transition; and (3) that a perfect copy of the data coming in and going out will fix the problem–the data coming in is supposed to be a "plaintext" encrypted version; maybe there is an expectation that I encode the stream coming in and going out (does encoding even change the data? I'm judging from the post that it does).

Either a confirmation that the bytes should be equivalent going in and going out, or a way to capture the memorystream in a file, and send it back out without changing anything would be awesome.

Best Answer

Let's say, that your MemoryStream contains the following input data: [0x01, 0x02, 0x03, 0x04] When you read it with streamreader, the binary representation of your string will be: [0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04], because strings use two byte representation for a character. What you do afterwards is that you allocate 8 bytes for your "bytes" variable instead of 4, and fill it with the second (modified) data. You can use Convert.ToBase64String() to get a string representation, also you can use FromBase64String() to parse it back. Something like this:

var testData = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
var inputStream = new MemoryStream(testData);

var inputAsString = Convert.ToBase64String(inputStream.ToArray());
Console.WriteLine(inputAsString);

var outputStream = new MemoryStream(Convert.FromBase64String(inputAsString));

var result = BitConverter.ToString(outputStream.ToArray());           
Console.WriteLine(result);