17

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.

Community
  • 1
  • 1
Chris
  • 21,703
  • 21
  • 59
  • 114
  • 6
    Don't save binary (non-text) data as a string. There's no point. Just treat like a stream of bytes. – Blorgbeard May 28 '15 at 22:08
  • Here's how to save/load a memorystream: http://stackoverflow.com/questions/8624071/save-and-load-memorystream-to-from-a-file – Blorgbeard May 28 '15 at 22:09
  • You cannot store arbitrary bytes as strings because [strings have rules](http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences) and arbitrary bytes don't. You have to encode the bytes somehow (e.g. Base64) or store raw bytes, not strings. – Dour High Arch May 28 '15 at 23:16
  • The memorystream is an encrypted key, while the data that was encrypted using the key is an encrypted string. If the memorystream is saved as a string, I can save both the encrypted key and the encrypted data as two strings in the same file. Im not sure how I would save a string next to a memorystream and read that back out...and since this is just a proof of concept, getting it done quickly is what is important at the moment...is there a way to save a string next to a memory stream in the same file? – Chris May 29 '15 at 13:59
  • “If the memorystream is saved as a string”; well if 32 was greater than 128 you could save a `decimal` in an `int`. But it isn't and you can't. – Dour High Arch May 29 '15 at 15:40
  • Oh, I converted it to a base64string and it worked fine. I'm just wondering if it would be possible to save it alongside the encrypted string without changing it to a string. – Chris May 29 '15 at 15:59
  • As other's have said, if you have binary data just dump it to a file directly. Don't convert it to a string unless you have a valid business requirement. Converting it to base64 will increase the space requirements by 33%. For example, converting 12 bytes to base64 will give you a string that's 16 bytes. – iheartcsharp Mar 09 '18 at 16:10

1 Answers1

26

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);
Viktor Peller
  • 536
  • 4
  • 7