File ecnryption using DES decrypting garbage - C# - c#

I am trying to write a simple file encrypter in C# using DESCryptoServiceProvider. The file format I am encrypting is .jpg. The encryption appears to look fine, but when I decrypt the encrypted file I get an error message in Windows Photo Viewer.
Here is my code:
public static void Encrypt(string inputFileName, string outputFileName, string key)
{
var inputPath = path + "\\" + inputFileName;
var outputPath = path + "\\" + outputFileName;
try
{
FileStream fsInput = new FileStream(inputPath, FileMode.Open, FileAccess.Read);
FileStream fsEncrypted = new FileStream(outputPath, FileMode.Create, FileAccess.Write);
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(key);
DES.IV = ASCIIEncoding.ASCII.GetBytes(key);
DES.Padding = PaddingMode.None;
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);
Console.WriteLine("file encrypted # {0}", outputFileName);
}
catch(Exception ex)
{
Console.WriteLine("catch in encryption: " + ex.Message + "\n\nclosing...");
}
}
public static void Decrypt(string inputFileName, string outputFileName, string key)
{
var inputPath = path + "\\" + inputFileName;
var outputFileHoler = inputFileName.Substring(0, (outputFileName.IndexOf('.') + 4)); //FIX TO REMOVE REGEX
var outputPath = path + "\\" + outputFileHoler;
Console.WriteLine(outputPath); //TEMP
try
{
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(key);
DES.IV = ASCIIEncoding.ASCII.GetBytes(key);
DES.Padding = PaddingMode.None;
FileStream fsread = new FileStream(inputPath, FileMode.Open, FileAccess.Read);
ICryptoTransform desdecrypt = DES.CreateDecryptor();
CryptoStream cryptostream = new CryptoStream(fsread, desdecrypt, CryptoStreamMode.Read);
StreamWriter fsDecrypted = new StreamWriter(outputPath);
fsDecrypted.Write(new StreamReader(cryptostream).ReadToEnd());
fsDecrypted.Flush();
fsDecrypted.Close();
Console.WriteLine("file decrypted # {0}", outputPath);
}
catch (Exception ex)
{
Console.WriteLine("catch in decryption: " + ex.Message + "\n\nclosing...");
}
}
What am I doing wrong?
PS. completely new to cryptography, please forgive me if it is something simple...

Do NOT attempt to implement crypto yourself unless you are 100% sure that you know what you are doing. Use well-reviewed, high-level(!) libraries.
You are attempting to use DES. DES is broken and insecure due to insufficient key length. Do not use it.
You are using your key instead of a random value as IV. Depending on how the crypto provider works, this either introduces a small vulnerability or makes your encryption 100% worthless because it leaks your key.
You are not using any padding. This will make it impossible to correctly encrypt/decrypt files that do not exactly fit the block size.
You do not show how you obtain your key. Chances are you do so in an insecure manner. Especially given that you use a string to store it.
The comments by CodesInChaos have pointed out quite a few important points. What is breaking your files is probably the StreamReader, the padding, and the lack of stream flushing/closing. However, again, do NOT attempt to write crypto code - it will be insecure even if you get it working.

Related

Decryption providing a padding error

I'm trying to save a serialized object to an encrypted file. This isn't production quality and I am aware of the security risks with the way that I am doing this, but ignoring those I will have a key in a resource (data.Settings.key) that wont change and I have a salt that is also a constant.
My encryption seems to work, but decryption returns me an Exception saying that padding is invalid and cannot be closed when I try to close my CryptoStream.
private static byte[] decrypt(byte[] bytes)
{
var decryptor = algorithm.CreateDecryptor();
using (var sMemoryStream = new MemoryStream())
using (var sCryptoStream = new CryptoStream(sMemoryStream, decryptor, CryptoStreamMode.Write))
{
sCryptoStream.Write(bytes, 0, bytes.Length);
sCryptoStream.Close();
return sMemoryStream.ToArray();
}
}
The algorithm variable is the same one that the encrypt method uses and is built by this method which is called in the classes constructor:
private static SymmetricAlgorithm GetAlgorithm()
{
var algorithm = Rijndael.Create();
// Create key from salt and password in config
var rdb = new Rfc2898DeriveBytes(data.Settings.key, new byte[] {
0x44,0x61,0x79,0x6e,0x65,0x44,0x6f,0x75,0x67,0x61,0x6e
});
algorithm.Padding = PaddingMode.PKCS7;
// Set key and IV from rdb
algorithm.Key = rdb.GetBytes(32);
algorithm.IV = rdb.GetBytes(16);
return algorithm;
}
I've tried changing the padding mode in the algorithm but I can't understand why it's fine with this padding when encrypting, but now when decrypting.
If it helps here is the method that calls the decrypt method:
private static User OpenFile(String sUserName)
{
Console.WriteLine("Opening file...");
using (Stream sFileStream = new FileStream(data.Settings.dir + "data\\accounts\\" + sUserName + ".dat",
FileMode.Open, FileAccess.Read, FileShare.None))
using (Stream sMemoryStream = new MemoryStream())
{
// Read from File to memory stream
sFileStream.CopyTo(sMemoryStream);
// Decrypt data and store in new memory stream
byte[] bytes = new byte[sMemoryStream.Length];
Console.WriteLine("\tb:" + bytes.Length);
bytes = decrypt(bytes);
Console.WriteLine("\ta:" + bytes.Length);
Stream stream = new MemoryStream(bytes);
Console.WriteLine("\ts:" + bytes.Length);
// Deserialise memory stream and return as User object
User user = (User)bfFormatter.Deserialize(stream);
stream.Close();
return user;
}
}

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.

Output is invalid

I have a PHP program that encrypts a PDF file into .xxx file this output is being read by a C# program that decrypts this .xxx file back into PDF file.
My problem is that when I open the file decrypted by C# , the PDF reader tells me that the file is corrupted .. when I encrypt plain text in PHP and decrypt on C# I got the file I encrypted .. so the problem is appearing only in PDF files or in other words it appears in BINARY files
any suggestions ?!
Notes:
In PHP I use mcrypt extension Rijndael algorithm CBC PKCS7 padding (padding is done manually)
In C# I use RijndaelManaged class to encrypt and decrypt data
Edit:
Here is encryption method that I use in PHP:
function encrypt($key, $iv, $text) {
ini_set ( 'memory_limit', '-1' );
$mcrypt_cipher = MCRYPT_RIJNDAEL_256;
$mcrypt_mode = MCRYPT_MODE_CBC;
$text=addpadding($text,mcrypt_get_block_size($mcrypt_cipher,'cbc'));
$encrypted = rtrim ( mcrypt_encrypt ( $mcrypt_cipher, $key, $text, $mcrypt_mode, $iv ), "\0" );
$encrypted = base64_encode ( $encrypted );
return $encrypted;
}
And here is the decryption method in C#:
public static string DecryptString(string message, string KeyString, string IVString)
{
byte[] Key = Encoding.UTF8.GetBytes(KeyString);
byte[] IV = Encoding.UTF8.GetBytes(IVString);
string decrypted = null;
RijndaelManaged rj = new RijndaelManaged();
rj.BlockSize = 256;
rj.Key = Key;
rj.IV = IV;
rj.Mode = CipherMode.CBC;
rj.Padding = PaddingMode.PKCS7;
try
{
MemoryStream ms = new MemoryStream();
//Encoding enc = new UTF8Encoding();
byte[] messageBytes = Convert.FromBase64String(message);
using (CryptoStream cs = new CryptoStream(ms, rj.CreateDecryptor(Key, IV), CryptoStreamMode.Write))
{
//byte[] messageBytes = enc.GetBytes(message);
cs.Write(messageBytes, 0, messageBytes.Length);
cs.Close();
}
byte[] encoded = ms.ToArray();
decrypted = Encoding.UTF8.GetString(encoded);
ms.Close();
}
catch (Exception e)
{
MessageBox.Show("An error occurred:"+ e.Message);
}
finally
{
rj.Clear();
}
return decrypted;
}
and here is how I call the decrypt in C# and how I write output:
string Key = cryptography.MD5("X-Ware" + cryptography.MD5("123"));
string IV = cryptography.MD5("XWare");
string decrypted = cryptography.DecryptString(contents, Key, IV);
string outputFilename = cryptography.MD5(OFD.FileName) + ".tmp";
StreamWriter sw = new StreamWriter("C:\\Windows\\Temp\\" + outputFilename, false, Encoding.UTF8);
BinaryWriter bw = new BinaryWriter(sw.BaseStream, Encoding.UTF8);
//sw.Write(decrypted);
bw.Write(decrypted);
sw.Close();
bw.Close();
I think the problem is that you treat the binary PDF data as text on both the PHP and the C# side.
decrypted = Encoding.UTF8.GetString(encoded);
makes no sense if encoded represents binary data. You should probably skip this step and define your DecryptString() as returning byte[]. And then rename it too.
If you do want it as a string you might have better luck with ASCII or ANSI encoding:
decrypted = Encoding.ASCII.GetString(encoded);
but the error may already be happening on the PHP side, I can't tell.
Additional, I just noted:
StreamWriter sw = new StreamWriter("C:\\Windows\\Temp\\" + outputFilename,
false, Encoding.UTF8);
BinaryWriter bw = new BinaryWriter(sw.BaseStream, Encoding.UTF8);
This is a very over-complicated way to create a BinaryWriter. The Encoding will not be used. And
bw.Write(decrypted);
This will write the string with a length-prefix, that certainly will make your PDF invalid.
When you keep the return of Decrypt as string, use
File.WriteAllText("C:\\Windows\\Temp\\" + outputFilename, decrypted);
And when you return it as byte[] (recommended), use
File.WriteAllBytes("C:\\Windows\\Temp\\" + outputFilename, decrypted);

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.

C# "Bad Data" exception when decrypting encrypted file

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

Categories

Resources