Search code examples
c#encryptioncryptostream

CryptoStream: Why CryptoStreamMode.Write to encrypt and CryptoStreamMode.Read to decrypt?


Let e = 'password' and I am transforming it to 'as9kio0736' in a CryptoStream.

Let d = 'as9kio0736' and I am transforming it to 'password in a CryptoStream.

When I am transforming d back to 'password' why is it not considered writing in a CryptoStream?

using (MemoryStream msEncrypt = new MemoryStream()) {
    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) {
            swEncrypt.Write(plainText);
        }
    }
}

using (MemoryStream msDecrypt = new MemoryStream(cipherText)) {
    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) {
        using (StreamReader srDecrypt = new StreamReader(csDecrypt)) {
            plaintext = srDecrypt.ReadToEnd();
        }
    }
}

Solution

  • CryptoStream is designed to perform transformation from a stream to another stream only and allows transformations chaining. For instance you can encrypt a data stream then Base 64 encode the encryption output.

    Chose the mode depending on whether you want to write to the transformation input stream or read from the transformation output stream.

    CryptoStream documentation is misleading.
    The first CrytoStream constructor argument is described as:
    "The stream on which to perform the cryptographic transformation"

    This description is ok if constructor third argument value is CryptoStreamMode.Read.

    But if third argument value is CryptoStreamMode.Write the first constructor argument description should be:
    "The stream on which the result of cryptographic transformation is written to"

    Also, documentation does not mention clearly that if you use CryptoStreamMode.Write, you MUST call FlushFinalBlock on your CryptoStream object after you finish writing.

    To summarize this:

    Writing to the transformation input stream:

    CryptoStream constructor arguments:

    • argument 1: destination stream
    • argument 3: CryptoStreamMode.Write

    CryptoStream object use:

    • Write data to the CryptoStream object
    • Call FlushFinalBlock on the CryptoStream object

    Reading from the transformation output stream:

    CryptoStream constructor arguments:

    • argument 1: source stream
    • argument 3: CryptoStreamMode.Read

    CryptoStream object use:

    • Read data from the CryptoStream object until you reach the stream end