AES Encryption and Decryption by the Chunk was resulting wrong output - c#

Hi i am using c# code and trying to encrypt and decrypt a CSV file
which is having lacks of record and 24 columns.
Encypting it by 4 mb chunk by chunk and generated the salt by random. How do i fix this issue.
encrypting the csv files chunk by chunk and decypting it back.I was getting wrong result in the resulting csv. some junk chars were getting after each chunk.
Thanks in Advance.

You write the salt one time at the beginning of the stream, but read it for each chunk.
Change your encrpt method like this:
....
MemoryStream mstream = null;
try {
while ((bytesRead = Infs.Read(chunk, 0, chunkSizeInBytes)) > 0) {
mstream = new MemoryStream();
mstream.Write(salt, 0, salt.Length);
using (var cryptoStream = new CryptoStream(mstream, aesProvider.CreateEncryptor(), CryptoStreamMode.Write)) {
....
or remove the fsCrypt.Read(salt, 0, salt.Length); inside the while loop of the Decrypt method.

Related

Rijndael encrypted text causes length of data to decrypt is invalid error - C#

I have searched online but have not been able to find any solutions to my problem.
I am using previously written methods to encrypt and ecrypt text using the Rijndael class.
I use these functions to encrypt and decrypt usernames and emails for a web application I have been working on.
The encryption/decryption works perfectly, but every once in a while I get this error:
System.Security.Cryptography.CryptographicException: Length of the data to decrypt is invalid.
Currently, I am getting this error with a specific email address and I can't reproduce the error even if I replace some of the letters in the email.
Here are the encryption/decrytpion functions. The IV and Key are defined as read only strings.
static public string Encrypting(string Source)
{
byte[] bytIn = System.Text.ASCIIEncoding.ASCII.GetBytes(Source);
// create a MemoryStream so that the process can be done without I/O files
System.IO.MemoryStream ms = new System.IO.MemoryStream();
byte[] IVBytes = Encoding.ASCII.GetBytes(IV);
byte[] KEYBytes = Encoding.ASCII.GetBytes(KEY);
Rijndael rijndael = Rijndael.Create();
rijndael.IV = IVBytes;
rijndael.Key = KEYBytes;
// create Crypto Stream that transforms a stream using the encryption
CryptoStream cs = new CryptoStream(ms, rijndael.CreateEncryptor(), CryptoStreamMode.Write);
// write out encrypted content into MemoryStream
cs.Write(bytIn, 0, bytIn.Length);
cs.FlushFinalBlock();
// get the output and trim the '\0' bytes
byte[] bytOut = ms.GetBuffer();
int i = 0;
for (i = 0; i < bytOut.Length; i++)
if (bytOut[i] == 0)
break;
// convert into Base64 so that the result can be used in xml
return System.Convert.ToBase64String(bytOut, 0, i);
}
static public string Decrypting(string Source)
{
// convert from Base64 to binary
byte[] bytIn = System.Convert.FromBase64String(Source);
// create a MemoryStream with the input
System.IO.MemoryStream ms = new System.IO.MemoryStream(bytIn, 0, bytIn.Length);
byte[] IVBytes = Encoding.ASCII.GetBytes(IV);
byte[] KEYBytes = Encoding.ASCII.GetBytes(KEY);
Rijndael rijndael = Rijndael.Create();
rijndael.IV = IVBytes;
rijndael.Key = KEYBytes;
// create Crypto Stream that transforms a stream using the decryption
CryptoStream cs = new CryptoStream(ms, rijndael.CreateDecryptor(), CryptoStreamMode.Read);
// read out the result from the Crypto Stream
System.IO.StreamReader sr = new System.IO.StreamReader(cs);
return sr.ReadToEnd();
}
FYI - I am very new to cryptography and security.
Can these functions be fixed to avoid special cases that cause the error, or should I scrap these and use the RijndaelManaged class?
Sites I found that use RijndaelManaged:
SeeSharp
TekEye
The issue is almost certainly nothing to do with Rijndael vs. RijndaelManaged (or any other such implementation), but instead because the encrypted data contains a 0x00, and you are incorrectly assuming that the the ciphertext ends at the first 0x00 byte. Since the ciphertext can legitimately contain any byte value you should instead use the stream's Length property to determine the length of the ciphertext.
Eliminate the section you've commented: "get the output and trim the '\0' bytes" and replace the return ... statement with:
return System.Convert.ToBase64String(ms.GetBuffer(), 0, ms.Length);
It should be noted that there are many other issues with your use of cryptography here, e.g. the use of a key generated directly from the ASCII encoding of a string, and the fact you're using a fixed IV both negatively impact security.
The norm for the error is a padding issue. What version of .NET are you using? It is more common to use the AES classes (AES, or Advanced Encryption Standard, which is Rijndael). There are plenty of AES implementations you can find as samples.
If you need some proof AES is Rijndael: http://en.wikipedia.org/wiki/Advanced_Encryption_Standard

How to start from arbitrary index (offset) in cryptoStream readByte()

I'm using the code bellow to Encrypt and Decrypt a file:
// Encryption
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes("password");
FileStream fsCrypt = new FileStream("cryptFile", FileMode,create);
RijndaelManaged RMCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateEncryptor(key, key),
CryptoStreamMode.Write);
FileStream fsIn = new FileStream("FileName", FileMode.Open);
int data;
while ((data = fsIn.ReadByte()) != -1)
cs.WriteByte((byte)data);
fsIn.Close();
cs.Close();
fsCrypt.Close();
// Decryption
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes("password");
FileStream fsCrypt = new FileStream("filename", FileMode.Open);
RijndaelManaged RMCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateDecryptor(key, key),
CryptoStreamMode.Read);
int data;
while ((data = cs.ReadByte()) != -1)
memorystream.WriteByte((byte)data);
It works well, without any problem!
For some reasons I've added 10 bytes at the first of the encrypted file!
Actually I've created a 10 bytes file (the file size is EXACTLY 10 Bytes), then I've appended the encrypted file to this file.
Note that the 10 bytes file is not encrypted, and is created using simple filestream, and it could be read in notepad.
Now in decryption code, how could I eliminate the first 10 bytes and decrypt remain data in the file?
I've tried to call ReadByte() for 10 times, and then goto the WHILE part and decrypt file, but it doesn't work and I get length invalid exception.
Thanks in advance.
Posting my comment as an answer as requested.
You say
I've tried to call ReadByte() for 10 times, and then goto the WHILE
part and decrypt file, but it doesn't work and I get length invalid
exception.
but you don't say exactly which stream you call ReadByte() 10 times on, and when exactly you call it.
Make sure you're calling it on fsCrypt before you instantiate the new CryptoStream.
Note also that that you can probably just call fsCrypt.Position = 10; or fsCrypt.Seek(10, SeekOrigin.Begin), instead of reading 10 dummy bytes, since FileStream supports seeking.
For example:
byte[] key = Encoding.Unicode.GetBytes("password");
FileStream fsCrypt = File.OpenRead("filename");
fsCrypt.Position = 10; // Skip the 10 useless bytes at the start
RijndaelManaged rijndaelManaged = new RijndaelManaged();
// Disposing CryptoStream will also dispose the FileStream passed to it
using (CryptoStream cryptoStream = new CryptoStream(fsCrypt, rijndaelManaged.CreateDecryptor(key, key), CryptoStreamMode.Read))
{
cryptoStream.CopyTo(memoryStream);
}
As an aside: DO NOT USE THE KEY AS THE IV!
The IV needs to be different every time you encrypt something, but can be public. A common technique is to randomly generate an IV every time you want to encrypt something, and put it as the first N bytes of the encrypted stream. When it comes to decrypting, read the first N bytes of the encrypted stream yourself (before creating the CryptoStream), set that as the IV, open the CryptoStream, and read the rest.

C# AesManaged Exception: Padding is invalid and cannot be removed

I know there is plenty of this questions with answers around but I have spent hours and hours googleing and have tried all suggestions that I have found.
I download a file and I want to store it encrypted in the isolated storage.
This is how I store it:
using (var fs = new IsolatedStorageFileStream(fileName, FileMode.Create, store))
{
byte[] bytesInStream = new byte[args.Result.Length];
args.Result.Read(bytesInStream, 0, bytesInStream.Length);
var aes = new AesManaged
{
Key = GetBytes("aaaaaaaa"),
IV = GetBytes("bbbbbbbb")
};
byte[] encryptedArray;
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cryptoStream.Write(bytesInStream, 0, bytesInStream.Length);
cryptoStream.FlushFinalBlock();
encryptedArray = memoryStream.ToArray();
}
}
fs.Write(encryptedArray, 0, encryptedArray.Length);
fs.Flush();
}
The following code is for reading the file from isolated storage and decrypt it:
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (store.FileExists(fileName))
{
var file = store.OpenFile(fileName, FileMode.Open,FileAccess.Read,FileShare.Read);
var reader = new BinaryReader(file);
var aes = new AesManaged
{
Key = GetBytes("aaaaaaaa"),
IV = GetBytes("bbbbbbbb")
};
byte[] decodedContent;
byte[] encodedContent = reader.ReadBytes(1280);
using (MemoryStream ms = new MemoryStream(encodedAudio))
{
using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Read))
{
BinaryReader r= new BinaryReader(cs);
decodedContent= r.ReadBytes(encodedContent.Length);
}
}
}
When the program reaches this line: decodedContent= r.ReadBytes(encodedContent.Length); I get CryptographicException with the following message: Padding is invalid and cannot be removed.
Can anyone help me with this issue?
You can't decrypt by blocks because silverlight AesManaged always include padding and if you read only a part of encrypted block - decryption class can't find the padding that should be removed. You can decrypt whole data only. Alternatively, you can split the data manually in the encryption part of your algorithm. Hans Passant told you the same, just in a short form ;)
You can decrypt 1,280 bytes at a time, if you decrypt without removing padding until the last block. That is, you have to set the decryptor to not remove padding (i.e. "no padding") on all but the last block.
I.e. when there are N blocks:
for blocks 1 to N-1: decrypt(1280 bytes, no padding)
for block N: decrypt(however many bytes left, padded)
You can also run the entire decryption with "no padding" and strip the padding yourself. The last byte will give you the number of bytes to clip from the end, from 1 to 16.
If you cannot turn off padding-removal on decryption (implied by your comment above), you can still decrypt 1,280 bytes at a time. Just encrypt the blocks individually. They will each get padding, and make it fit 1,280. For example, encrypt 1,279 bytes at a time (each block is given a 1 byte pad.) Encrypting the full 1,280 with padding will give you 1,296 bytes (a multiple of 16 bytes of plaintext is going to get a full 16-byte pad.)
Edit, for the interested:
If you find yourself with a large ciphertext, and you want to decrypt it in blocks, and for some reason your decryption is constrained such that you are forced to use padding mode PKCS#7, you can still decrypt the data a block at a time. It's a bit more expensive -- it will cost you an extra encryption of 16 bytes per block, but at least it is possible.
Take each block of raw ciphertext, and encrypt a little tail of 16 bytes for each block which is correctly padded for that block. Then decrypt the enlarged block, and finally, remove the extra bit of data used to encrypt the padding tail.
You just take the last 16 bytes of the block as your IV, and using the same key, encrypt some small data -- for example a single byte -- padded with PKCS#7. Attach the 16 byte result of the encryption to the block and now decrypt the block + 16 bytes. The padding is removed from the tail 16 bytes, and you can remove the bit of data, and end up with the original block of plaintext. See more in my answer here

Decrypting part of AES stream

I use AES encryption. It's ok when I encrypt and then decrypt whole file. I want to add multiple files to one encrypted. That's where the problem is. Encryption is fine, but decryption causes CryptographicException - bad data length. Is it even possible to decrypt part of file or is it encrypted as whole ? I used one cryptostream and passed there all files I want to encrypt to single file. I am trying to do opposite:
AesManaged aes = AES.InitAes(key, salt);
ICryptoTransform transform = aes.CreateDecryptor(aes.Key, aes.IV);
int defChunkSize = 1024 * 1024 * 50;
using (FileStream source = new FileStream(header.data.filename, FileMode.Open))
{
foreach (CryptHeader.fileStruct file in header.data.files)
{
preparePath(file.filename);
using (FileStream target = new FileStream(file.filename, FileMode.Create))
{
using (CryptoStream cryptoStream = new CryptoStream(target, transform, CryptoStreamMode.Write))
{
long padding = source.Length - header.data.files.Sum(x => x.length);//Just test
int chunkSize = (defChunkSize > (int)file.length) ? (int)file.length : defChunkSize;
byte[] chunkData = new byte[chunkSize];
int bytesRead = 0;
int totalRead = 0;
while (totalRead < file.length)
{
bytesRead = source.Read(chunkData, 0, chunkSize);
if (bytesRead <= 0) break;
totalRead += bytesRead;
cryptoStream.Write(chunkData, 0, bytesRead);
}
chunkData = null;
}
}
}
}
I've done the same few years ago without any problem. The logic I used is the following:
Encryption
define number of files
define array for keeping encrypted sizes
open output stream
seek (forced) to (number of files * 4) + 4 (assuming lengths are integers)
loop for encryption (encrypt- write encrypted data -assigned encrypted size)
seek to 0 (begin)
write number of files
write encrypted size array
close output stream
Decryption
open input stream
read number of files
define-read-fill array with encrypted sizes
loop for decryption (read using known sizes)
close output stream
I hope that this helps.
Short form: "you can't get there from here", it's impossible.
If you look at the description of how AES works you'll see two things.
1 AES uses a block size of 128 bits, so if your files aren't multiples of 8 bytes in length the blocks in the appended part won't line up,
2: AES use uses different keys for each block according to the rijndael key schedule, this is a likely going to be a deal breaker.
If you need to be able to concatenate encrypted files either wrap them so that the joins are visible and the fragments can be individually decrypted (gzip does this when compressing) or use a fixed substitution cypher like rot13
It can be done and it's working. I make table during encryption containing lengths of encrypted files. Than I decrypt exact parts (with padding).

MemoryStream and decrypting text file

I've got a weird issue while trying to decrypt an encrypted text file. Basically the contents of the .txt file is "this is a test :)" , when decrypting the output is "this is a test :", spot the missing ")".
This isn't the case when I decrypt the file a byte at a time (while loop), but when using the code bellow it seems to have the above issue.
private static void DecryptFile(string inputFile, string outputFile, string skey)
{
RijndaelManaged aes = new RijndaelManaged();
try
{
byte[] key = ASCIIEncoding.UTF8.GetBytes(skey);
byte[] file = File.ReadAllBytes(inputFile);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(key, key), CryptoStreamMode.Write))
{
cs.Write(file, 0, file.Length);
File.WriteAllBytes(outputFile, ms.ToArray());
aes.Clear();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
aes.Clear();
}
}
Please excuse the sloppy code, it was merely for testing purposes.
A block-cipher CryptoStream can only encrypt or decrypt content in fixed block sizes. You haven't given it enough content to fill the final block so it's waiting for more. This partial incomplete block is getting lost.
You either need to call FlushFinalBlock on your CryptoStream or fall outside the using so that it automatically closes it. Then your MemoryStream should contain the missing characters.
Note that when decrypting your output will now be rounded up to a full block, i.e. you'll get extra zeros padding the end of your data.

Categories