Only part of the string is getting decrypted, i think it has to do with my encoding.
Here is what happens:
string s = "The brown fox jumped over the green frog";
string k = "urieurut";
string enc = EncryptString(s, k);
string dec = DecryptString(enc, k);
The RESULT is this: The brown fox juϼ㴘裴혽Ή⪻ㆉr th≸ g⟤een frog
public static string EncryptString(string stringToEncrypt, string encryptionKey)
{
string encrypted = String.Empty;
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(encryptionKey);
RijndaelManaged RMCrypto = new RijndaelManaged();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, RMCrypto.CreateEncryptor(key, key), CryptoStreamMode.Write);
byte[] encryptedString = UE.GetBytes(stringToEncrypt);
cs.Write(encryptedString, 0, encryptedString.Length);
cs.FlushFinalBlock();
cs.Close();
encrypted = UE.GetString(ms.ToArray());
return encrypted;
}
public static string DecryptString(string stringToDecrypt, string encryptionKey)
{
string decrypted = String.Empty;
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(encryptionKey);
byte[] data = UE.GetBytes(stringToDecrypt);
RijndaelManaged RMCrypto = new RijndaelManaged();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, RMCrypto.CreateDecryptor(key, key), CryptoStreamMode.Write);
cs.Write(data, 0, data.Length);
cs.FlushFinalBlock();
cs.Close();
decrypted = UE.GetString(ms.ToArray());
return decrypted;
}
Here you go:
string s = "The brown fox jumped over the green frog";
string k = "urieurut";
byte[] enc = EncryptString(s, k);
string dec = DecryptString(enc, k);
You can't attempt to interpret an encrypted bunch of bytes as a Unicode string. Keep them as bytes. The decrypted version can be converted back to string.
Also note the disposing of disposable objects below. You could wind up with some resources being held too long or leak if you don't release them properly with using() or Dispose().
public static byte[] EncryptString(string stringToEncrypt, string encryptionKey)
{
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(encryptionKey);
using (RijndaelManaged RMCrypto = new RijndaelManaged())
using (MemoryStream ms = new MemoryStream())
using (ICryptoTransform encryptor = RMCrypto.CreateEncryptor(key, key))
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
byte[] encryptedString = UE.GetBytes(stringToEncrypt);
cs.Write(encryptedString, 0, encryptedString.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
}
public static string DecryptString(byte[] stringToDecrypt, string encryptionKey)
{
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(encryptionKey);
using (RijndaelManaged RMCrypto = new RijndaelManaged())
using (MemoryStream ms = new MemoryStream())
using (ICryptoTransform decryptor = RMCrypto.CreateDecryptor(key, key))
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
{
cs.Write(stringToDecrypt, 0, stringToDecrypt.Length);
cs.FlushFinalBlock();
return UE.GetString(ms.ToArray());
}
}
I solved my issue by using base64 string for the encryption - i may look at other options but i only needed these methods for a small amount of data, here is the final code:
public static string EncryptString(string stringToEncrypt, string encryptionKey)
{
string encrypted = String.Empty;
byte[] key = Encoding.Unicode.GetBytes(encryptionKey);
RijndaelManaged RMCrypto = new RijndaelManaged();
RMCrypto.Padding = PaddingMode.PKCS7;
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, RMCrypto.CreateEncryptor(key, key), CryptoStreamMode.Write);
byte[] encryptedString = Encoding.ASCII.GetBytes(stringToEncrypt);
cs.Write(encryptedString, 0, encryptedString.Length);
cs.FlushFinalBlock();
cs.Close();
//encrypted = Encoding.ASCII.GetString(ms.ToArray());
return Convert.ToBase64String(ms.ToArray());
}
public static string DecryptString(string stringToDecrypt, string encryptionKey)
{
string decrypted = String.Empty;
byte[] key = Encoding.Unicode.GetBytes(encryptionKey);
byte[] data = Convert.FromBase64String(stringToDecrypt);
RijndaelManaged RMCrypto = new RijndaelManaged();
RMCrypto.Padding = PaddingMode.PKCS7;
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, RMCrypto.CreateDecryptor(key, key), CryptoStreamMode.Write);
cs.Write(data, 0, data.Length);
cs.FlushFinalBlock();
cs.Close();
decrypted = Encoding.ASCII.GetString(ms.ToArray());
return decrypted;
}
Not sure about your specific code chunk, but Jeff Atwood did a nice little library that I've used before:
http://www.codeproject.com/KB/security/SimpleEncryption.aspx
It's worth a look as it simplifies the process of encrypting things a lot, I actually had to port to C# as there wasn't a port available when I saw it. However there is now a C# port (in the comments section).
Related
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.
This question already has an answer here:
Decrypt/Decrypt Arabic string
(1 answer)
Closed 7 years ago.
How to Encrypt/Decrypt Arabic string in C# using these methods ????
Wheni try to decrypt any arabic string its return "????" question marks.. How can use Encoding UTF8 through this code ??
Any help please ..
thanks in advance
public static string Encrypt(string pDataToEncrypt)
{
ASCIIEncoding textConverter = new ASCIIEncoding();
RijndaelManaged myRijndael = new RijndaelManaged();
byte[] toEncrypt;
ICryptoTransform encryptor = myRijndael.CreateEncryptor(key, IV);
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
toEncrypt = textConverter.GetBytes(pDataToEncrypt);
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
csEncrypt.FlushFinalBlock();
return Convert.ToBase64String(msEncrypt.GetBuffer(), 0, (int)msEncrypt.Length);
}
public static string Decrypt(string pDataToDecrypt)
{
RijndaelManaged myRijndael = new RijndaelManaged();
byte[] fromEncrypt;
//Encoding asciiEncoding = Encoding.ASCII;
fromEncrypt = Convert.FromBase64String(pDataToDecrypt);
ICryptoTransform decryptor = myRijndael.CreateDecryptor(key, IV);
MemoryStream msDecrypt = new MemoryStream(fromEncrypt, 0, fromEncrypt.Length);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
StreamReader sr = new StreamReader(csDecrypt);
return sr.ReadToEnd();
}
Using UTF-8 your code should be like this:
public static string Encrypt(string pDataToEncrypt)
{
RijndaelManaged myRijndael = new RijndaelManaged();
ICryptoTransform encryptor = myRijndael.CreateEncryptor(key, IV);
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor,CryptoStreamMode.Write);
byte[] toEncrypt = Encoding.UTF8.GetBytes(pDataToEncrypt);
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
csEncrypt.FlushFinalBlock();
return Convert.ToBase64String(msEncrypt.GetBuffer(), 0, (int)msEncrypt.Length);
}
public static string Decrypt(string pDataToDecrypt)
{
RijndaelManaged myRijndael = new RijndaelManaged();
byte[] fromEncrypt = Convert.FromBase64String(pDataToDecrypt);
ICryptoTransform decryptor = myRijndael.CreateDecryptor(key, IV);
MemoryStream msDecrypt = new MemoryStream(fromEncrypt, 0, fromEncrypt.Length);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[fromEncrypt.Length];
int decryptedByteCount = csDecrypt.Read(plainTextBytes, 0, plainTextBytes.Length);
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
How to encrypt/decrypt arabic text in C#
public static string Encrypt(string pDataToEncrypt)
{
ASCIIEncoding textConverter = new ASCIIEncoding();
RijndaelManaged myRijndael = new RijndaelManaged();
byte[] toEncrypt;
ICryptoTransform encryptor = myRijndael.CreateEncryptor(key, IV);
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
toEncrypt = textConverter.GetBytes(pDataToEncrypt);
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
csEncrypt.FlushFinalBlock();
return Convert.ToBase64String(msEncrypt.GetBuffer(), 0, (int)msEncrypt.Length);
}
public static string Decrypt(string pDataToDecrypt)
{
RijndaelManaged myRijndael = new RijndaelManaged();
byte[] fromEncrypt;
//Encoding asciiEncoding = Encoding.ASCII;
fromEncrypt = Convert.FromBase64String(pDataToDecrypt);
ICryptoTransform decryptor = myRijndael.CreateDecryptor(key, IV);
MemoryStream msDecrypt = new MemoryStream(fromEncrypt, 0, fromEncrypt.Length);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
StreamReader sr = new StreamReader(csDecrypt);
return sr.ReadToEnd();
}
when i try to encrypt its return "????" question marks
thanks in advance
Use
UnicodeEncoding()
instead of
ASCIIEncoding()
my doubt is about the key to decrypt a encrypted string, without the same key used to encrypt the string i dont get the original string ok, but I need to protect this key not use her in hardcode because any hacker could decompiling a dll and see this key, if I to store this key in any archive, the hacker could copy this archive and my method and decrypt my text, how can i prevent this attack? following my code implementation, here the salt and key are static I'm trying to think in anyway to safe these datas
private static byte[] salt = new byte[255];
private static byte[] key;
internal static string EncryptString(string InputText)
{
System.Security.Cryptography.RijndaelManaged RijndaelCipher =
new System.Security.Cryptography.RijndaelManaged();
RNGCryptoServiceProvider rcs = new RNGCryptoServiceProvider();
rcs.GetBytes(salt);
key = RijndaelCipher.Key;
byte[] plainText = System.Text.Encoding.Unicode.GetBytes(InputText);
System.Security.Cryptography.PasswordDeriveBytes SecretKey =
new System.Security.Cryptography.PasswordDeriveBytes(RijndaelCipher.Key, salt);
System.Security.Cryptography.ICryptoTransform Encryptor =
RijndaelCipher.CreateEncryptor(SecretKey.GetBytes(32), SecretKey.GetBytes(16));
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
System.Security.Cryptography.CryptoStream cryptoStream =
new System.Security.Cryptography.CryptoStream(memoryStream, Encryptor, CryptoStreamMode.Write);
cryptoStream.Write(plainText, 0, plainText.Length);
cryptoStream.FlushFinalBlock();
byte[] CipherBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
string EncryptedData = Convert.ToBase64String(CipherBytes);
return EncryptedData;
}
internal static string DecryptString(string text)
{
System.Security.Cryptography.RijndaelManaged RijndaelCipher =
new System.Security.Cryptography.RijndaelManaged();
byte[] EncryptedData = Convert.FromBase64String(text);
System.Security.Cryptography.PasswordDeriveBytes SecretKey =
new System.Security.Cryptography.PasswordDeriveBytes(RijndaelCipher.Key, salt);
ICryptoTransform Decryptor =
RijndaelCipher.CreateDecryptor(SecretKey.GetBytes(32), SecretKey.GetBytes(16));
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(EncryptedData);
CryptoStream cryptoStream = new CryptoStream(memoryStream, Decryptor, CryptoStreamMode.Read);
byte[] PlainText = new byte[EncryptedData.Length];
int DecryptedCount = cryptoStream.Read(PlainText, 0, PlainText.Length);
memoryStream.Close();
cryptoStream.Close();
string DecryptedData = Encoding.Unicode.GetString(PlainText, 0, DecryptedCount);
return DecryptedData;
}
#endregion
}
I have error from CryptoStream:
Padding is invalid and cannot be removed.
Code
public MemoryStream EncrypteBytes(Stream inputStream, string passPhrase, string saltValue)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
RijndaelCipher.Padding = PaddingMode.PKCS7;
RijndaelCipher.Mode = CipherMode.CBC;
byte[] salt = Encoding.ASCII.GetBytes(saltValue);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, salt, "SHA1", 2);
ICryptoTransform Encryptor = RijndaelCipher.CreateEncryptor(password.GetBytes(32), password.GetBytes(16));
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, Encryptor, CryptoStreamMode.Write);
var buffer = new byte[1024];
var read = inputStream.Read(buffer, 0, buffer.Length);
while (read > 0)
{
cryptoStream.Write(buffer, 0, read);
read = inputStream.Read(buffer, 0, buffer.Length);
}
cryptoStream.FlushFinalBlock();
memoryStream.Position = 0;
return memoryStream;
}
// Example usage: DecryptBytes(encryptedBytes, "SensitivePhrase", "SodiumChloride");
public byte[] DecrypteBytes(MemoryStream memoryStream, string passPhrase, string saltValue)
{
RijndaelManaged RijndaelCipher = new RijndaelManaged();
RijndaelCipher.Padding = PaddingMode.PKCS7;
RijndaelCipher.Mode = CipherMode.CBC;
byte[] salt = Encoding.ASCII.GetBytes(saltValue);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, salt, "SHA1", 2);
ICryptoTransform Decryptor = RijndaelCipher.CreateDecryptor(password.GetBytes(32), password.GetBytes(16));
CryptoStream cryptoStream = new CryptoStream(memoryStream, Decryptor, CryptoStreamMode.Read);
byte[] plainBytes = new byte[memoryStream.Length];
int DecryptedCount = cryptoStream.Read(plainBytes, 0, plainBytes.Length);
return plainBytes;
}
Use PaddingMode.Zeros to fix problem , Following code:
public byte[] EncryptFile(Stream input, string password, string salt)
{
// Essentially, if you want to use RijndaelManaged as AES you need to make sure that:
// 1.The block size is set to 128 bits
// 2.You are not using CFB mode, or if you are the feedback size is also 128 bits
var algorithm = new RijndaelManaged { KeySize = 256, BlockSize = 128 };
var key = new Rfc2898DeriveBytes(password, Encoding.ASCII.GetBytes(salt));
algorithm.Key = key.GetBytes(algorithm.KeySize / 8);
algorithm.IV = key.GetBytes(algorithm.BlockSize / 8);
algorithm.Padding = PaddingMode.Zeros;
using (Stream cryptoStream = new MemoryStream())
using (var encryptedStream = new CryptoStream(cryptoStream, algorithm.CreateEncryptor(), CryptoStreamMode.Write))
{
CopyStream(input, encryptedStream);
return ReadToEnd(cryptoStream);
}
}
public byte[] DecryptFile(Stream input, Stream output, string password, string salt)
{
// Essentially, if you want to use RijndaelManaged as AES you need to make sure that:
// 1.The block size is set to 128 bits
// 2.You are not using CFB mode, or if you are the feedback size is also 128 bits
var algorithm = new RijndaelManaged { KeySize = 256, BlockSize = 128 };
var key = new Rfc2898DeriveBytes(password, Encoding.ASCII.GetBytes(salt));
algorithm.Key = key.GetBytes(algorithm.KeySize / 8);
algorithm.IV = key.GetBytes(algorithm.BlockSize / 8);
algorithm.Padding = PaddingMode.Zeros;
try
{
using (var decryptedStream = new CryptoStream(output, algorithm.CreateDecryptor(), CryptoStreamMode.Write))
{
CopyStream(input, decryptedStream);
return ReadToEnd(output);
}
}
catch (CryptographicException ex)
{
throw new InvalidDataException("Please supply a correct password");
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
I hop help you.
Please check your pass phrase - it should be same in both methods EncrypteBytes and DecrypteBytes. If both are not same, then it will generate the error.
My problem was I was taking the encryped output in bytes and converting it to a string. The string back to byte array (for decrypting) was not the same. I was using UTF8Encoding, then I tried ASCIIEnconding. Neither worked.
Convert.FromBase64String/ToBase64String worked fine, got rid of the padding issues and actually decrypted the data.
It's work
using (FileStream fs = new FileStream( absolute, FileMode.Open )) {
// create a CryptoStream in read mode
using (CryptoStream cryptoStream = new CryptoStream( fs, decryptor, CryptoStreamMode.Read )) {
int readLength = ( int )fs.Length;
byte[] buffer = new byte[readLength];
cryptoStream.Read( buffer, 0, readLength );
using (MemoryStream ms = new MemoryStream( buffer )) {
BinaryFormatter bf = new BinaryFormatter( );
settings = ( SettingsJson )bf.Deserialize( ms );// Deserialize SettingsJson array
}
}
fs.Close( );
}