How to Protect a File? [duplicate] - c#

This question already has answers here:
How to create a password protected file in C#
(2 answers)
Closed 9 years ago.
Am having a FILE named Sample. It may be of any type(.txt/.doc/.docx/.pdf/....). Now I want to set a password for that file. If it is possible just help me with code's.

You can Encrypt the file using your own passwort or with generated keys (See the documentation)
Example from MSDN:
class Class1
{
// Call this function to remove the key from memory after use for security
[System.Runtime.InteropServices.DllImport("KERNEL32.DLL", EntryPoint="RtlZeroMemory")]
public static extern bool ZeroMemory(IntPtr Destination, int Length);
// Function to Generate a 64 bits Key.
static string GenerateKey()
{
// Create an instance of Symetric Algorithm. Key and IV is generated automatically.
DESCryptoServiceProvider desCrypto =(DESCryptoServiceProvider)DESCryptoServiceProvider.Create();
// Use the Automatically generated key for Encryption.
return ASCIIEncoding.ASCII.GetString(desCrypto.Key);
}
static void EncryptFile(string sInputFilename,
string sOutputFilename,
string sKey)
{
FileStream fsInput = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFilename,
FileMode.Create,
FileAccess.Write);
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
ICryptoTransform desencrypt = DES.CreateEncryptor();
CryptoStream cryptostream = new CryptoStream(fsEncrypted,
desencrypt,
CryptoStreamMode.Write);
byte[] bytearrayinput = new byte[fsInput.Length];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Close();
fsInput.Close();
fsEncrypted.Close();
}
static void DecryptFile(string sInputFilename,
string sOutputFilename,
string sKey)
{
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
//A 64 bit key and IV is required for this provider.
//Set secret key For DES algorithm.
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
//Set initialization vector.
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
//Create a file stream to read the encrypted file back.
FileStream fsread = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);
//Create a DES decryptor from the DES instance.
ICryptoTransform desdecrypt = DES.CreateDecryptor();
//Create crypto stream set to read and do a
//DES decryption transform on incoming bytes.
CryptoStream cryptostreamDecr = new CryptoStream(fsread,
desdecrypt,
CryptoStreamMode.Read);
//Print the contents of the decrypted file.
StreamWriter fsDecrypted = new StreamWriter(sOutputFilename);
fsDecrypted.Write(new StreamReader(cryptostreamDecr).ReadToEnd());
fsDecrypted.Flush();
fsDecrypted.Close();
}
static void Main()
{
// Must be 64 bits, 8 bytes.
// Distribute this key to the user who will decrypt this file.
string sSecretKey;
// Get the Key for the file to Encrypt.
sSecretKey = GenerateKey();
// For additional security Pin the key.
GCHandle gch = GCHandle.Alloc( sSecretKey,GCHandleType.Pinned );
// Encrypt the file.
EncryptFile(#"C:\MyData.txt",
#"C:\Encrypted.txt",
sSecretKey);
// Decrypt the file.
DecryptFile(#"C:\Encrypted.txt",
#"C:\Decrypted.txt",
sSecretKey);
// Remove the Key from memory.
ZeroMemory(gch.AddrOfPinnedObject(), sSecretKey.Length * 2);
gch.Free();
}
}
}

You cannot set a password on every file in order to restrict it from opening. However, you can protect file contents by using encryption.
See this link for Encryption & Decryption in C# http://support.microsoft.com/kb/307010

Related

Decrypt file have bad data if wrong key

I've code to decrypt file in DES Encryption, I try I keep getting the file even though I enter the key at the time when the key decrypt the encrypted differently. But i've get the error.
while ((data = cryptostreamDecr.ReadByte()) != -1) // Message Error : Bad Data.
Which code should I add or change in order to keep the process running decrypt?
private static void DecryptFile(string sInputFilename, string sKey)
{
var DES = new DESCryptoServiceProvider();
DES.Key = Encoding.ASCII.GetBytes(sKey);
DES.IV = Encoding.ASCII.GetBytes(sKey);
ICryptoTransform desdecrypt = DES.CreateDecryptor();
using (var fsread = new FileStream(sInputFilename, FileMode.Open,
FileAccess.ReadWrite))
{
using (var cryptostreamDecr = new CryptoStream(fsread,
desdecrypt,
CryptoStreamMode.Read))
{
int data;
fsread.Flush();
using (var ms = new MemoryStream())
{
while ((data = cryptostreamDecr.ReadByte()) != -1)
{
ms.WriteByte((byte)data);
}
cryptostreamDecr.Close();
using (var fsWrite = new FileStream(sInputFilename, FileMode.Truncate))
{
ms.WriteTo(fsWrite);
ms.Flush();
}
}
}
}
}
Encrypt Code :
public static void EncryptFile(string sInputFilename, string sKey)
{
FileStream fsInput = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.ReadWrite);
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
ICryptoTransform desencrypt = DES.CreateEncryptor();
CryptoStream cryptostream = new CryptoStream(fsInput,
desencrypt,
CryptoStreamMode.Write);
byte[] bytearrayinput = new byte[fsInput.Length];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
fsInput.SetLength(0);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.FlushFinalBlock();
cryptostream.Close();
fsInput.Close();
}
[EDIT] : remove in Encypt :
cryptostream.FlushFinalBlock();
And add in decrypt
DES.Padding = PaddingMode.None;
64 bits is the only valid key size for the DES encryption algorithm.
8 bits is equal to one ASCII character means 64 bits is equal to 8 Characters.
If you send 8 characters only then check this (C# "Bad Data" exception when decrypting encrypted file). It may solve your problem.
[Edit]
Add DES.Padding = PaddingMode.None; in DecryptFile.

Encrypting large files (size approximately 100MB) [duplicate]

I have to encrypt, store and then later decrypt large files. What is the best way of doing that? I heard RSA encryption is expensive and was advised to use RSA to encrypt an AES key and then use the AES key to encrypt the large files. Any suggestions with example will be great.
One organism's large is another's petite, though we all know expensive when we see it. Wink, wink.
Try benchmarking something like the following in your environment and see where you're at:
EDIT 2/13/2012: The code has been updated as I've become (imperceptibly) smarter and also noticed a few cut'n'paste errors that had crept in. Mea culpa.
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
...
// Rfc2898DeriveBytes constants:
public readonly byte[] salt = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // Must be at least eight bytes. MAKE THIS SALTIER!
public const int iterations = 1042; // Recommendation is >= 1000.
/// <summary>Decrypt a file.</summary>
/// <remarks>NB: "Padding is invalid and cannot be removed." is the Universal CryptoServices error. Make sure the password, salt and iterations are correct before getting nervous.</remarks>
/// <param name="sourceFilename">The full path and name of the file to be decrypted.</param>
/// <param name="destinationFilename">The full path and name of the file to be output.</param>
/// <param name="password">The password for the decryption.</param>
/// <param name="salt">The salt to be applied to the password.</param>
/// <param name="iterations">The number of iterations Rfc2898DeriveBytes should use before generating the key and initialization vector for the decryption.</param>
public void DecryptFile(string sourceFilename, string destinationFilename, string password, byte[] salt, int iterations)
{
AesManaged aes = new AesManaged();
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
// NB: Rfc2898DeriveBytes initialization and subsequent calls to GetBytes must be eactly the same, including order, on both the encryption and decryption sides.
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, salt, iterations);
aes.Key = key.GetBytes(aes.KeySize / 8);
aes.IV = key.GetBytes(aes.BlockSize / 8);
aes.Mode = CipherMode.CBC;
ICryptoTransform transform = aes.CreateDecryptor(aes.Key, aes.IV);
using (FileStream destination = new FileStream(destinationFilename, FileMode.CreateNew, FileAccess.Write, FileShare.None))
{
using (CryptoStream cryptoStream = new CryptoStream(destination, transform, CryptoStreamMode.Write))
{
try
{
using (FileStream source = new FileStream(sourceFilename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
source.CopyTo(cryptoStream);
}
}
catch (CryptographicException exception)
{
if (exception.Message == "Padding is invalid and cannot be removed.")
throw new ApplicationException("Universal Microsoft Cryptographic Exception (Not to be believed!)", exception);
else
throw;
}
}
}
}
/// <summary>Encrypt a file.</summary>
/// <param name="sourceFilename">The full path and name of the file to be encrypted.</param>
/// <param name="destinationFilename">The full path and name of the file to be output.</param>
/// <param name="password">The password for the encryption.</param>
/// <param name="salt">The salt to be applied to the password.</param>
/// <param name="iterations">The number of iterations Rfc2898DeriveBytes should use before generating the key and initialization vector for the decryption.</param>
public void EncryptFile(string sourceFilename, string destinationFilename, string password, byte[] salt, int iterations)
{
AesManaged aes = new AesManaged();
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
// NB: Rfc2898DeriveBytes initialization and subsequent calls to GetBytes must be eactly the same, including order, on both the encryption and decryption sides.
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, salt, iterations);
aes.Key = key.GetBytes(aes.KeySize / 8);
aes.IV = key.GetBytes(aes.BlockSize / 8);
aes.Mode = CipherMode.CBC;
ICryptoTransform transform = aes.CreateEncryptor(aes.Key, aes.IV);
using (FileStream destination = new FileStream(destinationFilename, FileMode.CreateNew, FileAccess.Write, FileShare.None))
{
using (CryptoStream cryptoStream = new CryptoStream(destination, transform, CryptoStreamMode.Write))
{
using (FileStream source = new FileStream(sourceFilename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
source.CopyTo(cryptoStream);
}
}
}
}
This may help
/// Encrypts a file using Rijndael algorithm.
///</summary>
///<param name="inputFile"></param>
///<param name="outputFile"></param>
private 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
{
MessageBox.Show("Encryption failed!", "Error");
}
}
///
/// Decrypts a file using Rijndael algorithm.
///</summary>
///<param name="inputFile"></param>
///<param name="outputFile"></param>
private void DecryptFile(string inputFile, string outputFile)
{
{
string password = #"myKey123"; // Your Key Here
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
FileStream fsCrypt = new FileStream(inputFile, FileMode.Open);
RijndaelManaged RMCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateDecryptor(key, key),
CryptoStreamMode.Read);
FileStream fsOut = new FileStream(outputFile, FileMode.Create);
int data;
while ((data = cs.ReadByte()) != -1)
fsOut.WriteByte((byte)data);
fsOut.Close();
cs.Close();
fsCrypt.Close();
}
}
source:
http://www.codeproject.com/Articles/26085/File-Encryption-and-Decryption-in-C
Generally the strategy you have described is used when data will be encrypted on one machine (like a server) and then decrypted by another machine (client). The server will encrypt the data using symmetric key encryption (for performance) with a newly generated key and encrypt this symmetric key with a public key (matching a client's private key). The server sends the client both the encrypted data and the encrypted symmetric key. The client can decrypt the symmetric key with it's private key and then use this symmetric key for decrypting the data.
If you are encrypting and decrypting the data on the same machine it may not make sense to use both RSA and AES as you would not be trying to pass the encryption key to another machine.
Like you heard asymmetric cryptography, like RSA, is much slower than symmetric cryptography (e.g. AES) but it does have it's advantages (simpler key management, e.g. a single private key to protect).
The key (pun intended) is to use the advantages of both (private key of asymmetric and speed of symmetric) while ignoring the inconvenience of the other (many secret keys and slow speed).
You can do this by using RSA once per file (no huge performance impact) to encrypt a (symmetric) secret key that is used to encrypt (much faster) your large file. This *wrapping of the symmetric key allows you to only manage a single, private key.
Here's a link to my old (but still true) blog post that gives an example to do this using C# and the .NET framework (Microsoft of Mono).
RSA
It's true asymmetric cryptography (RSA, ECC, etc.) is slower than symmetric (AES, ChaCha20, etc). RSA and others are great for securing a random symmetric key (or establishing one). AES and others are great for efficient encryption, used along with integrity checking (HMAC).
Importantly, mature symmetric ciphers don't have any known theoretical weakness. Unless your attackers has the symmetric key, the encryption cannot be broken. Currently, all mature asymmetric cryptography (RSA, ECC) are based on mathematical properties that are vulnerable to being cracked by a future Quantum Computer (if it ever comes).
Also, handling of public/private keys becomes a problem. It's simple for a human to remember a password - their brain cannot be hacked. With public/private keys, they need to be stored somewhere. Particularly the private key is sensitive. Computers have TDM components that can create and store public/private keys separate to the CPU. This is very complicated to use.
So with that in mind, RSA should only be used if and when it's absolutely necessary.
AES
Here is a complete version I wrote recently, that returns the wrapping streamer, so you can use it however you need.
Also, this method generates IV from random generator instead of the password digestor. This is best practice, for example 7z does this - see https://crypto.stackexchange.com/questions/61945/is-it-ok-to-transmit-an-iv-as-a-custom-http-header. The IV is included in the header for the output.
Usage:
void Save()
{
var encryptedFilePath = Directory.GetCurrentDirectory() + "\\data.bin.aes";
using(var fileStream = File.Create(encryptedFilePath))
{
using (var cryptoStream = Security.FileEncryptor.CreateEncryptor(fileStream, passwordHere))
{
var formatter = new BinaryFormatter();
formatter.Serialize(cryptoStream, myObject);
cryptoStream.Flush();
}
}
}
void Load()
{
var encryptedFilePath = Directory.GetCurrentDirectory() + "\\data.bin.aes";
using(var fileStream = File.Open(encryptedFilePath, FileMode.Open))
{
using (var cryptoStream = Security.FileEncryptor.CreateDecryptor(fileStream, passwordHere))
{
var formatter = new BinaryFormatter();
var myObject = (myObjectType)formatter.Deserialize(cryptoStream);
}
}
}
Utility:
using System.IO;
using System.Security.Cryptography;
using System;
namespace Security
{
class FileEncryptor
{
public static Stream CreateEncryptor(Stream source, string password)
{
byte[] SaltBytes = new byte[16];
RandomNumberGenerator.Fill(SaltBytes); //RandomNumberGenerator is used for .Net Core 3
AesManaged aes = new AesManaged();
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, SaltBytes, iterations);
aes.Key = key.GetBytes(aes.KeySize / 8);
byte[] IVBytes = new byte[aes.BlockSize / 8];
RandomNumberGenerator.Fill(IVBytes); //RandomNumberGenerator is used for .Net Core 3
aes.IV = IVBytes;
aes.Mode = CipherMode.CBC;
ICryptoTransform transform = aes.CreateEncryptor(aes.Key, aes.IV);
//Store/Send the Salt and IV - this can be shared. It's more important that it's very random, than being private.
source.WriteByte((byte)SaltBytes.Length);
source.Write(SaltBytes, 0, SaltBytes.Length);
source.WriteByte((byte)IVBytes.Length);
source.Write(IVBytes, 0, IVBytes.Length);
source.Flush();
var cryptoStream = new CryptoStream(source, transform, CryptoStreamMode.Write);
return cryptoStream;
}
public static Stream CreateDecryptor(Stream source, string password)
{
var ArrayLength = source.ReadByte();
if (ArrayLength == -1) throw new Exception("Salt length not found");
byte[] SaltBytes = new byte[ArrayLength];
var readBytes = source.Read(SaltBytes, 0, ArrayLength);
if (readBytes != ArrayLength) throw new Exception("No support for multiple reads");
ArrayLength = source.ReadByte();
if (ArrayLength == -1) throw new Exception("Salt length not found");
byte[] IVBytes = new byte[ArrayLength];
readBytes = source.Read(IVBytes, 0, ArrayLength);
if (readBytes != ArrayLength) throw new Exception("No support for multiple reads");
AesManaged aes = new AesManaged();
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
aes.IV = IVBytes;
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, SaltBytes, iterations);
aes.Key = key.GetBytes(aes.KeySize / 8);
aes.Mode = CipherMode.CBC;
ICryptoTransform transform = aes.CreateDecryptor(aes.Key, aes.IV);
var cryptoStream = new CryptoStream(source, transform, CryptoStreamMode.Read);
return cryptoStream;
}
public const int iterations = 1042; // Recommendation is >= 1000.
}
}

encryption with single key in c#

i have a code in c# that encrypt and decrypt .txt file. but i need to encrypt and decrypt files with any extension like pdf, zip, jpg etc..
i searched ant tried to find stream encryption but i couldnt find any..
i am trying following code from link . i changed file path and put some pdf or ppt. it works correctly but i can not open decrypted file.
using System;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Text;
namespace CSEncryptDecrypt
{
class Class1
{
// Call this function to remove the key from memory after use for security
[System.Runtime.InteropServices.DllImport("KERNEL32.DLL", EntryPoint="RtlZeroMemory")]
public static extern bool ZeroMemory(IntPtr Destination, int Length);
// Function to Generate a 64 bits Key.
static string GenerateKey()
{
// Create an instance of Symetric Algorithm. Key and IV is generated automatically.
DESCryptoServiceProvider desCrypto =(DESCryptoServiceProvider)DESCryptoServiceProvider.Create();
// Use the Automatically generated key for Encryption.
return ASCIIEncoding.ASCII.GetString(desCrypto.Key);
}
static void EncryptFile(string sInputFilename,
string sOutputFilename,
string sKey)
{
FileStream fsInput = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFilename,
FileMode.Create,
FileAccess.Write);
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
ICryptoTransform desencrypt = DES.CreateEncryptor();
CryptoStream cryptostream = new CryptoStream(fsEncrypted,
desencrypt,
CryptoStreamMode.Write);
byte[] bytearrayinput = new byte[fsInput.Length];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Close();
fsInput.Close();
fsEncrypted.Close();
}
static void DecryptFile(string sInputFilename,
string sOutputFilename,
string sKey)
{
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
//A 64 bit key and IV is required for this provider.
//Set secret key For DES algorithm.
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
//Set initialization vector.
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
//Create a file stream to read the encrypted file back.
FileStream fsread = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);
//Create a DES decryptor from the DES instance.
ICryptoTransform desdecrypt = DES.CreateDecryptor();
//Create crypto stream set to read and do a
//DES decryption transform on incoming bytes.
CryptoStream cryptostreamDecr = new CryptoStream(fsread,
desdecrypt,
CryptoStreamMode.Read);
//Print the contents of the decrypted file.
StreamWriter fsDecrypted = new StreamWriter(sOutputFilename);
fsDecrypted.Write(new StreamReader(cryptostreamDecr).ReadToEnd());
fsDecrypted.Flush();
fsDecrypted.Close();
}
static void Main()
{
// Must be 64 bits, 8 bytes.
// Distribute this key to the user who will decrypt this file.
string sSecretKey;
// Get the Key for the file to Encrypt.
sSecretKey = GenerateKey();
// For additional security Pin the key.
GCHandle gch = GCHandle.Alloc( sSecretKey,GCHandleType.Pinned );
// Encrypt the file.
EncryptFile(#"C:\MyData.txt",
#"C:\Encrypted.txt",
sSecretKey);
// Decrypt the file.
DecryptFile(#"C:\Encrypted.txt",
#"C:\Decrypted.txt",
sSecretKey);
// Remove the Key from memory.
ZeroMemory(gch.AddrOfPinnedObject(), sSecretKey.Length * 2);
gch.Free();
}
}
}
thanks for responses. i found the reason. i should use filestream not the streamwriter in the decryptFile function
following routine I'm using to serialize objects securely.
Maybe it can help you to understand how stream encryption works:
public bool Save(string filename, object toSerialize)
{
byte[] SALT = new byte[]
{0x26, 0xdc, 0xff, 0x00, 0xad, 0xed, 0x7a, 0xee, 0xc5, 0xfe, 0x07, 0xaf, 0x4d, 0x08, 0x22, 0x3c};
string EncryptionKey = "MYPASSWORD";
//basic serialization
IFormatter form = new BinaryFormatter();
var stream = new MemoryStream();
form.Serialize(stream, toSerialize);
//cryptography preparation
var alg = new RijndaelManaged();
var pdb = new Rfc2898DeriveBytes(EncryptionKey, SALT);
alg.Key = pdb.GetBytes(32);
alg.IV = pdb.GetBytes(16);
stream.Position = 0;
//cryptorgraphy serialization
var encStream = new MemoryStream();
var cryptoStream = new CryptoStream(encStream, alg.CreateEncryptor(), CryptoStreamMode.Write);
cryptoStream.Write(stream.ToArray(), 0, (int)stream.Length);
cryptoStream.FlushFinalBlock();
var outputFileStream = new FileStream(fileName, FileMode.Create);
outputFileStream.Write(encStream.ToArray(), 0, (int)encStream.Length);
outputFileStream.Close();
return true;
}
I can also put you sources to deserialize encrypted stream.

Encrypt an existing zip file

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.

Encrypting/Decrypting large files (.NET)

I have to encrypt, store and then later decrypt large files. What is the best way of doing that? I heard RSA encryption is expensive and was advised to use RSA to encrypt an AES key and then use the AES key to encrypt the large files. Any suggestions with example will be great.
One organism's large is another's petite, though we all know expensive when we see it. Wink, wink.
Try benchmarking something like the following in your environment and see where you're at:
EDIT 2/13/2012: The code has been updated as I've become (imperceptibly) smarter and also noticed a few cut'n'paste errors that had crept in. Mea culpa.
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
...
// Rfc2898DeriveBytes constants:
public readonly byte[] salt = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // Must be at least eight bytes. MAKE THIS SALTIER!
public const int iterations = 1042; // Recommendation is >= 1000.
/// <summary>Decrypt a file.</summary>
/// <remarks>NB: "Padding is invalid and cannot be removed." is the Universal CryptoServices error. Make sure the password, salt and iterations are correct before getting nervous.</remarks>
/// <param name="sourceFilename">The full path and name of the file to be decrypted.</param>
/// <param name="destinationFilename">The full path and name of the file to be output.</param>
/// <param name="password">The password for the decryption.</param>
/// <param name="salt">The salt to be applied to the password.</param>
/// <param name="iterations">The number of iterations Rfc2898DeriveBytes should use before generating the key and initialization vector for the decryption.</param>
public void DecryptFile(string sourceFilename, string destinationFilename, string password, byte[] salt, int iterations)
{
AesManaged aes = new AesManaged();
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
// NB: Rfc2898DeriveBytes initialization and subsequent calls to GetBytes must be eactly the same, including order, on both the encryption and decryption sides.
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, salt, iterations);
aes.Key = key.GetBytes(aes.KeySize / 8);
aes.IV = key.GetBytes(aes.BlockSize / 8);
aes.Mode = CipherMode.CBC;
ICryptoTransform transform = aes.CreateDecryptor(aes.Key, aes.IV);
using (FileStream destination = new FileStream(destinationFilename, FileMode.CreateNew, FileAccess.Write, FileShare.None))
{
using (CryptoStream cryptoStream = new CryptoStream(destination, transform, CryptoStreamMode.Write))
{
try
{
using (FileStream source = new FileStream(sourceFilename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
source.CopyTo(cryptoStream);
}
}
catch (CryptographicException exception)
{
if (exception.Message == "Padding is invalid and cannot be removed.")
throw new ApplicationException("Universal Microsoft Cryptographic Exception (Not to be believed!)", exception);
else
throw;
}
}
}
}
/// <summary>Encrypt a file.</summary>
/// <param name="sourceFilename">The full path and name of the file to be encrypted.</param>
/// <param name="destinationFilename">The full path and name of the file to be output.</param>
/// <param name="password">The password for the encryption.</param>
/// <param name="salt">The salt to be applied to the password.</param>
/// <param name="iterations">The number of iterations Rfc2898DeriveBytes should use before generating the key and initialization vector for the decryption.</param>
public void EncryptFile(string sourceFilename, string destinationFilename, string password, byte[] salt, int iterations)
{
AesManaged aes = new AesManaged();
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
// NB: Rfc2898DeriveBytes initialization and subsequent calls to GetBytes must be eactly the same, including order, on both the encryption and decryption sides.
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, salt, iterations);
aes.Key = key.GetBytes(aes.KeySize / 8);
aes.IV = key.GetBytes(aes.BlockSize / 8);
aes.Mode = CipherMode.CBC;
ICryptoTransform transform = aes.CreateEncryptor(aes.Key, aes.IV);
using (FileStream destination = new FileStream(destinationFilename, FileMode.CreateNew, FileAccess.Write, FileShare.None))
{
using (CryptoStream cryptoStream = new CryptoStream(destination, transform, CryptoStreamMode.Write))
{
using (FileStream source = new FileStream(sourceFilename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
source.CopyTo(cryptoStream);
}
}
}
}
This may help
/// Encrypts a file using Rijndael algorithm.
///</summary>
///<param name="inputFile"></param>
///<param name="outputFile"></param>
private 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
{
MessageBox.Show("Encryption failed!", "Error");
}
}
///
/// Decrypts a file using Rijndael algorithm.
///</summary>
///<param name="inputFile"></param>
///<param name="outputFile"></param>
private void DecryptFile(string inputFile, string outputFile)
{
{
string password = #"myKey123"; // Your Key Here
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
FileStream fsCrypt = new FileStream(inputFile, FileMode.Open);
RijndaelManaged RMCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateDecryptor(key, key),
CryptoStreamMode.Read);
FileStream fsOut = new FileStream(outputFile, FileMode.Create);
int data;
while ((data = cs.ReadByte()) != -1)
fsOut.WriteByte((byte)data);
fsOut.Close();
cs.Close();
fsCrypt.Close();
}
}
source:
http://www.codeproject.com/Articles/26085/File-Encryption-and-Decryption-in-C
Generally the strategy you have described is used when data will be encrypted on one machine (like a server) and then decrypted by another machine (client). The server will encrypt the data using symmetric key encryption (for performance) with a newly generated key and encrypt this symmetric key with a public key (matching a client's private key). The server sends the client both the encrypted data and the encrypted symmetric key. The client can decrypt the symmetric key with it's private key and then use this symmetric key for decrypting the data.
If you are encrypting and decrypting the data on the same machine it may not make sense to use both RSA and AES as you would not be trying to pass the encryption key to another machine.
Like you heard asymmetric cryptography, like RSA, is much slower than symmetric cryptography (e.g. AES) but it does have it's advantages (simpler key management, e.g. a single private key to protect).
The key (pun intended) is to use the advantages of both (private key of asymmetric and speed of symmetric) while ignoring the inconvenience of the other (many secret keys and slow speed).
You can do this by using RSA once per file (no huge performance impact) to encrypt a (symmetric) secret key that is used to encrypt (much faster) your large file. This *wrapping of the symmetric key allows you to only manage a single, private key.
Here's a link to my old (but still true) blog post that gives an example to do this using C# and the .NET framework (Microsoft of Mono).
RSA
It's true asymmetric cryptography (RSA, ECC, etc.) is slower than symmetric (AES, ChaCha20, etc). RSA and others are great for securing a random symmetric key (or establishing one). AES and others are great for efficient encryption, used along with integrity checking (HMAC).
Importantly, mature symmetric ciphers don't have any known theoretical weakness. Unless your attackers has the symmetric key, the encryption cannot be broken. Currently, all mature asymmetric cryptography (RSA, ECC) are based on mathematical properties that are vulnerable to being cracked by a future Quantum Computer (if it ever comes).
Also, handling of public/private keys becomes a problem. It's simple for a human to remember a password - their brain cannot be hacked. With public/private keys, they need to be stored somewhere. Particularly the private key is sensitive. Computers have TDM components that can create and store public/private keys separate to the CPU. This is very complicated to use.
So with that in mind, RSA should only be used if and when it's absolutely necessary.
AES
Here is a complete version I wrote recently, that returns the wrapping streamer, so you can use it however you need.
Also, this method generates IV from random generator instead of the password digestor. This is best practice, for example 7z does this - see https://crypto.stackexchange.com/questions/61945/is-it-ok-to-transmit-an-iv-as-a-custom-http-header. The IV is included in the header for the output.
Usage:
void Save()
{
var encryptedFilePath = Directory.GetCurrentDirectory() + "\\data.bin.aes";
using(var fileStream = File.Create(encryptedFilePath))
{
using (var cryptoStream = Security.FileEncryptor.CreateEncryptor(fileStream, passwordHere))
{
var formatter = new BinaryFormatter();
formatter.Serialize(cryptoStream, myObject);
cryptoStream.Flush();
}
}
}
void Load()
{
var encryptedFilePath = Directory.GetCurrentDirectory() + "\\data.bin.aes";
using(var fileStream = File.Open(encryptedFilePath, FileMode.Open))
{
using (var cryptoStream = Security.FileEncryptor.CreateDecryptor(fileStream, passwordHere))
{
var formatter = new BinaryFormatter();
var myObject = (myObjectType)formatter.Deserialize(cryptoStream);
}
}
}
Utility:
using System.IO;
using System.Security.Cryptography;
using System;
namespace Security
{
class FileEncryptor
{
public static Stream CreateEncryptor(Stream source, string password)
{
byte[] SaltBytes = new byte[16];
RandomNumberGenerator.Fill(SaltBytes); //RandomNumberGenerator is used for .Net Core 3
AesManaged aes = new AesManaged();
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, SaltBytes, iterations);
aes.Key = key.GetBytes(aes.KeySize / 8);
byte[] IVBytes = new byte[aes.BlockSize / 8];
RandomNumberGenerator.Fill(IVBytes); //RandomNumberGenerator is used for .Net Core 3
aes.IV = IVBytes;
aes.Mode = CipherMode.CBC;
ICryptoTransform transform = aes.CreateEncryptor(aes.Key, aes.IV);
//Store/Send the Salt and IV - this can be shared. It's more important that it's very random, than being private.
source.WriteByte((byte)SaltBytes.Length);
source.Write(SaltBytes, 0, SaltBytes.Length);
source.WriteByte((byte)IVBytes.Length);
source.Write(IVBytes, 0, IVBytes.Length);
source.Flush();
var cryptoStream = new CryptoStream(source, transform, CryptoStreamMode.Write);
return cryptoStream;
}
public static Stream CreateDecryptor(Stream source, string password)
{
var ArrayLength = source.ReadByte();
if (ArrayLength == -1) throw new Exception("Salt length not found");
byte[] SaltBytes = new byte[ArrayLength];
var readBytes = source.Read(SaltBytes, 0, ArrayLength);
if (readBytes != ArrayLength) throw new Exception("No support for multiple reads");
ArrayLength = source.ReadByte();
if (ArrayLength == -1) throw new Exception("Salt length not found");
byte[] IVBytes = new byte[ArrayLength];
readBytes = source.Read(IVBytes, 0, ArrayLength);
if (readBytes != ArrayLength) throw new Exception("No support for multiple reads");
AesManaged aes = new AesManaged();
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
aes.IV = IVBytes;
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, SaltBytes, iterations);
aes.Key = key.GetBytes(aes.KeySize / 8);
aes.Mode = CipherMode.CBC;
ICryptoTransform transform = aes.CreateDecryptor(aes.Key, aes.IV);
var cryptoStream = new CryptoStream(source, transform, CryptoStreamMode.Read);
return cryptoStream;
}
public const int iterations = 1042; // Recommendation is >= 1000.
}
}

Categories

Resources