SO, in Visual C#.NET I would like it to somehow be able to taken in a program (through an open file dialog), then somehow take the bytes of that program and encrypt the bytes, to be executed later.
How would I do that? How would I encrypt, then later decrypt, a program using Visual C#.NET?
This answer shows you how to execute a byte array. One caution, this may cause problems with virus scanners because it is common in malware.
If you don't want to execute from memory, I whipped up an example of how you could encrypt store then decrypt and run an executable.
public class FileEncryptRunner
{
Byte[] key = ASCIIEncoding.ASCII.GetBytes("thisisakeyzzzzzz");
Byte[] IV = ASCIIEncoding.ASCII.GetBytes("thisisadeltazzzz");
public void SaveEncryptedFile(string sourceFileName)
{
using (FileStream fStream = new FileStream(sourceFileName, FileMode.Open, FileAccess.Read, FileShare.Read),
outFStream = new FileStream(Environment.SpecialFolder.MyDocuments+"test.crp", FileMode.Create))
{
Rijndael RijndaelAlg = Rijndael.Create();
using (CryptoStream cStream = new CryptoStream(outFStream, RijndaelAlg.CreateEncryptor(key, IV), CryptoStreamMode.Write))
{
StreamWriter sWriter = new StreamWriter(cStream);
fStream.CopyTo(cStream);
}
}
}
public void ExecuteEncrypted()
{
using (FileStream fStream = new FileStream(Environment.SpecialFolder.MyDocuments + "test.crp", FileMode.Open, FileAccess.Read, FileShare.Read),
outFStream = new FileStream(Environment.SpecialFolder.MyDocuments + "crpTemp.exe", FileMode.Create))
{
Rijndael RijndaelAlg = Rijndael.Create();
using (CryptoStream cStream = new CryptoStream(fStream, RijndaelAlg.CreateDecryptor(key, IV), CryptoStreamMode.Read))
{ //Here you have a choice. If you want it to only ever exist decrypted in memory then you have to use the method in
// the linked answer.
//If you want to run it from a file than it's easy and you save the file and run it, this is simple.
cStream.CopyTo(outFStream);
}
}
Process.Start(Environment.SpecialFolder.MyDocuments + "crpTemp.exe");
}
}
Related
I'm trying to save a serialized object to an encrypted file. This isn't production quality and I am aware of the security risks with the way that I am doing this, but ignoring those I will have a key in a resource (data.Settings.key) that wont change and I have a salt that is also a constant.
My encryption seems to work, but decryption returns me an Exception saying that padding is invalid and cannot be closed when I try to close my CryptoStream.
private static byte[] decrypt(byte[] bytes)
{
var decryptor = algorithm.CreateDecryptor();
using (var sMemoryStream = new MemoryStream())
using (var sCryptoStream = new CryptoStream(sMemoryStream, decryptor, CryptoStreamMode.Write))
{
sCryptoStream.Write(bytes, 0, bytes.Length);
sCryptoStream.Close();
return sMemoryStream.ToArray();
}
}
The algorithm variable is the same one that the encrypt method uses and is built by this method which is called in the classes constructor:
private static SymmetricAlgorithm GetAlgorithm()
{
var algorithm = Rijndael.Create();
// Create key from salt and password in config
var rdb = new Rfc2898DeriveBytes(data.Settings.key, new byte[] {
0x44,0x61,0x79,0x6e,0x65,0x44,0x6f,0x75,0x67,0x61,0x6e
});
algorithm.Padding = PaddingMode.PKCS7;
// Set key and IV from rdb
algorithm.Key = rdb.GetBytes(32);
algorithm.IV = rdb.GetBytes(16);
return algorithm;
}
I've tried changing the padding mode in the algorithm but I can't understand why it's fine with this padding when encrypting, but now when decrypting.
If it helps here is the method that calls the decrypt method:
private static User OpenFile(String sUserName)
{
Console.WriteLine("Opening file...");
using (Stream sFileStream = new FileStream(data.Settings.dir + "data\\accounts\\" + sUserName + ".dat",
FileMode.Open, FileAccess.Read, FileShare.None))
using (Stream sMemoryStream = new MemoryStream())
{
// Read from File to memory stream
sFileStream.CopyTo(sMemoryStream);
// Decrypt data and store in new memory stream
byte[] bytes = new byte[sMemoryStream.Length];
Console.WriteLine("\tb:" + bytes.Length);
bytes = decrypt(bytes);
Console.WriteLine("\ta:" + bytes.Length);
Stream stream = new MemoryStream(bytes);
Console.WriteLine("\ts:" + bytes.Length);
// Deserialise memory stream and return as User object
User user = (User)bfFormatter.Deserialize(stream);
stream.Close();
return user;
}
}
This question already has answers here:
C# Encrypt serialized file before writing to disk
(4 answers)
Closed 5 years ago.
I use Serialize function to save an object to hard disk by the following code:
using (FileStream fs = new FileStream(fileName, FileMode.Create))
new BinaryFormatter().Serialize(fs, myObject);
Then I reload it again when I need it:
using(FileStream fs = new FileStream(fileName, FileMode.Open))
myObject = (Templates)new BinaryFormatter().Deserialize(fs);
I'm searching an easy way to encrypt the file I save to protect it and also fast way because the time factor in saving and reading the file is very important.
Any suggestions please, thank you in advance!
You're probably looking for something like this:
Aes aes = Aes.Create();
aes.Key = yourByteArrayKey;
aes.IV = yourByteArrayIV;
// Save
using (FileStream fs = new FileStream(fileName, FileMode.Create)) {
using (CryptoStream cs = new CryptoStream(fs, aes.CreateEncryptor(), CryptoStreamMode.Write)) {
new BinaryFormatter().Serialize(cs, myObject);
}
}
// Load
using (FileStream fs = new FileStream(fileName, FileMode.Open)) {
using (CryptoStream cs = new CryptoStream(fs, aes.CreateEncryptor(), CryptoStreamMode.Read)) {
myObject = (Templates)new BinaryFormatter().Deserialize(cs);
}
}
You can use any other algorithm as long as it can return an ICrytoTransform, like the aes.CreateEncryptor() method (which is inherited from SymmetricAlgorithm)
In VS2015, I would like to serialize a data table to a file, beginning at byte 16, since the file is to be encrypted and the IV uses the bytes 0-15. I have not yet found a serialization method taking an offset parameter, so should I convert the table to a byte array? There must be a cleaner approach. Here is one of the functions:
internal static void EncryptData(DataTable dTable, string userName, string password, string fileName)
{
using (FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
{
using (Aes aes = SetAes(userName, password)) // simply performs aes initialization
{
fs.Write(aes.IV, 0, 16); // writing the IV
using (CryptoStream cs = new CryptoStream(fs, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
dTable.WriteXml(cs, XmlWriteMode.WriteSchema); // This is overwriting the bytes 0-15 :(
}
}
}
}
EDIT: Adding deserialization function, which throws the exception "Length of the data to decrypt is invalid"
internal static void DecryptData(DataTable dTable, string userName, string password, string fileName)
{
using (FileStream fs = new FileStream(fileName, FileMode.Open))
{
byte[] IV = new byte[16];
fs.Read(IV, 0, 16);
using (Aes aes = SetAes(userName, password, IV)) // simply setting aes
{
using (CryptoStream cs = new CryptoStream(fs, aes.CreateDecryptor(), CryptoStreamMode.Read))
{
dTable.ReadXml(cs);
}
}
}
}
FINAL EDIT: The solution: Add IV bytes with File.WriteAllBytes and use FileStream filemode.Append in the serializing method(EncryptData):
using (Aes aes = SetAes(userName, password))
{
File.WriteAllBytes(fileName, aes.IV);
using (FileStream fs = new FileStream(fileName, FileMode.Append, FileAccess.Write, FileShare.None))
{
using (CryptoStream cs = new CryptoStream(fs, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
dTable.WriteXml(cs, XmlWriteMode.WriteSchema);
}
}
}
I want to write a C# class that can serialize, compress and encrypt objects, in that order. I need the resulting file to
Be created as fast as possible
Take as little space as possible
Be as unreadable as possible
I've been researching and coding for a while and this is what I have.
private void SaveObject(string path, object obj)
{
using (FileStream fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None))
{
string password = "123";
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
RijndaelManaged RMCrypto = new RijndaelManaged();
using (CryptoStream cryptoStream = new CryptoStream(fileStream, RMCrypto.CreateEncryptor(key, key), CryptoStreamMode.Write))
using (var gZipStream = new GZipStream(cryptoStream, CompressionMode.Compress))
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(gZipStream, obj);
}
}
}
private void LoadObject(string path, out object obj)
{
using (FileStream fileStream = new FileStream(path, FileMode.Open))
{
string password = "123";
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
RijndaelManaged RMCrypto = new RijndaelManaged();
using (CryptoStream cryptoStream = new CryptoStream(fileStream, RMCrypto.CreateDecryptor(key, key), CryptoStreamMode.Read))
using (var gZipStream = new GZipStream(cryptoStream, CompressionMode.Decompress))
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
obj = binaryFormatter.Deserialize(gZipStream);
}
}
}
I'm an amateur programmer and I have little knowledge about serialization, streams and encryption. I was even surprised this worked without a problem. My question is: Does this code follow the best programming practice and achieve the goals sufficiently without wasting time or resources?
Note: This is a generic method that I will use in my programs to store data locally.
take a look at https://github.com/HansHinnekint/EncryptionLib. The InfoBlockConvertor code of https://github.com/HansHinnekint/EncryptionLib/blob/master/EncryptionLibrary/InfoBlockConvertor.cs can be used as sample.
Only the compression needs to be added later on. That should not be that difficult.
I have the following C# code (code is inherited and can't compile it). This is used to decrypt and unzip a saved file.
using System.Security.Cryptography;
using System.Text;
using ICSharpCode.SharpZipLib.Zip;
//Not the real key but same amount of chars
private const string kEncyptionKey = "01234567";
public string DecryptAndDecompressText (string strFileName)
{
// Decryption ///
FileStream fin = null;
try
{
fin = new FileStream(strFileName, FileMode.Open, FileAccess.Read);
}
catch (System.IO.FileNotFoundException)
{
return "";
}
MemoryStream memoryToDecompress = new MemoryStream();
UnicodeEncoding UE = new UnicodeEncoding();
RijndaelManaged RMCrypto = new RijndaelManaged();
// This is the encryption key for our file
byte[] key = UE.GetBytes(kEncyptionKey);
// Decrypt the data to a stream
CryptoStream cs = new CryptoStream( memoryToDecompress,
RMCrypto.CreateDecryptor(key, key),
CryptoStreamMode.Write);
byte [] fileBuffer = new byte[fin.Length];
fin.Read(fileBuffer, 0, fileBuffer.Length);
cs.Write(fileBuffer, 0, fileBuffer.Length);
fin.Close();
// Reset the index of the Memory Stream
memoryToDecompress.Position = 0;
// Let the GC clean this up, we still need the memory stream
//cs.Close();
// Decompress the File
ZipInputStream s;
s = new ZipInputStream(memoryToDecompress);
ZipEntry theEntry;
try
{
theEntry = s.GetNextEntry();
}
catch (System.Exception)
{
// Could not open the file...
return "";
}
}
I'm trying to create a python program to do the same. This is what I've got:
from Crypto.Cipher import AES
KEY = '01234567'.encode('utf-16be')
_f = open('<file>', 'r')
_content = _f.read()
_cipher = AES.new(KEY, AES.MODE_CBC, KEY)
_dcontent = _cipher.decrypt(_content)
with open('extract.zip', 'w') as newfile:
newfile.write(_dcontent)
_f.close()
I'm writing the result to the disk since I expect it to be a zip file (which contains one file). However I can't open the file with Archive Manager.
Any suggestions are welcome!
You have to use the same key. System.Text.UnicodeEncoding is the UTF-16le encoding which also has an equivalent in python:
KEY = '01234567'.encode('utf-16le')
You have to read and write the files in binary mode if you're on Windows:
_f = open('<file>', 'rb')
...
open('extract.zip', 'wb')
You should use the proper zip file library. I am guessing that is something format specific that is failing on your write statement. Using this library should avoid such drawbacks. The open function can take a password as optional in case it is protected.