Scenario - I have multiple files on my server and as per policy we can keep only encrypted files. We are doing some data migration, for this we have to move these files on to cloud and as per documentations Base64 is the best way to transfer encrypted data over network. I am new in encryption and stuck between this. Let me know if this help you.
How to save file in base64 format?
================================================================
I am new in Encryption and got below code from net and trying to encrypting files using RijndaelManaged and the following code is working fine
public static void EncryptFile(string inputFile, string outputFile)
{
try
{
string password = #"myKey123"; // Your Key Here
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
string cryptFile = outputFile;
FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);
RijndaelManaged RMCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateEncryptor(key, key),
CryptoStreamMode.Write);
FileStream fsIn = new FileStream(inputFile, FileMode.Open);
int data;
while ((data = fsIn.ReadByte()) != -1)
cs.WriteByte((byte)data);
fsIn.Close();
cs.Close();
fsCrypt.Close();
}
catch
{
}
}
When I try to decrypt using Convert.FromBase64String, it returns an error
public static string DecryptFile(string inputFile)
{
var myRijndael = new RijndaelManaged { Key = _key, IV = _key, Padding = PaddingMode.PKCS7 };
_decryptor = myRijndael.CreateDecryptor(myRijndael.Key, myRijndael.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(inputFile)))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, _decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
return srDecrypt.ReadToEnd();
}
}
}
}
Please help me to solve this issue
Related
I wrote this code to encrypt a text and write the encrypted text to a file and then decrypt it from the file. But I get this exception: System.Security.Cryptography.CryptographicException: 'The input data is not a complete block.' When I use a byte[] for storing data, it works perfect but it seems that it cant correctly convert a file to byte[]. I also tried File.ReadAllBytes but I got the same error. Please Help me.
class Program
{
static void Main(string[] args)
{
string decrypted;
byte[] encrypted;
Console.Write("Enter a text to encrypt : ");
string plaintext = Console.ReadLine();
using (Aes aes = Aes.Create())
{
encrypted = AesEncryption.Encrypt(plaintext, aes);
File.WriteAllText(#"C:\Users\sepita\Desktop\My.txt", Encoding.UTF8.GetString(encrypted), Encoding.UTF8);
decrypted = AesEncryption.Decrypt(Encoding.UTF8.GetBytes(File.ReadAllText(#"C:\Users\sepita\Desktop\My.txt")), aes);
}
Console.WriteLine($"Encrypted : {Encoding.UTF8.GetString(encrypted)}");
Console.WriteLine($"Decrypted : {decrypted}");
}
}
static class AesEncryption
{
public static byte[] Encrypt(string plaintext, Aes aes)
{
byte[] encrypted;
ICryptoTransform encryptor = aes.CreateEncryptor();
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream stream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(plaintext);
}
encrypted = memoryStream.ToArray();
}
}
return encrypted;
}
public static string Decrypt(byte[] encrypted, Aes aes)
{
string decrypted = null;
ICryptoTransform decryptor = aes.CreateDecryptor();
using (MemoryStream memoryStream = new MemoryStream(encrypted))
{
using (CryptoStream stream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
using (StreamReader reader = new StreamReader(stream))
{
decrypted = reader.ReadToEnd();
}
}
}
return decrypted;
}
}
The result of your Encrypt function is binary data. It would be pure luck if this were a valid UTF8 string, so Encoding.UTF8.GetString(encrypted) will not work in general.
Replacing it by
File.WriteAllBytes(#"C:\Users\sepita\Desktop\My.bin", encrypted);
decrypted = AesEncryption.Decrypt(File.ReadAllBytes(#"C:\Users\sepita\Desktop\My.bin"), aes);
will work.
If you want a text file, use BASE64 conversion on the binary data:
File.WriteAllText(#"C:\Users\sepita\Desktop\My.txt", Convert.ToBase64String(encrypted));
decrypted = AesEncryption.Decrypt(Convert.FromBase64String(File.ReadAllText(#"C:\Users\sepita\Desktop\My.txt")), aes);
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 have an existing zip file, I want to use AESManaged class to encrypt it, but I don't find where I can set the password to the zip file in that class. After researching, I found some libaries such as 'DotNetZip' can complete the task. But my file is already a .zip, I needn't to compress again, I only want to encrypt it. Anyone can help me to use AESManaged class to ahieve the purpose?
Thanks
I don't know if this is what your are looking for but I created a code that encrypts any file.
Here's the code for the encrypter:
private void EncryptFile(string inputFile, string outputFile)
{
string password = #"yourPWhere";
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = CreateKey(password);
string cryptFile = outputFile;
FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);
RijndaelManaged RMCrypto = new RijndaelManaged();
IV = CreateIV(password_mTxtBx.Text);
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateEncryptor(key,IV),
CryptoStreamMode.Write);
FileStream fsIn = new FileStream(inputFile, FileMode.Open);
int data;
while ((data = fsIn.ReadByte()) != -1)
cs.WriteByte((byte)data);
fsIn.Close();
cs.Close();
fsCrypt.Close();
}
Here's the code for the decrypter:
private void DecryptFile(string inputFile, string outputFile)
{
string password = #"yourPWhere";
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = CreateKey(password);
FileStream fsCrypt = new FileStream(inputFile, FileMode.Open);
RijndaelManaged RMCrypto = new RijndaelManaged();
IV = CreateIV(password_mTxtBx.Text);
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateDecryptor(key, IV),
CryptoStreamMode.Read);
FileStream fsOut = new FileStream(outputFile.Remove(outputFile.Length - 4), FileMode.Create);
int data;
while ((data = cs.ReadByte()) != -1)
fsOut.WriteByte((byte)data);
fsOut.Close();
cs.Close();
fsCrypt.Close();
}
I saw a similar code on codeproject a few months ago. So it's not directly my work.
Credits go to the author.
Updated with password-based key derivation (PBKDF2):
private static int saltLengthLimit = 32;
private static byte[] GetSalt(int maximumSaltLength)
{
var salt = new byte[maximumSaltLength];
using (var random = new RNGCryptoServiceProvider())
{
random.GetNonZeroBytes(salt);
}
return salt;
}
public static byte[] CreateKey(string password)
{
var salt = GetSalt(10);
int iterationCount = 20000; // Nowadays you should use at least 10.000 iterations
using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, iterationCount))
return rfc2898DeriveBytes.GetBytes(16);
}
Creator for the IV (created from Password):
public byte[] CreateIV(string password)
{
var salt = GetSalt(9);
const int Iterations = 325;
using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, Iterations))
return rfc2898DeriveBytes.GetBytes(16);
}
The byte length of the key is in my case 128bit(!) = 16 bytes (128/8), but you can use any other length supported by Rijndael (Key: 128, 192, 256 bit = 16, 24, 32 bytes).
The IV is always 16 bytes!
If you want to use a password in your original zip file when uncompressing, then you will need to re-compress the files and add a password when doing so.
This link from the dotnetzip library documentation shows an easy way to zip with password encryption using that library.
Additional note about security:
Don't use the zip 2.0 encryption method if you care at all about encryption security as it is quite flawed. Instead use the AES 256-bit encryption.
Here is some example code(pulled directly from the link above) showing an implementation of the AES 256-bit encryption using the dotnetzip library with default level compression:
using (ZipFile zip = new ZipFile())
{
zip.AddFile("ReadMe.txt"); // no password for this one
zip.Password= "Cool.Hand.Luke!";
zip.Encryption= EncryptionAlgorithm.WinZipAes256;
zip.AddFile("Rawdata-2008-12-18.csv");
zip.Save("Backup-AES-Encrypted.zip");
}
Edit: added clarification about original zip file
Edit 2: added code
You can use DotNetZip (Ionic zip) as you mentioned, which supports setting password, providing zero level of compression:
using (ZipFile zip = new ZipFile())
{
zip.CompressionLevel = Ionic.Zlib.CompressionLevel.None;
zip.AddFile(#"MyMusic\Messiah-01.mp3");
zip.Save(ZipFileToCreate);
}
So there's no overhead (compressing already compressed file) you just setting the password.
I have recently been experimenting with the "CryptoStream", and ran into the idea of encrypting & decrypting a text via. the Aes class. 'Namespace: System.Security.Cryptography'
After making a function that succesfully encrypted a text using two input parameters: Text, Password
static byte[] Salt = { 18,39,27,48,82,32,12,92 };
public static string EncryptAES(string txt, string Password) {
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(Password, Salt);
RijndaelManaged RJM = new RijndaelManaged();
RJM.Key = rfc.GetBytes(RJM.KeySize / 8);
ICryptoTransform ICT = Aes.Create().CreateEncryptor(RJM.Key, RJM.IV);
using (MemoryStream MS = new MemoryStream()) {
using (CryptoStream CS = new CryptoStream(MS, ICT, CryptoStreamMode.Write)) {
using (StreamWriter SW = new StreamWriter(CS)) {
SW.Write(txt);
}
}
return Convert.ToBase64String(MS.ToArray());
}
}
The issue of decrypting the text took place.
My attempt of decrypt the text was the following:
public static string DecryptAES(string EncryptedTxt, string Password) {
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(EncryptedTxt, Salt);
RijndaelManaged RJM = new RijndaelManaged();
RJM.Key = rfc.GetBytes(RJM.KeySize / 8);
ICryptoTransform ICT = Aes.Create().CreateDecryptor(RJM.Key, RJM.IV);
using (MemoryStream MS = new MemoryStream(Convert.FromBase64String(EncryptedTxt))) {
using (CryptoStream CS = new CryptoStream(MS, ICT, CryptoStreamMode.Read)) {
using (StreamReader SR = new StreamReader(CS)) {
return SR.ReadToEnd();
}
}
}
However; it appears that my way of converting the memorystream to string and then back was invaild, as I get the following error: Error: Value cannot be null\nParameter name: inputBuffer
The error occurs at using (MemoryStream MS = new MemoryStream(Convert.FromBase64String(EncryptedTxt)))
How can I converter the MemoryStream into string and back?
Thanks in advance :-)
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.