Decrypting byte array with Rijndael - lost Bytes - c#

I am writing a encrypted (Rijndael) byte array in a .txt file.
When I read it out, I get a byte[48]. As soon as i decrypt it, I get a byte[32].
Why am I losing bytes here? If I write the result in the Console, it also cuts at a specific point.
static void ShowEntries()
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
path = path + #"\SafePass\";
byte[] file = File.ReadAllBytes(path + #"\crypt.txt");
using (MemoryStream memory = new MemoryStream(file))
{
using (BinaryReader binary = new BinaryReader(memory))
{
byte[] result = binary.ReadBytes(file.Length);
byte[] plainText = new byte[48];
plainText = Decrypt(result);
string SplainText = Converter(plainText);
Console.WriteLine(SplainText);
}
}
}
static string Converter(byte[] data)
{
string base64 = Convert.ToBase64String(data);
return base64;
}
static byte[] Decrypt(byte[] encryptedByte)
{
{
string password = #"mykey123"; // Your Key Here
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
MemoryStream mem = new MemoryStream();
RijndaelManaged RMCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(mem,
RMCrypto.CreateDecryptor(key, key),
CryptoStreamMode.Write);
cs.Write(encryptedByte, 0, encryptedByte.Length);
byte[] cipherText = null;
cipherText = mem.ToArray();
cs.Close();
return cipherText;
}
}

Assuming that your input data (i.e. what you're encrypting) is 32 bytes long, what's happening is that the encrypted data is being padded, which means that extra redundant information is added to the encrypted data.
In .NET, the default padding mode for symmetrical algorithms like Rijndael is PKCS #7.
I think that if you look at the extra data in the encrypted array all the extra values will be 16 (32 bytes input, next block is at 48, padding is the difference: 48-32=16).
Note that the padded bytes will be removed upon decryption, provided that the same padding mode is used for decryption as encryption. It's not going to affect your data.
But if you really want, you can set the padding mode to None, or one of the other values mentioned on MSDN.
Here's a similar answer to a similar question that you can also refer to.

Related

Invalid padding error when using AesCryptoServiceProvider in C#

I've written a simple encryp/decrypt method in c# which uses the AES alg. When I try to encrypt and then decrypt a string with certain lengths like 4 or 7 characters, it works fine, with other lengths however It says that the padding is invalid and cannot be removed.
public static string Decrypt(string text)
{
Aes a = System.Security.Cryptography.AesCryptoServiceProvider.Create();
a.Padding = PaddingMode.PKCS7;
a.Key = Convert.FromBase64String("UDlArN63HCk15fHBski/zvaWiMZJi+jR1BADvVgenCU=");
a.IV = Convert.FromBase64String("xZG/eLY8eq0mQhUXvKbUDQ==");
var dc = a.CreateDecryptor();
byte[] encryptedBytes = Encoding.Unicode.GetBytes(text);
byte[] decryptedBytes = dc.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.Unicode.GetString(decryptedBytes);
}
public static string Encrypt(string text)
{
Aes a = System.Security.Cryptography.AesCryptoServiceProvider.Create();
a.Padding = PaddingMode.PKCS7;
a.Key = Convert.FromBase64String("UDlArN63HCk15fHBski/zvaWiMZJi+jR1BADvVgenCU=");
a.IV = Convert.FromBase64String("xZG/eLY8eq0mQhUXvKbUDQ==");
var dc = a.CreateEncryptor();
byte[] decryptedBytes = Encoding.Unicode.GetBytes(text);
byte[] encryptedBytes = dc.TransformFinalBlock(decryptedBytes, 0, decryptedBytes.Length);
return Encoding.Unicode.GetString(encryptedBytes);
}
Ciphertexts are binary data which might contain bytes that are not printable. If try to encode the byte array as a Unicode string, you will lose some bytes. It will be impossible to recover them during decryption.
If you actually want to handle the ciphertext as a string, you need to convert it into a textual representation like Base 64 or Hex.
// encryption
return Convert.ToBase64String(decryptedBytes);
// decryption
byte[] decryptedBytes = Convert.FromBase64String(text);

Decrypt string using AES/CBC/NoPadding algorithm

I want to decrypt an Encrypted Sting using AES/CBC/Nopadding in c# Windows Phone 8 application. My string is in file of IsolatedSorage. I pasted the string HERE which is junk.
From this Article I am using AesManaged class to decrypt.
But how to set padding to NoPadding because by default the padding set to PKCS7 from here.
string fileName = "titlepage.xhtml";
if (fileStorage.FileExists(fileName))
{
IsolatedStorageFileStream someStream = fileStorage.OpenFile(fileName, System.IO.FileMode.Open, FileAccess.Read);
using (StreamReader reader = new StreamReader(someStream))
{
str1 = reader.ReadToEnd();
MessageBox.Show(str1);
try
{
string text = Decrypt(str1, "****************", "****************");
MessageBox.Show(text);
}
catch (CryptographicException cryptEx)
{
MessageBox.Show(cryptEx.Message, "Encryption Error", MessageBoxButton.OK);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "General Error", MessageBoxButton.OK);
}
}
}
public string Decrypt(string dataToDecrypt, string password, string salt)
{
AesManaged aes = null;
MemoryStream memoryStream = null;
try
{
//Generate a Key based on a Password and HMACSHA1 pseudo-random number generator
//Salt must be at least 8 bytes long
//Use an iteration count of at least 1000
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt), 10000);
//Create AES algorithm
aes = new AesManaged();
//Key derived from byte array with 32 pseudo-random key bytes
aes.Key = rfc2898.GetBytes(32);
//IV derived from byte array with 16 pseudo-random key bytes
aes.IV = rfc2898.GetBytes(16);
//Create Memory and Crypto Streams
memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Write);
byte[] data = Convert.FromBase64String(dataToDecrypt);
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
//Return Decrypted String
byte[] decryptBytes = memoryStream.ToArray();
//Dispose
if (cryptoStream != null)
cryptoStream.Dispose();
//Retval
return Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);
}
finally
{
if (memoryStream != null)
memoryStream.Dispose();
if (aes != null)
aes.Clear();
}
}
Edit 1:
When I am decrypting my Encrypted string in thins line
byte[] data = Convert.FromBase64String(dataToDecrypt);
Moving to Finally block and getting exception of The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters in decrypted string.
It is bit of confuse on this which is supported class to Decrypt in windows phone.
If I am completely wrong suggest me url of article regarding algorithm in Windows Phone
Edit 2:
As Below answer suggested " I am getting cyperText as bytes it is fine in decryption side. But it is giving an exception with the description
[Cryptography_SSD_InvalidDataSize]
Arguments:
Debugging resource strings are unavailable. Often the key and arguments provide
sufficient information to diagnose the problem
I believe that problem is IV[salt key] or setting padding to AesManged.
But I can't change padding property to AesManaged in Windows Phone.
By default padding to AesManged is PKCS7. I want to change to NoPadding. Because my cyperText is encrypted using AES/CBC/NoPadding algorithm "
If I understand the problem, you have data that is already encrypted in AES CBC mode, with no padding. But on the phone where you want to decrypt the data, the only option you have is PKCS#7 padding.
Well, you are in luck! You can decrypt the ciphertext using PKCS#7 padding. All you need to do is add the padding to the ciphertext, on the phone, and then decrypt it.
To add padding after the fact, you will encrypt a small bit of data and append it to the ciphertext. Then, you decrypt the modified ciphertext, and take that small bit of data off, and you have the original plaintext.
Here is how you do it:
Take a ciphertext on the phone. This is a multiple of 16 bytes, even if there is no padding. There is no other possibility -- AES ciphertext is always a multiple of 16 bytes.
Take the LAST 16 bytes of the ciphertext aside, and set that as the IV of your AES ENCRYPT. (Encrypt, not decrypt.) Use the same key as you are going to use to decrypt later.
Now encrypt something smaller than 16 bytes, for example, the character '$'. The phone is going to add PKCS#7 padding to this.
Append the resulting 16-bytes of ciphertext to the original ciphertext from step 1, and you now have a properly PKCS#7-padded ciphertext which includes the original plaintext plus the added '$'.
Use the original IV, and the same key, and now DECRYPT this combined ciphertext. You can now remove the '$' that will appear at the end of your plaintext (or whatever you added in step 3.)
When the small bit is encrypted with the last 16-bytes of the original ciphertext, you are actually extending the ciphertext in true AES CBC mode, and you happen to be doing that with PKCS#7 padding, so you can now decrypt the whole thing and take the small bit off. You will have the original plaintext which had no padding.
I thought this would be interesting to show in code:
var rfc2898 = new Rfc2898DeriveBytes("password", new byte[8]);
using (var aes = new AesManaged())
{
aes.Key = rfc2898.GetBytes(32);
aes.IV = rfc2898.GetBytes(16);
var originalIV = aes.IV; // keep a copy
// Prepare sample plaintext that has no padding
aes.Padding = PaddingMode.None;
var plaintext = Encoding.UTF8.GetBytes("this plaintext has 32 characters");
byte[] ciphertext;
using (var encryptor = aes.CreateEncryptor())
{
ciphertext = encryptor.TransformFinalBlock(plaintext, 0, plaintext.Length);
Console.WriteLine("ciphertext: " + BitConverter.ToString(ciphertext));
}
// From this point on we do everything with PKCS#7 padding
aes.Padding = PaddingMode.PKCS7;
// This won't decrypt -- wrong padding
try
{
using (var decryptor = aes.CreateDecryptor())
{
var oops = decryptor.TransformFinalBlock(ciphertext, 0, ciphertext.Length);
}
}
catch (Exception e)
{
Console.WriteLine("caught: " + e.Message);
}
// Last block of ciphertext is used as IV to encrypt a little bit more
var lastBlock = new byte[16];
var modifiedCiphertext = new byte[ciphertext.Length + 16];
Array.Copy(ciphertext, ciphertext.Length - 16, lastBlock, 0, 16);
aes.IV = lastBlock;
using (var encryptor = aes.CreateEncryptor())
{
var dummy = Encoding.UTF8.GetBytes("$");
var padded = encryptor.TransformFinalBlock(dummy, 0, dummy.Length);
// Set modifiedCiphertext = ciphertext + padded
Array.Copy(ciphertext, modifiedCiphertext, ciphertext.Length);
Array.Copy(padded, 0, modifiedCiphertext, ciphertext.Length, padded.Length);
Console.WriteLine("modified ciphertext: " + BitConverter.ToString(modifiedCiphertext));
}
// Put back the original IV, and now we can decrypt...
aes.IV = originalIV;
using (var decryptor = aes.CreateDecryptor())
{
var recovered = decryptor.TransformFinalBlock(modifiedCiphertext, 0, modifiedCiphertext.Length);
var str = Encoding.UTF8.GetString(recovered);
Console.WriteLine(str);
// Now you can remove the '$' from the end
}
}
The string you linked to is not Base-64. It looks as if it is raw encrypted bytes, interpreted as characters. Either work on the encryption side to output a Base-64 string encoding of the raw bytes or else work on the decryption side to read the cyphertext as raw bytes, not as text, and forget about removing the Base-64.
Generally better to work on the encryption side since passing Base-64 text is a lot less error-prone than passing raw bytes.

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.

Error on encryption and decryption.Couldn't find the cause of exceptions

I have following two methods.
1st method
//SymmetricEncryting
private byte[] SymmetricEncrypt()
{
try
{
//Get Byte Value
byte[] x= Encoding.Default.GetBytes("Test");
byte [] y;
//Create Symmetric Key Encription
RijndaelManaged rijndaelManaged = new RijndaelManaged();
//GetSymmetricPublicKey
_symmetricPublicKey = rijndaelManaged.Key;
//Get Symmetric Public IV
_symmetricPublicIv = rijndaelManaged.IV;
using (MemoryStream memoryStream = new MemoryStream(x))
{
//Start EncriptionProcess
var cryptoStream = new CryptoStream(memoryStream,
rijndaelManaged.CreateEncryptor
(_symmetricPublicKey,
_symmetricPublicIv),
CryptoStreamMode.Write);
cryptoStream.Write(x, 0, x.Length);
// Complete the encryption process
//cryptoStream.FlushFinalBlock();
y= memoryStream.ToArray();
}
return y;
}
catch (Exception)
{
throw;
}
}
2nd method
private string Decrypt(
byte[] y,
byte[] symmetricPublicKey,
byte[] symmtricPublicIv)
{
try
{
//Create the Key Container
CspParameters cspParameters = new CspParameters();
//Get the AsyPrivate and Public key from the Container
cspParameters.KeyContainerName = "Keys";
var rsaCryptoServiceProvider = new RSACryptoServiceProvider(cspParameters);
//Decrypt and get the Symmetric Public key
var decryptedSymmetricPubk = rsaCryptoServiceProvider.Decrypt(symmetricPublicKey, false);
//Decrypt and get the Symmetric Public IV
var decryptedSymmetricPubIv = rsaCryptoServiceProvider.Decrypt(symmtricPublicIv, false);
//Create RijndaelManaged object to do the Symmtric dycrption
RijndaelManaged rijndaelManaged = new RijndaelManaged();
//Create cryptostream using decrypted symmetric Public Key and IV
ICryptoTransform iCryptoTransform = rijndaelManaged.CreateDecryptor(decryptedSymmetricPubk,
decryptedSymmetricPubIv);
//Create a memory stream
using (MemoryStream memoryStream = new MemoryStream(y))
{
var cryptoStream = new CryptoStream(memoryStream, iCryptoTransform, CryptoStreamMode.Read);
byte[] z= new byte[y.Length];
cryptoStream.Read(z, 0, z.Length);
//cryptoStream.FlushFinalBlock();
//Convert byte array to string
var x= System.Text.Encoding.Default.GetString(z);
return x;
}
}
catch (Exception)
{
throw;
}
As you see in the code i am trying to encrypt a string using symmetric encryption.I encrypt the symmetric public key and Iv by using the asymmetric public key which i have already created.Then i am trying to decrypt the encrypted string .
Problem 1
What is the purpose of having cryptoStream.FlushFinalBlock(); on both encryption and decryption.As i learned from msdn it will end the processes running on the cyptostream
Problem 2
If i uncomment the line cryptoStream.FlushFinalBlock(); it throws an exception
"Memory stream is not expandable.". But if i comment the line it will work fine and return a byte array.
Problem 3
However the second method throws an exception "system.security.cryptography.cryptographicexception length of the data to decrypt is invalid ,on the execution of line cryptoStream.Read(z, 0, z.Length);
I couldn't find the actual cause of these errors on my debugging .Also i did some search on Google.But unfortunately i couldn't find any solution.Can any one please explain the answer?
You are encrypting using PKCS-padding (this is the default). AES/Rijndael is a block-cipher, which means that it only can encrypt blocks of 16 bytes at a time. To allow block-cipher to encrypt data of arbitrary sizes we use a padding algorithm. PKCS-padding works by adding 1-16 bytes at the end when encrypting and removing them when decrypting. The length of the padding is encoded in the padding itself.
You need the FlushFinalBlock when encrypting to let the CryptoStream know that there is no more incoming data and it should add the padding. It is not necessary and should not be used when you are using the CryptoStream in Read-mode.
The first exception come because you are using the plaintext-array as a backing store for the MemoryStream. Because of the padding the encryption will be larger than the plaintext.
The second exception is because you removed the FlushFinalBlock statement and because the MemoryStream is not allowed to resize to make an array of the correct length. The encrypted data should always be a multiple of 16 bytes, but since the MemoryStream will reuse x, y will have the same length as x, which is not always a valid length.
The solution is:
Use FlushFinalBlock in SymmetricEncrypt.
Replace using (MemoryStream memoryStream = new MemoryStream(x)) and using (MemoryStream memoryStream = new MemoryStream(y)) with using (MemoryStream memoryStream = new MemoryStream()). This will allow the MemoryStreams to resize freely.
Oddly, it works for me to just do a write operation when de-crypting as well. Something like:
var decryptMemoryStream = new MemoryStream();
var decryptStream = new CryptoStream(decryptMemoryStream, iCryptoTransform , CryptoStreamMode.Write);
//write the unencrypted data array to the stream
decryptStream.Write(y, 0, y.Length);
decryptStream.Flush();
decryptStream.Close();
var decryptedData = decryptMemoryStream.ToArray();

Rijndael padding or length is invalid

I am trying to encrypt/decrypt a string using eith Rijndael or Aes and the code below.
public class Crypto
{
private const string defaultVector = "asdfg123456789";
private const CipherMode cipherMode = CipherMode.CBC;
//Have tried PaddingMode.ISO10126, PaddingMode.None, and PaddingMode.PKCS7
private const PaddingMode paddingMode = PaddingMode.ISO10126;
private const int iterations = 2;
private static Rijndael GetCrypto(string passphrase)
{
var crypt = Rijndael.Create();
crypt.Mode = cipherMode;
crypt.Padding = paddingMode;
crypt.BlockSize = 256;
crypt.KeySize = 256;
crypt.Key =
new Rfc2898DeriveBytes(passphrase, Encoding.Unicode.GetBytes(defaultVector), iterations).GetBytes(32);
crypt.IV = new Rfc2898DeriveBytes(passphrase, Encoding.Unicode.GetBytes(defaultVector), iterations).GetBytes(32);
return crypt;
}
public static string Encrypt(string plainText, string passphrase)
{
byte[] clearData = Encoding.Unicode.GetBytes(plainText);
byte[] encryptedData;
var crypt = GetCrypto(passphrase);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearData, 0, clearData.Length);
//cs.FlushFinalBlock(); //Have tried this active and commented with no change.
}
encryptedData = ms.ToArray();
}
//Changed per Xint0's answer.
return Convert.ToBase64String(encryptedData);
}
public static string Decrypt(string cipherText, string passphrase)
{
//Changed per Xint0's answer.
byte[] encryptedData = Convert.FromBase64String(cipherText);
byte[] clearData;
var crypt = GetCrypto(passphrase);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, crypt.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(encryptedData, 0, encryptedData.Length);
//I have tried adding a cs.FlushFinalBlock(); here as well.
}
clearData = ms.ToArray();
}
return Encoding.Unicode.GetString(clearData);
}
}
//Edits: I have changed over the Unicode calls to Convert.ToBase64String per Xint0's answer below.
On the cs.Write in Decrypt method, I am getting the error that "Padding is invalid and cannot be removed."
I have tried setting the padding to PaddingMode.None but I get "Length of the data to encrypt is invalid." on the cs.Write in the Encrypt method.
I've looked at these and nothing they've said seems to work.
Padding is invalid and cannot be removed
Padding is invalid and cannot be removed?
Stack trace shows System.Security.CryptographicException is coming from RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast).
I have spend a lot of my time for finding what was causing CryptographicException and I was googling too including Stackoverflow.
It was a stupid mistake (as often when programming with copy-paste) as follow:
It was throwing on method FlushFinalBlock() from instance of CryptoStream.
Look at WRONG code:
CryptoStream cs = new CryptoStream(ms, rj.CreateDecryptor(rj.Key, rj.IV), CryptoStreamMode.Write);
I used it to encrypt so you can see CryptoStreamMode.Write but in the same instruction I was creating decryptor instead of encryptor (see second parameter in the constructor).
Be careful and check it to avoid wasting your precious time ;)
Regards
Bronek
I see two problems:
You are not flushing and closing the streams before calling ms.ToArray(). Change it to:
...
using (var cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearData, 0, clearData.Length);
cs.FlushFinalBlock();
cs.Close();
}
ms.Close();
encryptedData = ms.ToArray();
...
In Encrypt the resulting byte array encryptedData is NOT a Unicode string, yet you are using a Unicode encoder to get a string from the byte array. Instead of that use System.Convert.ToBase64String() in Encrypt and System.Convert.FromBase64String() in Decrypt.
In Encrypt do:
return System.Convert.ToBase64String(encryptedData);
In Decrypt do:
byte[] encryptedData = System.Convert.FromBase64String(cipherText);
EDIT
The biggest problem is the return value of Encrypt. The result of encrypting the byte representation of a Unicode string is NOT a byte representation of a Unicode string. You should not use the value of encryptedData with Encoding.Unicode.GetString() to get a string representation of the encrypted data. Use System.Convert.ToBase64String() to get a string representation of the encrypted data. Please see the Remarks section in the Encoding Class MSDN Documentation.
EDIT 2
Note that Rijndael is not exactly AES, if you are interoperating with AES the block size should always be 128-bits, independent of the key size. For details you can read about it here.
I had a similar problem, the issue in decrypt method was initializing an empty memory stream. when it worked when I initialized it with the cipher text byte array like this:
MemoryStream ms = new MemoryStream(cipherText);

Categories