I'm not sure what I'm doing wrong, the encryption it seems to work but when you get to the decryption says bad data when trying to deserialize it, not sure what I'm doing wrong. I'm new at doing encryption so if it's something really simple I'm sorry.
public byte[] Serialize(object obj, string key)
{
byte[] returnBytes;
using (MemoryStream memory = new MemoryStream())
{
UTF8Encoding UTF8 = new UTF8Encoding();
TripleDESCryptoServiceProvider crypt = new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider();
byte[] pass = provider.ComputeHash(UTF8.GetBytes(key));
crypt.Key = pass;
crypt.Mode = CipherMode.ECB;
crypt.Padding = PaddingMode.PKCS7;
using (CryptoStream stream = new CryptoStream(memory, crypt.CreateEncryptor(), CryptoStreamMode.Write))
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, obj);
stream.Close();
memory.Close();
}
returnBytes = memory.ToArray();
}
return returnBytes;
}
public object Deserialize(byte[] inBytes, string key)
{
object returnObj;
using (MemoryStream memory = new MemoryStream())
{
UTF8Encoding UTF8 = new UTF8Encoding();
TripleDESCryptoServiceProvider crypt = new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider();
byte[] pass = provider.ComputeHash(UTF8.GetBytes(key));
crypt.Key = pass;
crypt.Mode = CipherMode.ECB;
crypt.Padding = PaddingMode.PKCS7;
using (CryptoStream stream = new CryptoStream(memory, crypt.CreateDecryptor(), CryptoStreamMode.Read))
{
BinaryFormatter formatter = new BinaryFormatter();
returnObj = formatter.Deserialize(stream);
stream.Close();
memory.Close();
}
return returnObj;
}
}
This code i did a while back works on strings
public string encrypt(string message, string password)
{
byte[] result;
UTF8Encoding UTF8 = new UTF8Encoding();
MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider();
byte[] key = provider.ComputeHash(UTF8.GetBytes(password));
TripleDESCryptoServiceProvider algorithm = new TripleDESCryptoServiceProvider();
algorithm.Key = key;
algorithm.Mode = CipherMode.ECB;
algorithm.Padding = PaddingMode.PKCS7;
byte[] data = UTF8.GetBytes(message);
try
{
ICryptoTransform encryptor = algorithm.CreateEncryptor();
result = encryptor.TransformFinalBlock(data, 0, data.Length);
}
finally
{
algorithm.Clear();
provider.Clear();
}
return Convert.ToBase64String(result);
}
public string decrypt(string message, string passsword)
{
byte[] result;
UTF8Encoding UTF8 = new UTF8Encoding();
MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider();
byte[] key = provider.ComputeHash(UTF8.GetBytes(passsword));
TripleDESCryptoServiceProvider algorithm = new TripleDESCryptoServiceProvider();
algorithm.Key = key;
algorithm.Mode = CipherMode.ECB;
algorithm.Padding = PaddingMode.PKCS7;
byte[] data = Convert.FromBase64String(message);
try
{
ICryptoTransform decryptor = algorithm.CreateDecryptor();
result = decryptor.TransformFinalBlock(data, 0, data.Length);
}
finally
{
algorithm.Clear();
provider.Clear();
}
return UTF8.GetString(result);
}
You're not setting the IV property of crypt, so it's starting off as a random value each time. You need to set it to the same value when decrypting as when encrypting - like a salt for hashing. EDIT: Given the way ECB works, it looks like the IV may be ignored, which is why your previous code worked without storing it.
EDIT: While the IV part is certainly required for non-ECB, it's not enough. I'm not sure what the rest of the problem is, although:
The ECB cipher mode isn't recommended - any reason for using it?
You may well end up running into problems due to padding; I don't know if BinaryFormatter handles that for you automatically, but it's worth looking into.
EDIT: Doh - I've worked out the bigger problem; you should indeed be using inBytes, as per Elian's comment. Currently you're completely ignoring the cipher-text - that's got no chance of working!
Here's a complete program showing the whole thing hanging together:
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using System.Runtime.Serialization.Formatters.Binary;
class Test
{
static void Main()
{
byte[] data = Serialize("Some arbitrary test data", "pass");
object x = Deserialize(data, "pass");
Console.WriteLine(x);
}
private static SymmetricAlgorithm CreateCryptoServiceProvider(string key)
{
byte[] passwordHash;
using (MD5 md5 = MD5.Create())
{
// It's not clear why you're taking the hash of the password...
passwordHash = md5.ComputeHash(Encoding.UTF8.GetBytes(key));
}
var crypt = new TripleDESCryptoServiceProvider();
crypt.Key = passwordHash;
crypt.Mode = CipherMode.CBC; // This is the default anyway - can remove
crypt.Padding = PaddingMode.PKCS7; // Ditto
// Fix this to use a randomly generated one and store it for real code.
crypt.IV = new byte[crypt.BlockSize / 8];
return crypt;
}
public static byte[] Serialize(object obj, string key)
{
var provider = CreateCryptoServiceProvider(key);
using (MemoryStream memory = new MemoryStream())
{
using (CryptoStream stream = new CryptoStream(
memory, provider.CreateEncryptor(), CryptoStreamMode.Write))
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, obj);
}
return memory.ToArray();
}
}
public static object Deserialize(byte[] inBytes, string key)
{
var provider = CreateCryptoServiceProvider(key);
using (MemoryStream memory = new MemoryStream(inBytes))
{
using (CryptoStream stream = new CryptoStream(
memory, provider.CreateDecryptor(), CryptoStreamMode.Read))
{
BinaryFormatter formatter = new BinaryFormatter();
return formatter.Deserialize(stream);
}
}
}
}
Related
I have written a SecurityExtensions static class to deal with encryption using AES CBC 128 Bit
public static class SecurityExtensions
{
private static Aes GetAes(string keyText, byte[] iv)
{
var key = keyText.ToByteArray();
using var result = Aes.Create();
result.Mode = CipherMode.CBC;
result.Padding = PaddingMode.Zeros;
result.KeySize = 128;
if (iv.Length > 0)
{
result.IV = iv;
}
result.Key = key;
return result;
}
public static AesEncryptionInfo EncryptWithAes(this string plainText, string keyText)
{
var aesAlg = GetAes(keyText, new byte[0]);
var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
byte[] encrypted;
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (var swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
var result = new AesEncryptionInfo(encrypted, aesAlg.IV);
return result;
}
public static string DecryptFromAes(this byte[] cipherText, string keyText, byte[] iv)
{
var aesAlg = GetAes(keyText, iv);
var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
var result = srDecrypt.ReadToEnd();
return result;
}
}
}
}
}
This crashes unless I have the result.Padding = PaddingMode.Zeros line (which is not in the MS example I used as a basis)
When I use the extension as below, the original value is not returned
const string key = "test1234test1234";
var textToEncrypt = "TESTING ENCRYPTION";
var actualEncryptionInfo = textToEncrypt.EncryptWithAes(key);
var decryptedText = actualEncryptionInfo.Encrypted.DecryptFromAes(key, actualEncryptionInfo.InversionVector);
What am I doing wrong?
The AesEncryptionInfo is a simple class that holds the encrypted value and the IV
public class AesEncryptionInfo
{
public AesEncryptionInfo(byte[] encrypted, byte[] inversionVector)
{
InversionVector = inversionVector;
Encrypted = encrypted;
}
public byte[] InversionVector { get; set; }
public byte[] Encrypted { get; set; }
}
Paul
You are disposing the Aes instance with using statement in GetAes method.
Change:
using var result = Aes.Create();
to:
var result = Aes.Create();
And dispose the Aes in DecryptFromAes and EncryptWithAes.
using var aesAlg = GetAes(keyText, new byte[0]);
using var aesAlg = GetAes(keyText, iv);
I try to build simple AES encryption helper to encrypt/decrypt some strings
Fist, I have an issue with Padding mode wherein decryption it only accepts if Zero otherwise an error about padding occurs!
The second issue is when I try to encrypt simple string "Hello World," it got encrypted, and I have the base64 string, but when trying to decrypt, there's no error, but a weird unknown character is shown! like 㡲啁䎰廾ử靱㡲啁䎰廾ử靱
My code:
private static int keySizes = 256;
private static int blockSize = 128;
private static PaddingMode pMode = PaddingMode.Zeros;
private static CipherMode cMode = CipherMode.ECB;
private static byte[] key = GenEncryptionKey();
private const string passphrase = #"StartYourMorningWithASmile";
private static byte[] GenEncryptionKey()
{
HashAlgorithm hash = MD5.Create();
return hash.ComputeHash(Encoding.Unicode.GetBytes(passphrase));
}
private static AesManaged CreateCryptor()
{
AesManaged cryptor = new AesManaged();
cryptor.KeySize = keySizes;
cryptor.BlockSize = blockSize;
cryptor.Padding = pMode;
cryptor.Key = key;
cryptor.Mode = cMode;
cryptor.GenerateIV();
return cryptor;
}
public static string EncryptParams(string reqVal)
{
string cipherText = "";
if (string.IsNullOrEmpty(reqVal) || reqVal.Length < 1)
throw new ArgumentNullException();
byte[] plainBytes = Encoding.Unicode.GetBytes(reqVal);
using (var cryptor = CreateCryptor())
{
ICryptoTransform encryptor = cryptor.CreateEncryptor();
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
cs.Write(plainBytes, 0, plainBytes.Length);
}
byte[] cipherBytes = ms.ToArray();
cipherText = Convert.ToBase64String(cipherBytes);
}
cryptor.Clear();
}
return cipherText;
}
public static string DecryptParams(string resVal)
{
var data = Convert.FromBase64String(resVal);
byte[] cipherBytes = new byte[data.Length];
string plainText = "";
using (var crypto = CreateCryptor())
{
ICryptoTransform Dec = crypto.CreateDecryptor();
using (MemoryStream ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, Dec, CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
plainText = Encoding.Unicode.GetString(ms.ToArray());
}
}
crypto.Clear();
}
return plainText;
}
UPDATE 1:
Please set also the IV yourself to achieve successful decryption, as #maarten-bodewes pointed out. I missed that part and the decryption somehow worked (?) with your existing code, but you always should provide the same key and IV to a symmetric encryption algorithm to have it work both ways.
ORIGINAL ANSWER:
Your decryption fails (produces incorrect results) because you implemented the decryption part incorrectly (by using CryptoStreamMode.Write instead of CryptoStreamMode.Read) and besides feeding the decryption stream all zero bytes
At the point of execution of
cs.Write(cipherBytes, 0, cipherBytes.Length);
the variable cipherBytes is all zero. The real encrypted buffer is in the data variable which you only use to set the length of cipherBytes
So change your decryption method to this.
BONUS: After correcting the decryption part, you can specify the padding as you wish! I tested with PKCS7 and it is ok.
public static string DecryptParams(string resVal)
{
var cipherBytes = Convert.FromBase64String(resVal);
string plainText = "";
using (var crypto = CreateCryptor())
{
ICryptoTransform Dec = crypto.CreateDecryptor();
using (MemoryStream ms = new MemoryStream(cipherBytes))
{
using (var cs = new CryptoStream(ms, Dec, CryptoStreamMode.Read))
{
byte[] decryptBlock = new byte[4096];
MemoryStream decryptStream = new MemoryStream();
int readBytes;
while ((readBytes = cs.Read(decryptBlock, 0, 4096)) > 0)
{
decryptStream.Write(decryptBlock, 0, readBytes);
}
plainText = Encoding.Unicode.GetString(decryptStream.ToArray());
}
}
crypto.Clear();
}
return plainText;
}
Hope this helps.
Thanks to Oguz
Below is my description method after edit
public static string DecryptParams(string resVal)
{
var data = Convert.FromBase64String(resVal);
byte[] cipherBytes = new byte[data.Length];
string plainText = "";
using (var crypto = CreateCryptor())
{
ICryptoTransform Dec = crypto.CreateDecryptor();
using (MemoryStream ms = new MemoryStream(data))
{
using (var cs = new CryptoStream(ms, Dec, CryptoStreamMode.Read))
{
cs.Read(cipherBytes, 0, cipherBytes.Length);
plainText = Encoding.Unicode.GetString(cipherBytes.ToArray());
}
}
crypto.Clear();
}
return plainText;
}
one more thing about the return result after the decryption I got the original string plus \0\0\0\0 so I use myString.TrimEnd('\0') to solve that.
I am trying to implement image steganography with LSB and everything works except decrypting.
There is my class responsible for encryption and decryption of strings below. Encrypting works fine but Decrypt method always returns null:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace WindowsFormsApp1
{
class Encryptor {
//text to encrypt or already decrypted
private String decryptedText = "";
//text to decrypt or already encrypted
private String encryptedText = "";
private String key = "";
public Encryptor setDecryptedText(String text)
{
decryptedText = text;
return this;
}
public Encryptor setEncryptedText(String text)
{
encryptedText = text;
return this;
}
public Encryptor setKey(String text)
{
key = text;
return this;
}
Byte[] getHash(Byte[] hash)
{
Byte[] newHash = new Byte[32];
for (int i = 0; i < 32; i++)
{
newHash[i] = hash[i];
}
return newHash;
}
Byte[] getIV(Byte[] hash)
{
Byte[] newHash = new Byte[16];
int j = 0;
for (int i = 32; i < 48; i++)
{
newHash[j++] = hash[i];
}
return newHash;
}
String EncryptAesManaged()
{
SHA512 shaM = new SHA512Managed();
Byte[] data = Encoding.UTF8.GetBytes(key);
Byte[] hash = shaM.ComputeHash(data);
try
{
return Encrypt(decryptedText, getHash(hash), getIV(hash));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return null;
}
String DecryptAesManaged()
{
SHA512 shaM = new SHA512Managed();
var data = Encoding.UTF8.GetBytes(key);
Byte[] hash = shaM.ComputeHash(data);
try
{
return Decrypt(Convert.FromBase64String(encryptedText), getHash(hash), getIV(hash));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return "";
}
String Encrypt(string plainText, byte[] Key, byte[] IV)
{
Byte[] encrypted;
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform encryptor = aes.CreateEncryptor(Key, IV);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs)) {
sw.Write(Encoding.UTF8.GetBytes(plainText));
cs.FlushFinalBlock();
encrypted = ms.ToArray();
}
}
}
aes.Clear();
}
return Convert.ToBase64String(encrypted);
}
string Decrypt(byte[] cipherText, byte[] Key, byte[] IV)
{
string plaintext = null;
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform decryptor = aes.CreateDecryptor(Key, IV);
try
{
using (MemoryStream ms = new MemoryStream(cipherText))
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
using (StreamReader reader = new StreamReader(cs))
{
plaintext = reader.ReadToEnd(); //Here get null
}
aes.Clear();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
return plaintext;
}
public String getEncrypted()
{
return EncryptAesManaged();
}
public String getDecrypted()
{
return DecryptAesManaged();
}
}
}
Why is Decrypt() returning null rather than the originally encrypted string?
You don't show how you use your Encryptor class, so your question doesn't quite include a Minimal, Complete, and Verifiable example. I was able to reproduce the problem with the following test harness:
public static void Test()
{
var key = "my key";
var plainText = "hello";
var encryptor = new Encryptor();
encryptor.setDecryptedText(plainText);
encryptor.setKey(key);
var encrypted = encryptor.getEncrypted();
Console.WriteLine(encrypted);
var deecryptor = new Encryptor();
deecryptor.setEncryptedText(encrypted);
deecryptor.setKey(key);
var decrypted = deecryptor.getDecrypted();
Console.WriteLine(decrypted);
Assert.IsTrue(plainText == decrypted);
}
Demo fiddle #1 here.
Given that, your code has 2 problems, both of which are actually in encryption rather than decryption.
Firstly, in Encrypt(string plainText, byte[] Key, byte[] IV), you are writing to the StreamWriter sw, then flushing the CryptoStream and returning the MemoryStream contents -- but you never flush or dispose sw, so its buffered contents are never forwarded to the underlying stream(s).
To fix this, your code should looks something like:
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(Encoding.UTF8.GetBytes(plainText));
}
}
encrypted = ms.ToArray();
}
Now getDecrypted() no longer returns a null result -- but instead returns a wrong result of "System.Byte[]", as shown in demo fiddle #2 here.
Secondly, again in Encrypt(...), you are effectively encoding your plainText twice at this line:
sw.Write(Encoding.UTF8.GetBytes(plainText));
Encoding.UTF8.GetBytes(plainText) converts the plain text to a byte array, but the StreamWriter is also intended to do this job, converting strings to bytes and passing them to the underlying stream. So, since you are not passing a string to Write(), the overload that gets called is StreamWriter.Write(Object):
Writes the text representation of an object to the text string or stream by calling the ToString() method on that object.
Thus what actually gets encrypted is the ToString() value of a byte array, which is "System.Byte[]".
To fix this, simply remove the call to Encoding.UTF8.GetBytes(plainText) and write the string directly. Thus your Encrypt() method should now look like:
static String Encrypt(string plainText, byte[] Key, byte[] IV)
{
string encrypted;
using (var aes = new RijndaelManaged())
{
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.KeySize = 256;
ICryptoTransform encryptor = aes.CreateEncryptor(Key, IV);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write, true))
{
using (var sw = new StreamWriter(cs))
{
sw.Write(plainText);
}
}
// Calling GetBuffer() avoids the extra allocation of ToArray().
encrypted = Convert.ToBase64String(ms.GetBuffer(), 0, checked((int)ms.Length));
}
aes.Clear();
}
return encrypted;
}
Demo fiddle #3 here that now passes successfully.
Disclaimer: this answer does not attempt to to review your code for security best practices such as secure setup of salt and IV.
I'm trying to encrypt and decrypt a file using AES. The problem that I have is that when the file gets decrypted, it is broken and you can't open it. The original file has a length of 81.970 bytes and the decrypted file has a length of 81.984 bytes...so there are 14 bytes added for some reason. The problem could be in the way the file gets encrypted but I don't know what I'm doing wrong.
What am I missing here? Could it be the way I'm processing the password, the iv and the padding?
Thanks for your time!
This is the code I use to encrypt:
private AesManaged aesManaged;
private string filePathToEncrypt;
public Encrypt(AesManaged aesManaged, string filePathToEncrypt)
{
this.aesManaged = aesManaged;
this.filePathToEncrypt = filePathToEncrypt;
}
public void DoEncryption()
{
byte[] cipherTextBytes;
byte[] textBytes = File.ReadAllBytes(this.filePathToEncrypt);
using(ICryptoTransform encryptor = aesManaged.CreateEncryptor(aesManaged.Key, aesManaged.IV))
using (MemoryStream ms = new MemoryStream())
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
cs.Write(textBytes, 0, textBytes.Length);
cs.FlushFinalBlock();
cipherTextBytes = ms.ToArray();
}
File.WriteAllBytes("EncryptedFile.aes", cipherTextBytes);
}
This is the code I use to decrypt:
private AesManaged aesManaged;
private string filePathToDecrypt;
public Decrypt(AesManaged aesManaged, string filePathToDecrypt)
{
this.aesManaged = aesManaged;
this.filePathToDecrypt = filePathToDecrypt;
}
public void DoDecrypt()
{
byte[] cypherBytes = File.ReadAllBytes(this.filePathToDecrypt);
byte[] clearBytes = new byte[cypherBytes.Length];
ICryptoTransform encryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.IV);
using (MemoryStream ms = new MemoryStream(cypherBytes))
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Read))
{
cs.Read(clearBytes, 0, clearBytes.Length);
clearBytes = ms.ToArray();
}
File.WriteAllBytes("DecryptedFile.gif", clearBytes);
}
And here is how I call the functions:
string filePathToEncrypt = "dilbert.gif";
string filePathToDecrypt = "EncryptedFile.aes";
string password = "Password";
string passwordSalt = "PasswordSalt";
Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(password, Encoding.ASCII.GetBytes(passwordSalt));
var aesManaged = new AesManaged
{
Key = deriveBytes.GetBytes(128 / 8),
IV = deriveBytes.GetBytes(16),
Padding = PaddingMode.PKCS7
};
Console.WriteLine("Encrypting File...");
var encryptor = new Encrypt(aesManaged, filePathToEncrypt);
encryptor.DoEncryption();
Thread.Sleep(300);
Console.WriteLine("Decrypting File...");
var decryptor = new Decrypt(aesManaged, filePathToDecrypt);
decryptor.DoDecrypt();
Thread.Sleep(300);
Try with:
public void DoEncryption()
{
byte[] cipherBytes;
byte[] textBytes = File.ReadAllBytes(this.filePathToEncrypt);
using (ICryptoTransform encryptor = aesManaged.CreateEncryptor(aesManaged.Key, aesManaged.IV))
using (MemoryStream input = new MemoryStream(textBytes))
using (MemoryStream output = new MemoryStream())
using (CryptoStream cs = new CryptoStream(output, encryptor, CryptoStreamMode.Write))
{
input.CopyTo(cs);
cs.FlushFinalBlock();
cipherBytes = output.ToArray();
}
File.WriteAllBytes("EncryptedFile.aes", cipherBytes);
}
and
public void DoDecrypt()
{
byte[] cypherBytes = File.ReadAllBytes(this.filePathToDecrypt);
byte[] textBytes;
using (ICryptoTransform decryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.IV))
using (MemoryStream input = new MemoryStream(cypherBytes))
using (MemoryStream output = new MemoryStream())
using (CryptoStream cs = new CryptoStream(input, decryptor, CryptoStreamMode.Read))
{
cs.CopyTo(output);
textBytes = output.ToArray();
}
File.WriteAllBytes("DecryptedFile.gif", textBytes);
}
Note that the code could be modified to not use temporary byte[] and read/write directly to input/output streams.
In general you can't desume the length of the plaintext from the length of the cyphertext, so this line:
new byte[cypherBytes.Length]
was totally wrong.
And please, don't use Encoding.ASCII in 2016. It is so like previous century. Use Encoding.UTF8 to support non-english characters.
The answer may be very simple. I don't see where do u try to choose a cipher mode, so by default it probably takes CBC, as IV was inited. Then, 81.970 are padded by 14 bytes, to be divisible by 32. So when it happens, the memory you allocated was just 81.970, so the padding bytes doesn't write correctly, cause of some sort of memory leak, and when decrypt is started, unpadding doesn't work correctly.
I'm using DES-ECB + base64 encryption in my application. That's the code of the class I called "Crypto"
public class Crypto
{
public static string Decrypt(string encryptedString)
{
DESCryptoServiceProvider desProvider = new DESCryptoServiceProvider();
desProvider.Mode = CipherMode.ECB;
desProvider.Padding = PaddingMode.PKCS7;
desProvider.Key = Encoding.ASCII.GetBytes("e5d66cf8");
using (MemoryStream stream = new MemoryStream(Convert.FromBase64String(encryptedString)))
{
using (CryptoStream cs = new CryptoStream(stream, desProvider.CreateDecryptor(), CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs, Encoding.ASCII))
{
return sr.ReadToEnd();
}
}
}
}
public static string Encrypt(string decryptedString)
{
DESCryptoServiceProvider desProvider = new DESCryptoServiceProvider();
desProvider.Mode = CipherMode.ECB;
desProvider.Padding = PaddingMode.PKCS7;
desProvider.Key = Encoding.ASCII.GetBytes("e5d66cf8");
using (MemoryStream stream = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(stream, desProvider.CreateEncryptor(), CryptoStreamMode.Write))
{
byte[] data = Encoding.Default.GetBytes(decryptedString);
cs.Write(data, 0, data.Length);
return Convert.ToBase64String(stream.ToArray());
}
}
}
}
but when I encrypt a string, then decrypt it again and encrypt one more time, the encrypted string is not the same as previous encrypted was. So that's the first encrypted string:
kEN0HUp/dqz8kXA7nYivJG6Jl3haLJjhBq1UfEtQTwaPwizW//03M0UxF8dBuYZo2BoZ5vsVcXRJF1LpFZLWxDsdeKAC43L2K2OoYRxTn/dA6KmM13YS9xOezGiROQfVj5qrkdokJRCvj0gYfFoH2oeDGyN+EAw5Dgzsp697kj4=
and here comes the second encrypted string:
kEN0HUp/dqz8kXA7nYivJG6Jl3haLJjhBq1UfEtQTwaPwizW//03M0UxF8dBuYZo2BoZ5vsVcXRJF1LpFZLWxDsdeKAC43L2K2OoYRxTn/dA6KmM13YS9xOezGiROQfVj5qrkdokJRCvj0gYfFoH2oeDGyN+EAw5
They are almost same, except this "Dgzsp697kj4=" in the first string.
What's wrong?
Thanks in advance.
You are losing data. In your Encrypt() method you need to call EncryptFinalBlock() to let the padding algorithm know that you are done so that it can add the padding:
using (CryptoStream cs = new CryptoStream(stream, desProvider.CreateEncryptor(), CryptoStreamMode.Write))
{
byte[] data = Encoding.Default.GetBytes(decryptedString);
cs.Write(data, 0, data.Length);
cs.FlushFinalBlock(); // <-- Add this
return Convert.ToBase64String(stream.ToArray());
}
I had a similar problem. You should check that white space is not getting appended to the end of the decrypted string. You might need to trim the white space off.