"Bad Data" error and issues with Streams

  • Thread starter Thread starter floppyzedolfin
  • Start date Start date
F

floppyzedolfin

Hello!
I'm actually encoding an encryption / decryption program.
The encryption programes takes a file path in parameter, and encrypts
the contents of the file and stores that into another file.

I'm using AES for it is quick, and RSA to encrypt AES, to transmit AES
keys (it'll run on two separate computers).

Please notice that
- this is my first C# code :)
- this is the first time I use Streams
- I used ASCIIEncoding for byte[] <-> string, but I don't know if it
uses ASCII 128 or ASCII 256 (and it's rather important).

I have the following issues :
- the file encrypted with the AES algorithm is smaller in size than
the original one (ratio is about 1:1.7). Is it possible that the
Streams end too early ?
- a "Bad Data" error is raised when importing RSAParam, in decrypt.

Thanks in advance.


Here's the code.


using System;
using System.Collections.Generic,
using System.Text;
using System.IO;
using System.Security.Cryptography;

namespace Project
{
class EncryptedData
{
// contains the names of the files where encrypted data will be
stored

public string Enc_File
{
get {return enc_file};
set {enc_file = value};
}
string enc_file;

public string Enc_Key
{
get {return enc_key};
set {enc_key = value};
}
string enc_key;

public string Enc_IV
{
get {return enc_IV};
set {enc_IV = value};
}
string enc_IV;
}

class LetsDoIt
{
const int RSA_KEY_SIZE = 4096;

static void Main()
{
try
{
RSACryptoServiceProvider RSACrypto = new
RSACryptoServiceProvider(RSA_KEY_SIZE);

EncryptedData encFiles = new EncryptedData();

encFiles = encrypt("toEncrypt.txt",
RSACrypto.ExportParameters(false));

string decFile = decrypt(encFiles,
RSACrypto.ExportParameters(true));
}
catch (Exception e) { Console.WriteLine("Error in Main: {0}",
e.Message); }
}

static EncryptedData encrypt(string FileToEncrypt, RSAParameters
RSAParam)
{
try
{
// Part 1 : encrypting data
// 1 : create a Rijndael instance.
Rijndael rijndaelAlg = Rijndael.Create();
rijndaelAlg.GenerateKey();
rijndaelAlg.GenerateIV();
ICryptoTransformer rijndaelEncryptor =
rijndael.CreateEncryptor(rijndaelAlg.Key, rijndaelAlg.IV);

// 2 : open and read file
FileStream fstf = File.Open(FileToEncrypt, FileMode.OpenOrCreate);
StreamReader strf = new StreamReader(fst);
string file_contents = str.ReadToEnd();

EncryptedData encryptedFiles = new EncryptedData();
encryptedFiles.Enc_File = "encryptedFile";

// 3 : creating a new file, and writing encrypted data into it
FileStream fstef = new FileSream(encryptedFiles.Enc_File,
FileMode.OpenOrCreate);
CryptoStream cstf = new CryptoStream(fstef, rijndaelEncryptor,
CryptoStreamMode.Write);
StreamWriter stw = new StreamWriter(cstf);
stw.Write(file_contents);

// 4 : closing streams
stw.Close();
cstf.Close();
fstef.Close();
strf.Close();
fstf.Close();

// Part 2 : encrypting keys
// 1 : create a RSA instance, and import the public keys
RSACryptoServiceProvider RSA = new
RSACryptoServiceProvider(RSA_KEY_SIZE);
RSA.ImportParameters(RSAParam);

// 2 : encrypt Rijndael keys
byte[] EncKey_byte = RSA.Encrypt(rijndaelAlg.Key, false);
byte[] EncIV_byte = RSA.Encrypt(rijndaelAlg.IV, false);

ASCIIEncoding ByteConverter = new ASCIIEncoding();
string EncKey_string = ByteConverter.GetString(EncKey_byte);
string EncIV_string = ByteConverter.GetString(EncIV_byte);

// 3 : finally, writing encrypted keys into files
encryptedFiles.Enc_Key = "encryptedKey";
encryptedFiles.Enc_IV = "encryptedIV";
FileStream fstK = new FileStream(encryptedFiles.Enc_Key,
FileMode.OpenOrCreate);
FileStream fstI = new FileStream(encryptedFiles.Enc_IV,
FileMode.OpenOrCreate);
StreamWriter stwK = new StreamWriter(fstK);
StreamWriter stwI = new StreamWriter(fstI);
stwK.Write(EncKey_string);
stwI.Write(EncIV_string);

// 4 : closing streams
stwK.Close();
stwI.Close();
fstK.Close();
fstI.Close();

return encryptedFiles;
}
catch (Exception e) { Console.WriteLine("Error in encrypt: {0}",
e.Message); }
}

static string decrypt(EncryptedData encData, RSAParameters RSAParam)
{
try
{
// 1 : get files' contents
FileStream fstK = File.Open(encData.Enc_Key, FileMode.Open);
FileStream fstI = File.Open(encData.Enc_I, FileMode.Open);
StreamReader stwK = new StreamReader(fstK);
StreamReader stwI = new StreamReader(fstI);

string EncKey_string = stwK.ReadToEnd();
string EncIV_Key = stwI.ReadToEnd();

ASCIIEncoding ByteConverter = new ASCIIEncoding();
byte[] EncKey_byte = ByteConverter.GetBytes(EncKey_string);
byte[] EncIV_byte = ByteConverter.GetBytes(EncIV_string);

// 2 : decrypt keys with RSA algorithm
RSACryptoServiceProvider RSA = RSACryptoServiceProvider();
RSA.ImportParameters(RSAParam);

byte[] Key_byte = RSA.Decrypt(EncKey_byte, false);
byte[] IV_byte = RSA.Decrypt(EncIV_byte, false);

// 3 : decrypt the file using the rijndael keys
Rijndael rijndaelAlg = Rijndael.Create();
ICryptoTransform rijndaelDecryptor =
rijndaelAlg.CreateDecryptor(Key_byte, IV_byte);

FileStream fstef = File.Open(encData.Enc_File, FileMode.Open);
CryptoStream cstef = new CryptoStream(fstef, rijndaelDecryptor,
CryptoStreamMode.Read);
StreamReader stref = new StreamReader(cstef);

// 4 : writing retrieved contents into file
string contents;
string DecFile = "DecFile.txt";
FileStream fstf = File.Open(DecFile, FileMode.OpenOrCreate);
StreamWriter stwf = new StreamWriter(fstf);

contents = stref.ReadToEnd();
stwf.Write(contents);

// 5 : closing streams
stwf.Close();
fstf.Close();
stref.Close();
cstef.Close();
stwK.Close();
stwI.Close();
fstK.Close();
fstI.Close();

return DecFile;
}
catch (Exception e) { Console.WriteLine("Error in decrypt: {0}",
e.Message); }
}
}
}
 
floppyzedolfin said:
- this is my first C# code :)
- this is the first time I use Streams
- I used ASCIIEncoding for byte[] <-> string, but I don't know if it
uses ASCII 128 or ASCII 256 (and it's rather important).

I have not examined in detail the whole of your code, but I can tell
you that this is a no-no. Every time that you are using cryptographic keys
or you are manipulating encrypted data, you are working arrays of bytes, and
it is critical that you preserve each and everyone of the bits in those
bytes. This means that you cannot use any kind of Encoding. Specifically,
ASCIIEncoding uses 7-bit ASCII, so you are definitely going to lose
information, but even if you use another Encoding, it is going to perform
some conversion on the characters and you will be losing bits.
This means that you should avoid converting any of your arrays of bytes
into strings (unless you use something more sophisticated such as Base64
encoding). Which in turn means that you should not be using StreamReaders or
StreamWriters, which read and write strings. Instead, use FileStreams, which
take arrays of bytes as the data to read or write.
 
Instead, use FileStreams, which
take arrays of bytes as the data to read or write.

Yep, that sounds good.

I'll give more information later (for those who may be interested).
 
Well, files do have the same size by now, but I get some "out of
bonds" errors when decrypting.
And sometimes, "Bad Data" :(
 
Back
Top