C# "Bad Data" exception when decrypting encrypted file - c#

Hey I'm very new to encryption and decryption, or even the c# language to be honest. Basically, I have a tcp chat server that "saves" logs and encrypts the text file. This is how I encrypt (based from the MSDN sample):
public static void EncryptFile(string strInputFileName, string strOutputFileName, string strKey)
{
FileStream fsIn = new FileStream(strInputFileName, FileMode.Open, FileAccess.Read);
FileStream fsOut = new FileStream(strOutputFileName, FileMode.Create, FileAccess.Write);
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
des.Key = ASCIIEncoding.ASCII.GetBytes(strKey);
des.IV = ASCIIEncoding.ASCII.GetBytes(strKey);
ICryptoTransform desencrypt = des.CreateEncryptor();
CryptoStream cryptostream = new CryptoStream(fsOut, desencrypt, CryptoStreamMode.Write);
byte[] byteArrayInput = new byte[fsIn.Length - 1];
fsIn.Read(byteArrayInput, 0, byteArrayInput.Length);
cryptostream.Write(byteArrayInput, 0, byteArrayInput.Length);
fsIn.Close();
fsOut.Close();
}
The method success fully encrypts files. This is my decrypt method:
public static void DecryptFile(string strInputFileName, string strOutputFileName, string strKey)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
des.Key = ASCIIEncoding.ASCII.GetBytes(strKey);
des.IV = ASCIIEncoding.ASCII.GetBytes(strKey);
byte[] te = new byte[1024];
FileStream fsRead = new FileStream(strInputFileName, FileMode.Open, FileAccess.Read);
ICryptoTransform desdecrypt = des.CreateDecryptor();
CryptoStream cryptostream = new CryptoStream(fsRead, desdecrypt, CryptoStreamMode.Read);
StreamWriter fsDecrypted = new StreamWriter(strOutputFileName);
fsDecrypted.Write(new StreamReader(cryptostream).ReadToEnd());//This is where the "Bad Data" occurs.
fsDecrypted.Flush();
fsDecrypted.Close();
fsRead.Close();
}
And when I inspect the cryptostream object, it says that it has thrown an exception, "Stream does not support seeking".
Any help would be greatly appreciated!

Here:
cryptostream.Write(byteArrayInput, 0, byteArrayInput.Length);
fsIn.Close();
fsOut.Close();
You're closing fsOut directly, without closing cryptostream. That means the crypto stream doesn't get the chance to flush any final blocks etc.
Additionally:
Use using statements instead of manually calling Close or Dispose
You're currently calling Read once, and assuming it will read all the data - you're not checking the return value. (You're also removing the last byte of the input file for some reason... why?) In general, you should loop round, reading into a buffer and then writing out however many bytes you read, until the Read method returns 0. If you're using .NET 4, Stream.CopyTo is your friend.

objCryptStream.CopyTo(stream);
Worked for me, complete code is
public static string DecryptString(string encriptedText, string key)
{
try
{
//Convert the text into bytest
byte[] ecriptedBytes = System.Convert.FromBase64String(encriptedText);
// Create a memory stream to the passed buffer
MemoryStream objMemStream = new MemoryStream(ecriptedBytes);
//Set the legal keys and initialization verctors
objCrptoService.Key = GetLegalsecretKey(key);
objCrptoService.IV = GetLegalIV();
// Create a CryptoStream using the memory stream and the cryptographic service provider version
// of the Data Encryption stanadard algorithm key
CryptoStream objCryptStream = new CryptoStream(objMemStream, objCrptoService.CreateDecryptor(), CryptoStreamMode.Read);
// Create a StreamReader for reading the stream.
//StreamReader objstreamReader = new StreamReader(objCryptStream);
MemoryStream stream = new MemoryStream();
objCryptStream.CopyTo(stream);
stream.Position = 0;
StreamReader R = new StreamReader(stream);
string outputText = R.ReadToEnd();
// Close the streams.
R.Close();
objCryptStream.Close();
objMemStream.Close();
return outputText;
}
catch (Exception exc)
{
return "";
}
}

What fixed my issue was calling FlushFinalBlock on cryptostream, When creating the file
CryptoStream cryptostream = new CryptoStream(memoryStream, this._encryptionKeyHelper.Encryptor(), CryptoStreamMode.Write);
xmlser.Serialize(cryptostream, builderObject);
cryptostream.FlushFinalBlock();

Related

Length of the key to encrypt a file

Many years ago I used this code to encrypt an entire file:
public static void CryptFile(string sInputFilename, string sOutputFilename, string sKey)
{
FileStream fsInput = new FileStream(sInputFilename, FileMode.Open, FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFilename, FileMode.Create, FileAccess.Write);
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
ICryptoTransform desencrypt = DES.CreateEncryptor();
CryptoStream cryptostream = new CryptoStream(fsEncrypted,desencrypt,CryptoStreamMode.Write);
byte[] bytearrayinput = new byte[fsInput.Length];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Close();
fsInput.Close();
fsEncrypted.Close();
}
Today I tried to use it again but I always get this error:
the specified key size is not valid for this algorithm.
I have tried with many strings of varying length but cannot understand which is the correct length to use.
The correct length is 8 characters, such as "12345678"

Why my c# encryption is working but decryption said bad data

So im making a encryption/decryption windows forms project for fun, but my decryption app shows me a error:
An unhandled exception of type 'System.Security.Cryptography.CryptographicException' occurred in mscorlib.dll
Additional information: Bad Data.
I can't find any fixes in the internet and in not that good in c#, so maybe you can help me.
Encryption:
static void EncryptFile(string sInputFile,
string sOutputFile,
string sKey)
{
FileStream fsInput = new FileStream(sInputFile, FileMode.Open, FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFile, FileMode.Create, FileAccess.Write);
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
ICryptoTransform desencrypt = DES.CreateEncryptor();
CryptoStream cryptoStream = new CryptoStream(fsEncrypted, desencrypt, CryptoStreamMode.Write);
byte[] bytearrayinput = new byte[fsInput.Length - 1];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptoStream.Write(bytearrayinput, 0, bytearrayinput.Length);
}
Decryption:
static void DecryptFile(string sInputFilename,
string sOutputFilename,
string sKey)
{
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
FileStream fsread = new FileStream(sInputFilename, FileMode.Open, FileAccess.Read);
ICryptoTransform desdecrypt = DES.CreateDecryptor();
CryptoStream cryptostreamDecr = new CryptoStream(fsread, desdecrypt, CryptoStreamMode.Read);
StreamWriter fsDecrypted = new StreamWriter(sOutputFilename);
fsDecrypted.Write(new StreamReader(cryptostreamDecr).ReadToEnd());
fsDecrypted.Flush();
fsDecrypted.Close();
}
How i use them:
EncryptFile(fileBox.Text, fileOutFolder+"/encrypted.txt", sSecretKey);
DecryptFile(fileBox.Text, saveFileDialog1.FileName, keyBox.Text)
The encrypted data is probably not in the target file when you read from it.
You should close your streams in EncryptFile. And since stream are disposable, you should put them in a 'using' construct:
using (fsInput=[....])
{
using (fsEncrypted=[..])
{
[....]
fsEnCrypted.Close();
}
}
I think solution to Your problem is quite simple and lies in calling DecryptFile(...) method. I don't know whole code, but try to replace SaveFileDialog object with OpenFileDialog object. I can't see any SaveFileDialog object in Your attached code, so it's only rational explanation of this strange behaviour in Your app.
Hope this will be helpfull for You.
Well... just by adding flush() and close() to my cryptoStream did work.
Feel free to use this lazt as f*** encryption meth-od.

Decrypt file have bad data if wrong key

I've code to decrypt file in DES Encryption, I try I keep getting the file even though I enter the key at the time when the key decrypt the encrypted differently. But i've get the error.
while ((data = cryptostreamDecr.ReadByte()) != -1) // Message Error : Bad Data.
Which code should I add or change in order to keep the process running decrypt?
private static void DecryptFile(string sInputFilename, string sKey)
{
var DES = new DESCryptoServiceProvider();
DES.Key = Encoding.ASCII.GetBytes(sKey);
DES.IV = Encoding.ASCII.GetBytes(sKey);
ICryptoTransform desdecrypt = DES.CreateDecryptor();
using (var fsread = new FileStream(sInputFilename, FileMode.Open,
FileAccess.ReadWrite))
{
using (var cryptostreamDecr = new CryptoStream(fsread,
desdecrypt,
CryptoStreamMode.Read))
{
int data;
fsread.Flush();
using (var ms = new MemoryStream())
{
while ((data = cryptostreamDecr.ReadByte()) != -1)
{
ms.WriteByte((byte)data);
}
cryptostreamDecr.Close();
using (var fsWrite = new FileStream(sInputFilename, FileMode.Truncate))
{
ms.WriteTo(fsWrite);
ms.Flush();
}
}
}
}
}
Encrypt Code :
public static void EncryptFile(string sInputFilename, string sKey)
{
FileStream fsInput = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.ReadWrite);
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
ICryptoTransform desencrypt = DES.CreateEncryptor();
CryptoStream cryptostream = new CryptoStream(fsInput,
desencrypt,
CryptoStreamMode.Write);
byte[] bytearrayinput = new byte[fsInput.Length];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
fsInput.SetLength(0);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.FlushFinalBlock();
cryptostream.Close();
fsInput.Close();
}
[EDIT] : remove in Encypt :
cryptostream.FlushFinalBlock();
And add in decrypt
DES.Padding = PaddingMode.None;
64 bits is the only valid key size for the DES encryption algorithm.
8 bits is equal to one ASCII character means 64 bits is equal to 8 Characters.
If you send 8 characters only then check this (C# "Bad Data" exception when decrypting encrypted file). It may solve your problem.
[Edit]
Add DES.Padding = PaddingMode.None; in DecryptFile.

Using Rijndael to encrypt/decrypt files

I need to transfer xml files and they are required to be encrypted. I have found some examples think I'm close but when I decrypt the file I end up with trailing junk characters. There are some posts about this but I have not seen any that will exactly help. Here is the encrypt and decrypt code.
private void EncryptFile(string inputFile, string outputFile, string key) {
try {
byte[] keyBytes;
keyBytes = Encoding.Unicode.GetBytes(key);
Rfc2898DeriveBytes derivedKey = new Rfc2898DeriveBytes(key, keyBytes);
RijndaelManaged rijndaelCSP = new RijndaelManaged();
rijndaelCSP.Key = derivedKey.GetBytes(rijndaelCSP.KeySize / 8);
rijndaelCSP.IV = derivedKey.GetBytes(rijndaelCSP.BlockSize / 8);
ICryptoTransform encryptor = rijndaelCSP.CreateEncryptor();
FileStream inputFileStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read);
byte[] inputFileData = new byte[(int)inputFileStream.Length];
inputFileStream.Read(inputFileData, 0, (int)inputFileStream.Length);
FileStream outputFileStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write);
CryptoStream encryptStream = new CryptoStream(outputFileStream, encryptor, CryptoStreamMode.Write);
encryptStream.Write(inputFileData, 0, (int)inputFileStream.Length);
encryptStream.FlushFinalBlock();
rijndaelCSP.Clear();
encryptStream.Close();
inputFileStream.Close();
outputFileStream.Close();
}
catch (Exception ex) {
MessageBox.Show(ex.Message, "Encryption Failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
MessageBox.Show("File Encryption Complete!");
}
private void DecryptFile(string inputFile, string outputFile, string key) {
try {
byte[] keyBytes = Encoding.Unicode.GetBytes(key);
Rfc2898DeriveBytes derivedKey = new Rfc2898DeriveBytes(key, keyBytes);
RijndaelManaged rijndaelCSP = new RijndaelManaged();
rijndaelCSP.Key = derivedKey.GetBytes(rijndaelCSP.KeySize / 8);
rijndaelCSP.IV = derivedKey.GetBytes(rijndaelCSP.BlockSize / 8);
ICryptoTransform decryptor = rijndaelCSP.CreateDecryptor();
FileStream inputFileStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read);
CryptoStream decryptStream = new CryptoStream(inputFileStream, decryptor, CryptoStreamMode.Read);
byte[] inputFileData = new byte[(int)inputFileStream.Length];
decryptStream.Read(inputFileData, 0, (int)inputFileStream.Length);
FileStream outputFileStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write);
outputFileStream.Write(inputFileData, 0, inputFileData.Length);
outputFileStream.Flush();
rijndaelCSP.Clear();
decryptStream.Close();
inputFileStream.Close();
outputFileStream.Close();
}
catch (Exception ex) {
MessageBox.Show(ex.Message, "Decryption Failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
MessageBox.Show("File Decryption Complete!");
}
I end up with
<?xml version="1.0" encoding="UTF-8"?>
<transaction>
<header>
<qOrderNumber></qOrderNumber>
<qRequestDate></qRequestDate>
<testOrder></testOrder>
<qCustomerNumber></qCustomerNumber>
<transactionStatus></transactionStatus>
</header>
<lines>
<line>
<productID></productID>
<serialNumber></serialNumber>
</line>
<line>
<productID></productID>
<serialNumber></serialNumber>
</line>
</lines>
</transaction>NULNULNULNULNULNUL
When decrypting, pay attention to the return value from the CryptoStream.Read call. It tells you the length of the decrypted data in your byte array (usually will not match the length of the encrypted data due to padding). Try using the following in your decrypt function:
int decrypt_length = decryptStream.Read(inputFileData, 0, (int)inputFileStream.Length);
FileStream outputFileStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write);
outputFileStream.Write(inputFileData, 0, decrypt_length);
On the RijndaelManaged object, set the Padding property to PaddingMode.ANSIX923 or PaddingMode.ISO10126.
Those null bytes were added to fill out the final encrypted block. It was padded with zeros by default, which means that no indication is given as to the actual length of the data. The other padding modes include a length in the final byte, so that the padding can be removed after decryption.
Set the padding property in both the encrypt and decrypt routine to the same value.
rijndaelCSP.Padding = PaddingMode.ANSIX923;
If it knows what to expect, then the decryption stream will remove the padding automatically, so no further changes should be necessary.
UPDATE
From looking at your code, it appears that the number of bytes that you are writing to the output file is equal to the number of bytes read in from the input file.
byte[] inputFileData = new byte[(int)inputFileStream.Length];
decryptStream.Read(inputFileData, 0, (int)inputFileStream.Length);
The decryption process is not going to completely fill up the inputFileData array, because of the padding in the input.
The output stream will then write out the entire length of the buffer, even though it wasn't completely filled.
outputFileStream.Write(inputFileData, 0, inputFileData.Length);
This is the source of your nulls.
You may want to change the way you are doing the encryption and decryption so that it no longer uses fixed-length bufferes. Alternatively, you could store the length of the encrypted data at the beginning, and only write the number of bytes that correspond to that length.

How to encrypt and save a binary stream after serialization and read it back?

I am having some problems in using CryptoStream when I want to encrypt a binary stream after binary serialization and save it to a file. I am getting the following exception
System.ArgumentException : Stream was not readable.
Can anybody please show me how to encrypt a binary stream and save it to a file and deserialize it back correctly?
The code is as follows:
class Program
{
public static void Main(string[] args)
{
var b = new B {Name = "BB"};
WriteFile<B>(#"C:\test.bin", b, true);
var bb = ReadFile<B>(#"C:\test.bin", true);
Console.WriteLine(b.Name == bb.Name);
Console.ReadLine();
}
public static T ReadFile<T>(string file, bool decrypt)
{
T bObj = default(T);
var _binaryFormatter = new BinaryFormatter();
Stream buffer = null;
using (var stream = new FileStream(file, FileMode.OpenOrCreate))
{
if(decrypt)
{
const string strEncrypt = "*#4$%^.++q~!cfr0(_!#$#$!&#&#*&#(7cy9rn8r265&$#&*E^184t44tq2cr9o3r6329";
byte[] dv = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF};
CryptoStream cs;
DESCryptoServiceProvider des = null;
var byKey = Encoding.UTF8.GetBytes(strEncrypt.Substring(0, 8));
using (des = new DESCryptoServiceProvider())
{
cs = new CryptoStream(stream, des.CreateEncryptor(byKey, dv), CryptoStreamMode.Read);
}
buffer = cs;
}
else
buffer = stream;
try
{
bObj = (T) _binaryFormatter.Deserialize(buffer);
}
catch(SerializationException ex)
{
Console.WriteLine(ex.Message);
}
}
return bObj;
}
public static void WriteFile<T>(string file, T bObj, bool encrypt)
{
var _binaryFormatter = new BinaryFormatter();
Stream buffer;
using (var stream = new FileStream(file, FileMode.Create))
{
try
{
if(encrypt)
{
const string strEncrypt = "*#4$%^.++q~!cfr0(_!#$#$!&#&#*&#(7cy9rn8r265&$#&*E^184t44tq2cr9o3r6329";
byte[] dv = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF};
CryptoStream cs;
DESCryptoServiceProvider des = null;
var byKey = Encoding.UTF8.GetBytes(strEncrypt.Substring(0, 8));
using (des = new DESCryptoServiceProvider())
{
cs = new CryptoStream(stream, des.CreateEncryptor(byKey, dv), CryptoStreamMode.Write);
buffer = cs;
}
}
else
buffer = stream;
_binaryFormatter.Serialize(buffer, bObj);
buffer.Flush();
}
catch(SerializationException ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
[Serializable]
public class B
{
public string Name {get; set;}
}
It throws the serialization exception as follows
The input stream is not a valid binary format. The starting contents (in bytes)
are: 3F-17-2E-20-80-56-A3-2A-46-63-22-C4-49-56-22-B4-DA ...
If you do it like this, it should work:
// A: encrypting when writing
// 1. create backing storage stream. In your case a file stream
using(Stream innerStream = File.Create(path))
// 2. create a CryptoStream in write mode
using(Stream cryptoStream = new CryptoStream(innerStream, encryptor, CryptoStreamMode.Write))
{
// 3. write to the cryptoStream
binaryFormatter.Serialize(cryptoStream, obj);
}
// B: decrypting when reading
// 1. create backing storage stream. In your case a file stream
using(Stream innerStream = File.Open(path, FileMode.Open))
// 2. create a CryptoStream in read mode
using(Stream cryptoStream = new CryptoStream(innerStream, decryptor, CryptoStreamMode.Read))
{
// 3. read from the cryptoStream
obj = binaryFormatter.Deserialize(cryptoStream);
}
There are a couple of problems with your code:
You're using an encryptor when reading. This was probably a typo, but it should be a decryptor.
You are flushing the buffer, but that is not enough when using a CryptoStream. Encryptors and decryptors work on blocks of a fixed size. The last block may not have that size, so it needs special treatment. The last block is the one written before the stream is closed, not flushed. Flushing on a CryptoStream does nothing useful, because it cannot write anything of size less than the input block size of the encryptor/decryptor, unless it is the last thing to be written. And on top of this, in general you should always close your streams, no matter what. The using statement is the recommended way of doing it:
using(buffer)
_binaryFormatter.Serialize(buffer, bObj);
There is a great example on how to do this in the MSDN documentation:
CryptoStream MSDN it's in the "Examples" section.
The procedure is basically this:
create cryptostream (empty stream)
write contents to cryptostream (encrypt)
save cryptostream to file
create cryptostream from file contents
read from cryptostream (decrypt)

Categories

Resources