Encrypt and compress FileStream and save to same file - c#

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.

Related

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

Encryption of file using algorithm Salsa20

I'm doing my homework. It's connected with encryption of file.
I use algorithm Salsa20
Here's my code:
using (var salsa = new Salsa20.Salsa20())
{
using (var fstream_out = new FileStream(filePath, FileMode.Truncate, FileAccess.ReadWrite, FileShare.Write))
{
salsa.Key = key;
salsa.IV = iv;
using (var cstream = new CryptoStream(fstream_out, salsa.CreateEncryptor(), CryptoStreamMode.Write))
{
var bytes = File.ReadAllBytes(filePath);
cstream.Write(bytes, 0, 1000000);
}
}
}
When I try to encrypt file, there's exception "The process cannot access the file because it is being used by another process."
What's wrong?

Crypto stream: read data error

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();
}

Error about padding occurs during my attempt to decrypt string data from a FileStream using Rijndael

I'm trying to encrypt some strings (actually a walkaround for encrypt an XElement object) into a file using Rijndael. However when decrypting, a CryptographicException will be thrown with the message "Padding is invalid and cannot be removed".
I've been searching several posts for possible solutions, in which someone mentions the PaddingMode, the FlushFinalBlock() method, and others.
Also someone has mentioned that it's because reading directly from a FileStream will set the length of the stream to that of the file, thus leaving no room for padding, but I don't know how to resolve the issue. Please kindly give your suggestions.
var root = new XElement("Users",
new XElement("User", new XAttribute("id", "1"), "User1"),
new XElement("User", new XAttribute("id", "2"), "User2"));
var r = Rijndael.Create();
r.Padding = PaddingMode.PKCS7;
using (var fs = File.Open(#"D:\user.xml", FileMode.Create))
using (var cs = new CryptoStream(fs, r.CreateEncryptor(r.Key, r.IV), CryptoStreamMode.Write))
using (var sw = new StreamWriter(cs, Encoding.Unicode))
{
sw.Write(root.ToString());
cs.FlushFinalBlock();
}
var r = Rijndael.Create();
r.Padding = PaddingMode.PKCS7;
using(var fs = File.Open(#"D:\user.xml", FileMode.Open, FileAccess.ReadWrite))
using(var cs = new CryptoStream(fs, r.CreateDecryptor(r.Key, r.IV), CryptoStreamMode.Read))
using (var sr = new StreamReader(cs, Encoding.Unicode))
{
var root = sr.ReadToEnd();
}
I believe you need to flush the stream writer as well.
As a note, make sure you actually use a random IV ( which you are doing here). Sometimes people write code like this and then when the go to use it to decrypt the file later, the realize they don't have the IV and so they just hard code it. Just prepend it to the file.
{
sw.Write(root.ToString());
cs.FlushFinalBlock();
sw.flush();
}

Encrypting a ZipPackage Stream in Memory

I am using .NET 4.0 and trying to do the following:
Create a System.IO.Packaging.Package in Memory
Add Items to the package
encrypt package before it is written to file.
I tried to create a MemoryStream and add the files to it by:
using (var memoryZip = Package.Open(_memoryStream, FileMode.Open))
{
var partUri = PackUriHelper.CreatePartUri(_fileUri);
var part = memoryZip.CreatePart(
partUri,
String.Empty,
CompressionOption.NotCompressed);
using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
fileStream.CopyTo(packagePart.GetStream());
}
}
Then I tried to encrypt it and saved it to a file:
_key = new DESCryptoServiceProvider
{
Key = Encoding.ASCII.GetBytes(_password);
IV = Encoding.ASCII.GetBytes(_password);
}
var fileStream = File.Open(_fileName, FileMode.Create, FileAccess.Write);
var cryptoStream = new CryptoStream(streamToFile, _key.CreateEncryptor(), CryptoStreamMode.Write);
//Convert filestream to byte[]
var streamAsBytes = new byte[(_memoryStream.Length)];
_memoryStream.Read(streamAsBytes, 0, streamAsBytes.Length);
//Encrypt
cryptoStream.Write(streamAsBytes, 0, streamAsBytes.Length);
fileStream.Close();
cryptoStream.Flush();
cryptoStream.Close();
However, when I go to decrypt it:
var fileStream = new FileStream(_zipFileName, FileMode.Open, FileAccess.Read);
var cryptoStream = new CryptoStream(fileStream, _key.CreateDecryptor(), CryptoStreamMode.Read);
using(var zipPackage = Package.Open(cryptoStream, FileMode.Open))
I get a FileFormatException: "File contains corrupted data."
This isn't the same message you would get if decryption failed. I would expect that the stream that went in during encryption is the same one as the one that came out so any idea why the package would be corrupted?

Categories