Decryption of file missing ~10 characters from ending - c#

I've written Encryption/Decryption methods using the RC2CryptoServiceProvider in C# and for some reason, I cannot get my decryptor to decrypt the final few bytes. The file seems to just cut off. My encryption method looks like:
public static byte[] EncryptString(byte[] input, string password)
{
PasswordDeriveBytes pderiver = new PasswordDeriveBytes(password, null);
byte[] ivZeros = new byte[8];
byte[] pbeKey = pderiver.CryptDeriveKey("RC2", "MD5", 128, ivZeros);
RC2CryptoServiceProvider RC2 = new RC2CryptoServiceProvider();
byte[] IV = new byte[8];
ICryptoTransform encryptor = RC2.CreateEncryptor(pbeKey, IV);
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
csEncrypt.Write(input, 0, input.Length);
csEncrypt.FlushFinalBlock();
return msEncrypt.ToArray();
}
While my decryption looks like:
public static byte[] DecryptString(byte[] input, string password, int originalSize)
{
PasswordDeriveBytes pderiver = new PasswordDeriveBytes(password, null);
byte[] ivZeros = new byte[8];
byte[] pbeKey = pderiver.CryptDeriveKey("RC2", "MD5", 128, ivZeros);
RC2CryptoServiceProvider RC2 = new RC2CryptoServiceProvider();
byte[] IV = new byte[8];
ICryptoTransform decryptor = RC2.CreateDecryptor(pbeKey, IV);
MemoryStream msDecrypt = new MemoryStream();
CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write);
csDecrypt.Write(input, 0, originalSize);
// csDecrypt.FlushFinalBlock();
char[] decrypted = new char[input.Length];
decrypted = System.Text.Encoding.UTF8.GetChars(msDecrypt.ToArray());
return msDecrypt.ToArray();
}
The char[] decrypted is returning the whole file decrypted, except the file ends with </LudoData> and when decrypting, I only get up to the first < character.
I have been playing with the lengths of things and nothing is changing anything. In my specific case, input is of length 11296, and originalSize is of size 11290. However, decrypted ends up being of size 11280 when decrypting. What gives!

Is there a reason that you have the Flush() commented out? Have you tried fully closing your streams?

Sigh, I fought this battle about a month ago and had a very similar issue, except I was experiencing TOO much on the end. ToArray was my solution.
You're doing some weird stuff here I'm not exactly sure of. You're using cryptostreams when you don't have to, you're keeping track of the original length for some weird reason and you're using deprecated classes. Your issue is probably a combination of padding, incorrect assumptions (evidenced by originalLength) and incorrect handling of streams (which can be tricky). Try this instead:
Encrypt:
var rij = RijndaelManaged.Create();
rij.Mode = CipherMode.CBC;
rij.BlockSize = 256;
rij.KeySize = 256;
rij.Padding = PaddingMode.ISO10126;
var pdb = new Rfc2898DeriveBytes(password,
Encoding.Default.GetBytes("lolwtfbbqsalt" + password));
var enc = rij.CreateEncryptor(pdb.GetBytes(rij.KeySize / 8),
pdb.GetBytes(rij.BlockSize / 8));
return enc.TransformFinalBlock(unencryptedBytes, 0, unencryptedBytes.Length);
Decrypt:
// throws a cryptographic exception if password is wrong
var rij = RijndaelManaged.Create();
rij.Mode = CipherMode.CBC;
rij.BlockSize = 256;
rij.KeySize = 256;
rij.Padding = PaddingMode.ISO10126;
var pdb = new Rfc2898DeriveBytes(password,
Encoding.Default.GetBytes("lolwtfbbqsalt" + password));
var dec = rij.CreateDecryptor(pdb.GetBytes(rij.KeySize / 8),
pdb.GetBytes(rij.BlockSize / 8));
return dec.TransformFinalBlock(encryptedBytes, 0,
encryptedBytes.Length);
Notice the only thing different within these two methods are CreateEncryptor/CreateDecryptor, so you can refactor out lots of duplication. Also notice I get in a byte array and get out a byte array without having to use any streams. Its also a bit more secure than RC2, and would be even more so if the salt were more random.

Related

How to decrypt AES with crypto-js from C#

I am trying to decrypt a value that is encrypted with AES in backend with C#.
The decryption part will happen in the front end with Angular (using crypto-js )
The problem that I am having is that I'm always getting an empty string as the result of the decryption.
I don't know what am I doing wrong. Am I missing some sort of configuration?
My C# code to Encrypt looks like this:
//
EncryptAES("XEMFkT92UtR1VJI8kU8XQJALk98GGEFM", "random text to encrypt");
public static string EncryptAES(string passPhrase, string plainText)
{
byte[] iv = Generate256BitsOfRandomEntropy();
byte[] temp;
byte[] array;
using (Aes aes = Aes.Create())
{
byte[] salt = Generate256BitsOfRandomEntropy();
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(passPhrase, salt, 100);
aes.Key = pdb.GetBytes(32);
aes.KeySize = 256;
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
aes.IV = iv;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream, Encoding.UTF8))
{
streamWriter.Write(plainText);
}
temp = memoryStream.ToArray();
array = salt.Concat(iv).Concat(temp).ToArray();
cryptoStream.Flush();
encryptor.Dispose();
}
}
}
return Convert.ToBase64String(array);
}
//Random byte[] generator
private static byte[] Generate256BitsOfRandomEntropy()
{
var randomBytes = new byte[16];
using (var rngCsp = new RNGCryptoServiceProvider())
{
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
The decryption part in the.ts file is:
//The param "key" will be same as the C# code: XEMFkT92UtR1VJI8kU8XQJALk98GGEFM
//The param "toDecrypt" will the the Base64 returned by the service in C#
decryptAES(key: string, toDecrypt: string) {
var data = Buffer.from(toDecrypt, 'base64');
var salt = data.slice(0, 16); //first 16 bytes to get the salt
var iv = data.slice(16, 32);// next 16 bytes to get the IV
const wordArrayIV = CryptoJS.lib.WordArray.create(Array.from(iv));
const wordArraySalt = CryptoJS.lib.WordArray.create(Array.from(salt))
var keyPBKDF2 = CryptoJS.PBKDF2(key, wordArraySalt, {
keySize: 256 / 32,
iterations: 100
});
var decrypted = CryptoJS.AES.decrypt(toDecrypt, keyPBKDF2,
{
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: wordArrayIV
});
//Return empty string
return decrypted.toString();
}
In the C# code, the key derived with PBKDF2 is not used, but a randomly generated key. This is because when the key size is set, a new key is implicitly generated.
As fix simply remove the setting of the key size, i.e. the line aes.KeySize = 256 (the key size is implicitly set when the key is set).
...
aes.Key = pdb.GetBytes(32);
//aes.KeySize = 256; // Fix: remove
//aes.Padding = PaddingMode.PKCS7; // default
//aes.Mode = CipherMode.CBC; // default
aes.IV = iv;
...
In addition, there are several issues in the CryptoJS code: First, the Buffers are incorrectly converted to WordArrays, so that IV and salt are wrong.
Also, the ciphertext is not taken into account when separating and is furthermore passed incorrectly to AES.decrypt().
And the decrypted data is hex encoded, but should be UTF-8 decoded.
function decryptAES(key, toDecrypt) {
var data = CryptoJS.enc.Base64.parse(toDecrypt);
var wordArraySalt = CryptoJS.lib.WordArray.create(data.words.slice(0, 4)); // Fix: Array -> WordArray conversion
var wordArrayIV = CryptoJS.lib.WordArray.create(data.words.slice(4, 8)); // Fix: Array -> WordArray conversion
var wordArrayCt = CryptoJS.lib.WordArray.create(data.words.slice(8)); // Fix: Consider ciphertext
var keyPBKDF2 = CryptoJS.PBKDF2(key, wordArraySalt, {keySize: 256 / 32, iterations: 100});
var decrypted = CryptoJS.AES.decrypt({ciphertext: wordArrayCt}, keyPBKDF2, {iv: wordArrayIV}); // Fix: Pass ciphertext as CipherParams object
return decrypted.toString(CryptoJS.enc.Utf8); // Fix: UTF-8 decode
}
var decrypted = decryptAES('XEMFkT92UtR1VJI8kU8XQJALk98GGEFM', '4YI4unJecVXvvNQVgBsdUwrr7rlwcImDb7t1LT88UO0w8BdFpOp5PLsu6PRJ+eCeKB01rWdVVrGMLj7tOi3KHg==');
console.log(decrypted);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
Note that the ciphertext in above code was generated with the fixed C# code.
Regarding vulnerabilities: An iteration count of 100 in key derivation with PBKDF2 is generally too small.

Trying to decrypt a string using AES Managed

I am trying to write code to decrypt a string.
I was given an equivalent in python and I am trying to create the same in . NET
Python:
//Initialization vector is just a string of 16 null bytes
iv = '\x00' * 16
//Create new AES object using the key and init vector
aes = AES.new(key, AES.MODE_CBC, iv)
//Decrypt password and remove padding
result = aes.decrypt(myString).rstrip('\x0b\x08\x07')
return result
Here is my attempt:
byte[] iv = new byte[16];
byte[] rawPlaintext = Convert.FromBase64String("MyBase64String");
byte[] key = // Read from common source
using (Aes aes = new AesManaged())
{
aes.Padding = PaddingMode.None;
aes.KeySize = 128; // in bits
aes.Key = new byte[128 / 8]; // 16 bytes for 128 bit encryption
aes.IV = new byte[128 / 8]; // AES needs a 16-byte IV
// Should set Key and IV here. Good approach: derive them from
// a password via Cryptography.Rfc2898DeriveBytes
byte[] cipherText = key;
byte[] plainText = iv;
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(rawPlaintext, 0, rawPlaintext.Length);
}
cipherText = ms.ToArray();
}
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherText, 0, cipherText.Length);
}
plainText = ms.ToArray();
}
string s = System.Text.Encoding.Unicode.GetString(plainText);
Console.WriteLine(s);
}
It doesn't appear to be working for the result is a string of symbols.
Possible issues:
- I see a mode of CBC getting set. I'm not sure where that equivalent setting would be. I've tried to play with the PaddingMode.
- Could my iv byte[] be causing the issue? Is the default null or 0?
EDIT:
- From what I am reading AesManaged uses AES in CBC mode so that should be a non-issue.
Try replacing this:
string s = System.Text.Encoding.Unicode.GetString(plainText);
to:
string s = System.Text.Encoding.UTF8.GetString(plainText);

Creating/Decrypt passwords with Salt/IV

I've been ask to do a task in a project that involves encryption on a windows 8.
The scenario is something like this:
I get a byte[] from a server, the first 16 bytes are the IV, the next 128 are the Salt and the remaining ones are the File itself.
The user then provides a password and with that and the salt i should create a PKCS5 Key with 40 iterations and the key should have 32bytes length.
Right now i've splitted the byte[] in th 3 i require, but i dont know how the rest is done in windows C#.
I've done some work with encryption/decryption, but let me give you the resource I used for AES 256 bit encryption. Hopefully this will give you an idea of how to switch it over to PKCS5, but everything else I'm pretty sure is the same. It's a little lengthy, but let me know if this applies to your situation. I'm curious how much different it would be for PKCS5 instead of AES256.
Edit: Because the code they posted wasn't clear on the iterations, the iterations is controlled by the line var key = Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000); using 1000 iterations.
http://www.codeproject.com/Articles/769741/Csharp-AES-bits-Encryption-Library-with-Salt
Core Encryption Code
using System.Security.Cryptography;
using System.IO;
Encryption
public byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
// Set your salt here, change it to meet your flavor:
// The salt bytes must be at least 8 bytes.
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
}
}
return encryptedBytes;
}
Decryption
public byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
// Set your salt here, change it to meet your flavor:
// The salt bytes must be at least 8 bytes.
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
Getting Randomized Encryption Result with Salt
If we encrypt the same context (i.e. string of "Hello World") for 10 times, the encrypted results will be the same. What if we want the results different from each time it is encrypted?
What I do is appending a random salt bytes in front of the original bytes before encryption, and remove it after decryption.
Example of Appending Randomized Salt Before Encrypting a String
public string Encrypt(string text, string pwd)
{
byte[] originalBytes = Encoding.UTF8.GetBytes(text);
byte[] encryptedBytes = null;
byte[] passwordBytes = Encoding.UTF8.GetBytes(pwd);
// Hash the password with SHA256
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
// Generating salt bytes
byte[] saltBytes = GetRandomBytes();
// Appending salt bytes to original bytes
byte[] bytesToBeEncrypted = new byte[saltBytes.Length + originalBytes.Length];
for (int i = 0; i < saltBytes.Length; i++)
{
bytesToBeEncrypted[i] = saltBytes[i];
}
for (int i = 0; i < originalBytes.Length; i++)
{
bytesToBeEncrypted[i + saltBytes.Length] = originalBytes[i];
}
encryptedBytes = AES_Encrypt(bytesToBeEncrypted, passwordBytes);
return Convert.ToBase64String(encryptedBytes);
}
Example of Removing the Salt after Decryption
public string Decrypt(string decryptedText, string pwd)
{
byte[] bytesToBeDecrypted = Convert.FromBase64String(decryptedText);
byte[] passwordBytes = Encoding.UTF8.GetBytes(pwd);
// Hash the password with SHA256
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
byte[] decryptedBytes = AES_Decrypt(bytesToBeDecrypted, passwordBytes);
// Getting the size of salt
int _saltSize = 4;
// Removing salt bytes, retrieving original bytes
byte[] originalBytes = new byte[decryptedBytes.Length - _saltSize];
for (int i = _saltSize; i < decryptedBytes.Length; i++)
{
originalBytes[i - _saltSize] = decryptedBytes[i];
}
return Encoding.UTF8.GetString(originalBytes);
}
Code for getting random bytes
public byte[] GetRandomBytes()
{
int _saltSize = 4;
byte[] ba = new byte[_saltSize];
RNGCryptoServiceProvider.Create().GetBytes(ba);
return ba;
}
Step 1: Split the incoming data into IV, salt and cyphertext. You say you have done this.
Step 2: Pass the supplied password and the salt from step 1 as inputs to the PKCS5 key generation method, using 40 iterations. There should be a PKCS5 class in your crypto library. The output from this step will be a key.
Step 3: Use the key from step 2 and the IV from step 1 to decrypt the cyphertext from step 1. Use the specified decryption algorithm, probably AES, in the specified mode. Since an IV is supplied then it is likely that CBC mode is intended, so you will probably need to use the AES-CBC mode from your cypher library. Check the problem specification to confirm both algorithm and cypher mode -- I am only guessing here.
If you have a problem with any of these steps, ask here again, showing your code and explaining the errors you are getting.

Decrypted data with usage of TripleDESCryptoServiceProvider has additonal characters

I am facing with problem when decrypting data with usage of TripleDESCryptoServiceProvider. The problem is that decrypted value contains beside of original value some additional, strange characters at the end
Per instance if I provide "rastko" to be encrypted, I will get later with decryption something like this "rastko⥊㮶". For other values it could be different number of 'dummy' characters or in some cases I will get exact value.
Then, I saw that for all encrypted data byte array size is divisible by 8. It looks like any provided data is rounded on value that is divisible by 8. Only in case when original encoded value is divisible by 8, decryption will retrieve appropriate value.
Here are methods that I am using :
public static byte[] EncryptPassword(string password, out byte[] cryptoKey, out byte[] cryptoIV)
{
try
{
UnicodeEncoding unicodeEncoding = new UnicodeEncoding();
byte[] unicodePassword = unicodeEncoding.GetBytes(password);
byte[] encryptedPassword;
using (TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider())
{
tripleDes.Key = GetCryptoKey();
tripleDes.Mode = CipherMode.CBC;
tripleDes.Padding = PaddingMode.PKCS7;
cryptoKey = tripleDes.Key;
cryptoIV = tripleDes.IV;
using (MemoryStream memoryStream = new MemoryStream())
{
ICryptoTransform cryptoTransform = tripleDes.CreateEncryptor();
using (
CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write))
{
cryptoStream.Write(unicodePassword, 0, unicodePassword.Length);
////cryptoStream.FlushFinalBlock();
}
encryptedPassword = memoryStream.ToArray();
}
}
return encryptedPassword;
}
catch (Exception ex)
{
throw new Exception("Password encryption failed !", ex);
}
}
public static string DecryptPassword(byte[] encryptedPassword, byte[] cryptoKey, byte[] cryptoIV)
{
try
{
UnicodeEncoding unicodeEncoding = new UnicodeEncoding();
string readablePassword;
using (TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider())
{
tripleDes.Key = cryptoKey;
tripleDes.IV = cryptoIV;
tripleDes.Mode = CipherMode.CBC;
tripleDes.Padding = PaddingMode.PKCS7;
// Create a new MemoryStream using the passed
// array of encrypted data.
using (MemoryStream memoryStream = new MemoryStream(encryptedPassword))
{
// Create crypto transform that defines the basic operations of cryptographic transformations.
ICryptoTransform cryptoTransform = tripleDes.CreateDecryptor();
// Create a CryptoStream using the MemoryStream and the passed key and initialization vector (IV).
using (CryptoStream decryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write))
{
decryptoStream.Write(encryptedPassword, 0, encryptedPassword.Length);
///decryptoStream.FlushFinalBlock();
}
byte[] decryptedPassword = memoryStream.ToArray();
//Convert the buffer into a string and return it.
readablePassword = unicodeEncoding.GetString(decryptedPassword, 0, decryptedPassword.Length);
}
}
return readablePassword;
}
catch (Exception ex)
{
throw new Exception("Password decryption failed !", ex);
}
}
private static byte[] GetCryptoKey()
{
UnicodeEncoding unicodeEncoding = new UnicodeEncoding();
string plainKey = "rastkoisajev2310982josipasenera153";
byte[] encodedKey = unicodeEncoding.GetBytes(plainKey);
// Prepares 192 bit key
byte[] preparedKey = new byte[24];
Array.Copy(encodedKey, preparedKey, 24);
return preparedKey;
}
Here is sample test invocation :
private static void CryptoTest()
{
string password = "rastko";
byte[] cryptoKey;
byte[] cryptoIV;
byte[] encryptedPassword = Crypto.EncryptPassword(password, out cryptoKey, out cryptoIV);
string decryptedPAssword = Crypto.DecryptPassword(encryptedPassword, cryptoKey, cryptoIV);
}
I have not good experience with security. What I see is that IV vector is 8byte size and as I found it is related to BlockSize, that is 8times greater then IV size. TripleDESCryptoServiceProvider for IV vector is using 8byte value. I can not change this.
Could you please tell me what I have to do or did I wrote something wrongly ?
DES is a 64 bit block cypher. Any text that does not divide cleanly into 64 bit (=8 byte) blocks needs to be padded to make up a whole number of blocks. You need to set padding for encryption and decryption. If you have control of both ends then use PKCS#5 padding to encrypt and decrypt. If you only have control over the decryption end, then ask the encrypting end what padding they are using and expect that.
Note that encrypting a password is normally not the way to go. Use PBKDF2 instead. Don't confuse passwords and keys!
Try to make sure that your CryptoStreams get closed or flushed:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.cryptostream.flushfinalblock.aspx
If you don't then the padding/unpadding will likely not be performed, and you get trash instead.
After detail investigation I have found the solution for my problem.
I have changed a little bit decryption logic.
Instead of this part in DecryptPassword method :
// Create a CryptoStream using the MemoryStream and the passed key and initialization vector (IV).
using (CryptoStream decryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write))
{
decryptoStream.Write(encryptedPassword, 0, encryptedPassword.Length);
///decryptoStream.FlushFinalBlock();
}
byte[] decryptedPassword = memoryStream.ToArray();
//Convert the buffer into a string and return it.
readablePassword = unicodeEncoding.GetString(decryptedPassword, 0, decryptedPassword.Length);
}
I am now using the Read logic from CryptoStream and then I am just removing nullable characters. It is like this now :
// Create a CryptoStream using the MemoryStream and the passed key and initialization vector (IV).
using (CryptoStream decryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Read))
{
// Create buffer to hold the decrypted data.
byte[] fromEncrypt = new byte[encryptedPassword.Length];
decryptoStream.Read(fromEncrypt, 0, fromEncrypt.Length);
//Convert the buffer into a string and return it.
readablePassword = unicodeEncoding.GetString(fromEncrypt);
readablePassword = readablePassword.Replace("\0", string.Empty);
}
This works perfectly for me ! Thank you all for your time.

unable to open xml after decryption 1 byte to many?

I'm trying to encrypt XML, and after decryption I end up with 1 byte too many - probably because of padding. This is my code. How can I change this to make it work?
public byte[] encryptData(byte[] source,string key)
{
byte[] btKeyInBytes = UTF8Encoding.UTF8.GetBytes(key);
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(key, btKeyInBytes);
AesManaged encryptor = new AesManaged();
encryptor.Padding = PaddingMode.Zeros;
using (MemoryStream encryptStream = new MemoryStream())
{
using (CryptoStream encStream = new CryptoStream(encryptStream, encryptor.CreateEncryptor(rfc.GetBytes(16), rfc.GetBytes(16)), CryptoStreamMode.Read))
{
//Read from the input stream, then encrypt and write to the output stream.
encStream.Write(source, 0, source.Length);
encStream.FlushFinalBlock();
encryptor.Clear();
}
encryptStream.Flush();
encryptedSource = encryptStream.ToArray();
}
return encryptedSource;
}
public byte[] decryptData(byte[] source, string key)
{
byte[] encryptedSource = null;
byte[] btKeyInBytes = UTF8Encoding.UTF8.GetBytes(key);
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(key, btKeyInBytes);
AesManaged encryptor = new AesManaged();
encryptor.Padding = PaddingMode.Zeros;
using (MemoryStream encryptStream = new MemoryStream())
{
using (CryptoStream encStream = new CryptoStream(encryptStream, encryptor.CreateDecryptor(rfc.GetBytes(16), rfc.GetBytes(16)), CryptoStreamMode.Write))
{
//Read from the input stream, then encrypt and write to the output stream.
encStream.Write(source, 0, source.Length);
encStream.FlushFinalBlock();
encryptor.Clear();
}
encryptStream.Flush();
encryptedSource = encryptStream.ToArray();
}
return encryptedSource;
}
It seems that the padding gives me 1 extra byte during decryption
If your problem is padding, then PaddingMode.Zeros is about the worst choice, since zeros cannot always be reliably removed. Better to use PKCS7 padding.
It is also possible that the encoding of end-of-line has changed between systems. Some systems use a single byte while other systems use two bytes. You really need to look at exactly what is in the decrypted file, byte by byte, as #Rup suggests.
I got it!
Now let's try to explain.
Let's say I have a file of 927 bytes.
What I do is to read this file and split it in pieces of 656 bytes. This byte array of 656 bytes is being encrypted. The second array will be 271 bytes.
In every block for encryption I used padding. When decrypting, you will not be able to know in which block padding was used because every block now can be divided by 16 (because of the padding in the encryption). Basically I only want padding used for the last block(271).
so this is my new code:
public byte[] encryptData(byte[] source, string key, bool padding)
{
byte[] encryptedSource = null;
byte[] btKeyInBytes = UTF8Encoding.UTF8.GetBytes(key);
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(key, btKeyInBytes);
AesManaged encryptor = new AesManaged();
//encryptor.Mode = CipherMode.CFB;
encryptor.KeySize = 128; // in bits
encryptor.Key = new byte[128 / 8]; // 16 bytes for 128 bit encryption
encryptor.IV = new byte[128 / 8];
if (padding) { encryptor.Padding = PaddingMode.PKCS7; }
else { encryptor.Padding = PaddingMode.None; }
using (MemoryStream encryptStream = new MemoryStream())
{
using (CryptoStream encStream =
new CryptoStream(encryptStream,
encryptor.CreateEncryptor(rfc.GetBytes(16),
rfc.GetBytes(16)),
CryptoStreamMode.Write))
{
//Read from the input stream, then encrypt and write to the output stream.
encStream.Write(source, 0, source.Length);
}
encryptStream.Flush();
encryptedSource = encryptStream.ToArray();
}
return encryptedSource;
}
public byte[] decryptData(byte[] source, string key,bool padding)
{
byte[] encryptedSource = null;
byte[] btKeyInBytes = UTF8Encoding.UTF8.GetBytes(key);
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(key, btKeyInBytes);
AesManaged encryptor = new AesManaged();
encryptor.Key = new byte[128 / 8]; // 16 bytes for 128 bit encryption
encryptor.IV = new byte[128 / 8];
if (padding) { encryptor.Padding = PaddingMode.PKCS7; }
else { encryptor.Padding = PaddingMode.None; }
using (MemoryStream encryptStream = new MemoryStream())
{
using (CryptoStream encStream =
new CryptoStream(encryptStream,
encryptor.CreateDecryptor(rfc.GetBytes(16),
rfc.GetBytes(16)),
CryptoStreamMode.Write))
{
//Read from the input stream, then encrypt and write to the output stream.
encStream.Write(source, 0, source.Length);
}
encryptStream.Flush();
encryptedSource = encryptStream.ToArray();
}
return encryptedSource;
}
I hope this helps!

Categories