Crypto stream: read data error - c#

I got this (i also tried crStream.CopyTo(ms)):
var cryptic = new DESCryptoServiceProvider();
cryptic.Key = ASCIIEncoding.ASCII.GetBytes(passKey);
cryptic.IV = ASCIIEncoding.ASCII.GetBytes(passKey);
Stream crStream = new CryptoStream(data, cryptic.CreateEncryptor(), CryptoStreamMode.Write);
Stream ms = new MemoryStream();
var buffer = new byte[0x10000];
int n;
while ((n = crStream.Read(buffer, 0, buffer.Length)) != 0) // Exception occurs here
ms.Write(buffer, 0, n);
crStream.Close();
Data = Stream and contains a binary serialized class
The following exception occurs when i run it:
"Stream does not support reading."
What i am trying to accomplish is simply encrypt data from a stream. So i have an incoming stream and i want to encrypt that data and put it into the memory stream. This will then be compressed and saved to a file.

the error says everything: you create the stream for encryption (= put plain-text into and get encrypted output, in write):
Stream crStream = new CryptoStream(data, cryptic.CreateEncryptor(), CryptoStreamMode.Write);
Just have a look at the MSDN-Documentation for CryptoStream - there is a example included of how to do it right - it's basically this part (right from MSDN):
using (MemoryStream msEncrypt = new MemoryStream())
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}

Related

TransformFinalBlock vs CryptoStream

I am confused about this topic when it comes to AES encryption.
The MSDN page shows quite a lot of code used to encrypt/decrypt and uses multiple streams:
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
While the video on encryption from MS shows all of this done in a single line:
byte[] plainText = cryptTransform.TransofmrFinalBlock(cipherText, 0, cipherText.Length);
Why would I use the former over the latter? Is there something the first one does that the second on can't?

How to read contents of MemoryStream, fed by a cryptostream

I am working on some AES encryption in C#. I have a similar decryption method which functions flawlessly, however, no matter what I try I cannot read the encrypted contents of the MemoryStream
I have tried a few different ways of reading,
ms.Position = 0;
return new StreamReader(ms, Encoding.ASCII).ReadToEnd()
OR
using (StreamReader sr = new StreamReader(cs)) {
return sr.ReadToEnd();
}
OR
byte[] enc = ms.ToArray();
string ret=null;
foreach (byte b in enc) {
ret += b.ToString();
}
Here's the snippet from the code.
using (AesManaged aesMan = new AesManaged()) {
if (keystr.Length == aesSize/8)
{
//Its a valid key
aesMan.KeySize = aesSize;
aesMan.Key = Encoding.UTF8.GetBytes(keystr);
aesMan.IV = Encoding.UTF8.GetBytes(ivstr);
ICryptoTransform encryptor aesMan.CreateEncryptor(aesMan.Key, aesMan.IV);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(inpstr);
using (StreamReader sr = new StreamReader(ms)) {
return sr.ReadToEnd();
}
}
}
I get various errors, such as the stream is not readable, or that it cannot read a closed stream, as well as a blank string being returned.
Has anyone got any ideas? I'm at a loss
Most of those stream functions like StreamReader, StreamWriter, etc., close the underlying stream when you Dispose() them. Try not disposing them until you are done, or using the constructors that allow you to chose not to close the underlying stream. In rare cases, I've had to implement a dummy wrapper around a stream to prevent closing the underlying stream

Memory issue while encrypting files

I have a memory issue while reading a file and encrypt it in C# UWP.
This is my code:
using System;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using Windows.Storage;
using System.Runtime.InteropServices.WindowsRuntime;
public async void encrypt_file(StorageFile file, string key, string pw_salt)
{
try
{
SymmetricAlgorithm algorithm = Aes.Create();
DeriveBytes rgb = new Rfc2898DeriveBytes(key, Encoding.Unicode.GetBytes(pw_salt));//create password
byte[] rgbKey = rgb.GetBytes(algorithm.KeySize >> 3);
byte[] rgbIV = rgb.GetBytes(algorithm.BlockSize >> 3);
ICryptoTransform transform = algorithm.CreateEncryptor(rgbKey, rgbIV);//create encrytor/decryptor
using (MemoryStream memStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memStream, transform, CryptoStreamMode.Write))
{
byte[] plainContent = (await FileIO.ReadBufferAsync(file)).ToArray();//read bytes
cryptoStream.Write(plainContent, 0, plainContent.Length);
cryptoStream.FlushFinalBlock();
await FileIO.WriteBufferAsync(file, memStream.ToArray().AsBuffer());//write bytes
await file.RenameAsync(file.Name + ".myfile");
plainContent = null;
cryptoStream.Dispose();
memStream.Dispose();
transform.Dispose();
}
}
GC.Collect();
}
catch { }
}
After I run this code, my application is using too much memory. What am I doing wrong?
Posted as an answer, because as a comment it would be illegible.
I don't have experience with UWP, so unfortunately I can't make the exact changes to your code, but in general .NET you would do:
var buffer = new byte[1024 * 1024]; // 1MB buffer
using (var encryptedStream = new FileStream("FileName.ext.aes", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, buffer.Length, FileOptions.Asynchronous))
{
using (var crypto = new CryptoStream(encryptedStream, encryptor, CryptoStreamMode.Write))
{
using (var unencryptedStream = new FileStream("FileName.ext", FileMode.Open, FileAccess.Read, FileShare.Read, buffer.Length, FileOptions.Asynchronous))
{
int bytesRead;
do
{
bytesRead = await unencryptedStream.ReadAsync(buffer, 0, buffer.Length);
await crypto.WriteAsync(buffer, 0, bytesRead);
} while (bytesRead == buffer.Length);
}
}
}
So, you read a block from your unencrypted stream and write it to your crypro stream, who in turn will encrypt the data and writes this to your output stream. Then you check if the amount of data read equals the requested amount of data to be read (buffer.Length). If its less it means you reached the end of the stream.
This way your memory footprint is restricted to the buffer size (in this example 1MB).

Encrypt and compress FileStream and save to same file

I have a method to compress and encrypt a stream.
private static void CompressThenEncrypt(string inputFileName, ICryptoTransform encryptor)
{
using (var inputFileStream = new FileStream(inputFileName, FileMode.Open, FileAccess.ReadWrite))
using (var cryptoStream = new CryptoStream(inputFileStream, encryptor, CryptoStreamMode.Write))
using (var zipStream = new GZipStream(cryptoStream, CompressionMode.Compress))
{
inputFileStream.CopyTo(zipStream);
}
}
Which does work, but it appends compressed and encrypted data to raw one I have in that file.
So if my file contains:
kkk
Then after compression and encryption it does look for example like that:
kkkㆆ鬁⠕⟶ꏙᇚ셑襜㷡ꕢ束৘㺝娥☪
Do anyone have any idea how to overwrite new data?
I suggest:
Write to a new file
Delete the old file
Rename the new file to the old file.
Write to a temporary MemoryStream. Something like:
private static void CompressThenEncrypt(string inputFileName, ICryptoTransform encryptor)
{
using (var fileStream = new FileStream(inputFileName,FileMode.Open, FileAccess.ReadWrite))
using (var memoryStream = new MemoryStream())
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
using (var zipStream = new GZipStream(cryptoStream, CompressionMode.Compress))
{
fileStream.CopyTo(zipStream);
cryptoStream.FlushFinalBlock();
fileStream.SetLength(0);
memoryStream.Position = 0;
memoryStream.CopyTo(fileStream);
}
}
I think that should work, from the top of my head. Not sure you would have to set the length, and I'm not sure you can get away with not resetting the position of the MemoryStream. I haven't tested this code. If you are concerned about memory usage, you can always buffer the usage, but that would require more complicated code.

Padding invalid when decrypting stream

I am trying to encrypt a stream (coming from a file) using AesManaged. I can encrypt the file without error, but on decryption I get the following CryptographicException:
Padding is invalid and cannot be
removed.
The exception is raised when the CryptoStream is being disposed. I use the following to encrypt the input data:
public byte[] Encrypt(Stream plain)
{
// Create a decrytor to perform the stream transform.
using( var msEncrypt = new MemoryStream() )
{
using (ICryptoTransform encryptor = _myAes.CreateEncryptor(_myAes.Key, _myAes.IV))
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (BinaryWriter swEncrypt = new BinaryWriter(csEncrypt))
{
int buf_size = 32768;
byte[] buffer = new byte[buf_size];
int read = 0;
while ((read = plain.Read(buffer, 0, buf_size)) > 0)
{
swEncrypt.Write(buffer, 0, read);
}
}
return msEncrypt.ToArray();
}
}
And this to decrypt the data:
public byte[] Decrypt(Stream cipherText)
{
using (MemoryStream ms = new MemoryStream())
{
// Create a decrytor to perform the stream transform.
using (ICryptoTransform decryptor = _myAes.CreateDecryptor(_myAes.Key, _myAes.IV))
using (CryptoStream csDecrypt = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
using (BinaryWriter swDecrypt = new BinaryWriter(csDecrypt))
{
int buf_size = 32768;
byte[] buffer = new byte[buf_size];
int read = 0;
while ((read = cipherText.Read(buffer, 0, buf_size)) > 0)
{
swDecrypt.Write(buffer, 0, read);
}
}
return ms.ToArray();
}
}
Any ideas about why this exception is coming up would be great. Thanks
UPDATE
Here is where the Aes object was created, note the Key and IV are just set to their current values temporarily, it is not the real key that will be used:
private Crypto()
{
_myAes = new AesManaged();
_myAes.Padding = PaddingMode.PKCS7;
_myAes.KeySize = 128;
_myAes.Key = Enumerable.Repeat((byte)'B', 128 / 8).ToArray();
_myAes.IV = Enumerable.Repeat((byte)'C', 128 / 8).ToArray();
}
In the past I got this exception when I tried to decrypt a buffer whose length was not a multiple of 16 bytes.
Did you try calling Flush on the CryptoStream before it is disposed? Possibly, if it isn't flushed then it ends up trying to decrypt a buffer with a non-aligned length.
And another note - I don't know if this will solve your problem, but when you create a CryptoStream in order to decrypt the buffer, shouldn't you be using CryptoStreamMode.Read instead of CryptoStreamMode.Write?
Ensure that you finish the CryptoStream cleanly on the write side. You may need to call FlushFinalBlock() to ensure that the end-of-stream padding is written through -- otherwise, you are likely to end up missing the final block of the stream, which will result in an invalid padding exception.
I don't know if it is still relevant to post something after 4 years but, you should try to set padding to none. I got the same problem with 3DES and the issue got solved with that (but make sure the length of data to be decrypted is correct...)
private Crypto()
{
_myAes = new AesManaged();
_myAes.Padding = PaddingMode.none; //rather than _myAes.Padding = PaddingMode.PKCS7;
_myAes.KeySize = 128;
_myAes.Key = Enumerable.Repeat((byte)'B', 128 / 8).ToArray();
_myAes.IV = Enumerable.Repeat((byte)'C', 128 / 8).ToArray();
}

Categories