Add project files.

This commit is contained in:
Pablu23
2023-01-10 22:19:04 +01:00
parent 1cc52b0d1c
commit e52f241422
8 changed files with 691 additions and 0 deletions

13
.idea/.idea.EncryptFolder/.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,13 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/contentModel.xml
/modules.xml
/projectSettingsUpdater.xml
/.idea.EncryptFolder.iml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="com.jetbrains.rider.android.RiderAndroidMiscFileCreationComponent">
<option name="ENSURE_MISC_FILE_EXISTS" value="true" />
</component>
</project>

16
EncryptFolder.sln Normal file
View File

@@ -0,0 +1,16 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EncryptFolder", "EncryptFolder\EncryptFolder.csproj", "{EB82D4BD-71E7-4A0D-8183-AAE87EE293F8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EB82D4BD-71E7-4A0D-8183-AAE87EE293F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB82D4BD-71E7-4A0D-8183-AAE87EE293F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB82D4BD-71E7-4A0D-8183-AAE87EE293F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB82D4BD-71E7-4A0D-8183-AAE87EE293F8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

627
EncryptFolder/Program.cs Normal file
View File

@@ -0,0 +1,627 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace EncryptFolder
{
public static class Program
{
private static string _workDir = Directory.GetCurrentDirectory();
private static string _encryptFolder = Path.Combine(_workDir, "private");
private static string _password = "";
public static void Main()
{
if (Directory.Exists(_encryptFolder))
{
MenuDecrypt();
}
else
{
MenuEncrypt();
}
}
private static void MenuDecrypt()
{
Console.Write("Enter Password: ");
string? password = Console.ReadLine();
if (string.IsNullOrWhiteSpace(password))
{
Console.WriteLine("No password was Input.\nClosing Program...");
Environment.Exit(0);
}
_password = password;
StartDecryptProc();
}
private static void MenuEncrypt()
{
var files = Directory.GetFiles(_workDir).ToList();
// Get Path of Executable
// Exe File is supposed to be in the same Folder as the Files that should get encrypted,
// but should obviously not be encrypted itself
string? execPath = Environment.ProcessPath;
string? dllPath = Assembly.GetEntryAssembly()?.Location;
// If dll and or exe Path are in the files List, remove them.
// If not remove all exe and dll files for safety
if (!string.IsNullOrWhiteSpace(dllPath))
files.RemoveAll(x => x == dllPath);
if (string.IsNullOrWhiteSpace(execPath))
files.RemoveAll(f => Path.GetExtension(f) == "exe" || Path.GetExtension(f) == "dll");
else
files.RemoveAll(x => x == execPath);
foreach (string file in files)
{
Console.WriteLine(file);
}
Console.WriteLine("Are you sure you want to Encrypt these Files?\n[Y]es\n[N]o");
string? input = Console.ReadLine();
switch (input?.ToLower())
{
case "y" or "yes" or "j":
break;
case "n" or "no":
Console.WriteLine("Exiting...");
Environment.Exit(0);
break;
default:
Console.WriteLine("Wrong Input.\nClosing Program...");
Environment.Exit(0);
break;
}
Console.Write("Enter Password: ");
string? password = Console.ReadLine();
if (string.IsNullOrWhiteSpace(password))
{
Console.WriteLine("No password was Input.\nClosing Program...");
Environment.Exit(0);
}
_password = password;
StartEncryptProc(files.ToArray());
}
private static void StartEncryptProc(string[] files)
{
// Creates private Folder
Directory.CreateDirectory(_encryptFolder);
// Creates List for tasks that are going to be run
// Every file has its own Task
var tasks = new List<Task>();
for (int i = 0; i < files.Length; i++)
{
// Because of a racing condition and scoping issues the variables need to be set again here
// in order to work correctly
string file = files[i];
int index = i;
// Run the Encrypt Process and add the running task to the tasks list
tasks.Add(Task.Run(async () => await EncryptProc(file, index)));
}
try
{
var cancel = new CancellationTokenSource();
Task.Run(() => UpdateConsole(cancel.Token));
// Wait for all Tasks to complete
Task.WaitAll(tasks.ToArray());
// Cancel the UpdateConsole
cancel.Cancel();
}
catch (AggregateException ex)
{
foreach (var inner in ex.InnerExceptions)
{
Console.WriteLine($"Caught AggregateException in Task: " + inner.Message);
}
}
catch (Exception ex)
{
Console.WriteLine($"Caught Exception in Main: " + ex.Message);
}
}
private static Task EncryptProc(string path, int index)
{
// Obfuscate filename and add extension .enc
string fileName = $"{index}.enc";
// Create Path in the Private folder for storing of file
string newPath = Path.Combine(_encryptFolder, fileName);
// Creates 128 Bit Key from password
// And retrieves random Salt used for it
byte[] pwd = CreateKey(_password, out byte[] salt);
var fileInfo = new FileInfo(path);
bool withInfo = false;
if (fileInfo.Length >= 30_000_000)
{
withInfo = true;
}
byte[] pwdHash = CreateHash(pwd);
// Encrypt the File
EncryptFile(path, newPath, pwd, salt, pwdHash, withInfo);
// Delete the Unencrypted file
File.Delete(path);
return Task.CompletedTask;
}
private static void EncryptFile(string path, string outFile, byte[] key, byte[] salt, byte[] pwdHash, bool withInfo)
{
// Setup AES
var aes = Aes.Create();
aes.Key = key;
// Create Encryptor with the Key and the AES Genereratev IV
var transform = aes.CreateEncryptor(key, aes.IV);
// Gets IV Length in bit
int lIv = aes.IV.Length;
byte[] lenIV = BitConverter.GetBytes(lIv);
// Encrypt the Filename and get Length of Bytes
string fileName = Path.GetFileName(path);
byte[] name = EncryptString(key, aes.IV, fileName);
int lName = name.Length;
byte[] lenName = BitConverter.GetBytes(lName);
// Gets Salt Length
int lSalt = salt.Length;
byte[] lenSalt = BitConverter.GetBytes(lSalt);
// Gets PwdHash Length
int lHash = pwdHash.Length;
byte[] lenHash = BitConverter.GetBytes(lHash);
using (var outFs = new FileStream(outFile, FileMode.Create))
{
/*
* 0 - 3 = Byte IV Length
* 4 - 7 = Byte Name Length
* 8 - 11 = Salt Length
* 12 - 15 = Hash Length
* 16 - IV Length = IV
* IV Length - Name Length = Name Obfuscated
* Name Length - Salt Length = Salt
* Salt Length - Hash Length = Hash
*/
// Write the IV Length to Header
outFs.Write(lenIV, 0, 4);
// Write Filename Length to Header
outFs.Write(lenName, 0, 4);
// Write Salt Length to Header
outFs.Write(lenSalt, 0, 4);
// Write Hash Length to Header
outFs.Write(lenHash, 0, 4);
// After IV Length Bit
// Write the IV itself
outFs.Write(aes.IV, 0, lIv);
// Write the Filename (Encrypted)
outFs.Write(name, 0, lName);
// Write the Password Salt
outFs.Write(salt, 0, lSalt);
// Write teh Password Hash
outFs.Write(pwdHash, 0, lHash);
using (var outStreamEncrypted = new CryptoStream(outFs, transform, CryptoStreamMode.Write))
{
int count;
int offset = 0;
// BlockSizeBytes is arbitrary size
int blockSizeBytes = aes.BlockSize / 8;
byte[] data = new byte[blockSizeBytes];
using (var inFs = new FileStream(path, FileMode.Open))
{
// Go through every ByteBlock in File
do
{
long size = inFs.Length;
// Read bytes into data Array and set count to how many bytes were actually read
count = inFs.Read(data, 0, blockSizeBytes);
offset += count;
if (withInfo)
{
Info.AddOrUpdate(fileName, new Info() { BytesSize = size, BytesRead = offset, NewMessage = true }, (_, inf) =>
{
inf.BytesRead = offset;
inf.NewMessage = true;
return inf;
});
}
// Encrypt bytes and Write it to new File
outStreamEncrypted.Write(data, 0, count);
// As long as there are more bytes to be read
} while (count > 0);
}
// Needed, but dont know what it does
outStreamEncrypted.FlushFinalBlock();
}
}
}
private static void StartDecryptProc()
{
// Create task List
var tasks = new List<Task>();
// Get the remaining encrypted Files
var files = Directory.GetFiles(_encryptFolder).ToList();
files.RemoveAll(f => Path.GetExtension(f) != ".enc");
// Foreach encrypted File start a Task which decrypts that file
foreach (string file in files)
{
// Because of a racing condition and scoping issues the variable needs to be set again here
// in order to work correctly
string path = file;
tasks.Add(Task.Run(async () => await DecryptProc(path)));
}
try
{
var cancel = new CancellationTokenSource();
Task.Run(() => UpdateConsole(cancel.Token));
// Wait for all Tasks to complete
Task.WaitAll(tasks.ToArray());
cancel.Cancel();
// Delete the now unused Folder
Directory.Delete(_encryptFolder, false);
}
catch (AggregateException ex)
{
foreach (var inner in ex.InnerExceptions)
{
Console.WriteLine($"Caught AggregateException in Task: " + inner.Message);
}
}
catch (Exception ex)
{
Console.WriteLine($"Caught Exception in Main: " + ex.Message);
}
}
private static Task DecryptProc(string path)
{
var fileInfo = new FileInfo(path);
bool withInfo = false;
if (fileInfo.Length >= 30_000_000)
{
withInfo = true;
}
// Create shared FileStream
using (var fs = new FileStream(path, FileMode.Open))
{
// Get Header Metadata and Header Length
(int headerLen, int ivLen, int nameLen, int saltLen, int hashLen) = GetFileHeader(fs);
// Get Header Data and Point of where the Cipher starts
(int startCipher, byte[] iv, byte[] name, byte[] salt, byte[] hash) = GetHeaderData(fs, headerLen, ivLen, nameLen, saltLen, hashLen);
// Create 128 Bit (16 Byte) Key with Password and Salt
byte[] key = CreateKey(_password, salt);
byte[] generatedHash = CreateHash(key);
if (!generatedHash.SequenceEqual(hash))
throw new Exception("Password was incorrect");
// Decrypt the Filename
string fileName = DecryptString(key, iv, name);
// Create Output path
string outFile = Path.Combine(_workDir, fileName);
if (File.Exists(outFile))
{
outFile = Path.Combine(_workDir, Path.GetRandomFileName());
outFile = Path.ChangeExtension(outFile, Path.GetExtension(fileName));
}
// Decrypt File to output Path
DecryptFile(fs, outFile, startCipher, iv, key, withInfo);
}
// Delete the Encrypted File
File.Delete(path);
return Task.CompletedTask;
}
private static (int headerLen, int ivLen, int nameLen, int saltLen, int hashLen) GetFileHeader(FileStream inFs)
{
// lIV + lName + lSalt + lHash = 16
int headerLen = 16;
byte[] lIV = new byte[4];
byte[] lName = new byte[4];
byte[] lSalt = new byte[4];
byte[] lHash = new byte[4];
// Read IV Length
inFs.Seek(0, SeekOrigin.Begin);
inFs.Read(lIV, 0, 3);
// Read Filename Length
inFs.Seek(4, SeekOrigin.Begin);
inFs.Read(lName, 0, 3);
// Read Salt Length
inFs.Seek(8, SeekOrigin.Begin);
inFs.Read(lSalt, 0, 3);
inFs.Seek(12, SeekOrigin.Begin);
inFs.Read(lHash, 0, 3);
// Convert Byte to int Length
int ivLen = BitConverter.ToInt32(lIV, 0);
int nameLen = BitConverter.ToInt32(lName, 0);
int saltLen = BitConverter.ToInt32(lSalt, 0);
int hashLen = BitConverter.ToInt32(lHash, 0);
return (headerLen, ivLen, nameLen, saltLen, hashLen);
}
private static (int startCipher, byte[] iv, byte[] name, byte[] salt, byte[] pwdHash) GetHeaderData(FileStream inFs, int headerLen, int ivLen, int nameLen, int saltLen, int hashLen)
{
// Store IV
byte[] iv = new byte[ivLen];
inFs.Seek(headerLen, SeekOrigin.Begin);
inFs.Read(iv, 0, ivLen);
// Store Filename
byte[] name = new byte[nameLen];
inFs.Seek(headerLen + ivLen, SeekOrigin.Begin);
inFs.Read(name, 0, nameLen);
// Store Salt
byte[] salt = new byte[saltLen];
inFs.Seek(headerLen + ivLen + nameLen, SeekOrigin.Begin);
inFs.Read(salt, 0, saltLen);
byte[] hash = new byte[hashLen];
inFs.Seek(headerLen + ivLen + nameLen + saltLen, SeekOrigin.Begin);
inFs.Read(hash, 0, hashLen);
// Data starts after Header and Header Data
int startCipher = nameLen + ivLen + saltLen + hashLen + headerLen;
return (startCipher, iv, name, salt, hash);
}
private static void DecryptFile(FileStream inFs, string outFile, int startCipher, byte[] iv, byte[] key, bool withInfo)
{
// Setup Aes
using var aes = Aes.Create();
aes.Key = key;
//aes.Padding = PaddingMode.PKCS7;
// Create Decryptor with the Key and the IV
var transform = aes.CreateDecryptor(key, iv);
string name = Path.GetFileName(inFs.Name);
long size = inFs.Length;
using var outFs = new FileStream(outFile, FileMode.CreateNew);
using var outStreamDecrypted = new CryptoStream(outFs, transform, CryptoStreamMode.Write);
int count;
int overall = 0;
// Arbitrary Size
int blockSizeBytes = aes.BlockSize / 8;
byte[] data = new byte[blockSizeBytes];
// Set Stream position to starting Data Position
inFs.Seek(startCipher, SeekOrigin.Begin);
do
{
// Read Bytes into Data array and get read bytes
count = inFs.Read(data, 0, blockSizeBytes);
overall += count;
if (withInfo)
{
Info.AddOrUpdate(name, new Info() { BytesSize = size, BytesRead = overall, NewMessage = true }, (_, inf) =>
{
inf.BytesRead = overall;
inf.NewMessage = true;
return inf;
});
}
// Decrypts Bytes and writes them to the output file
outStreamDecrypted.Write(data, 0, count);
// As long as there are more Bytes to read
} while (count > 0);
// Dont know what this does but its needed
outStreamDecrypted.FlushFinalBlock();
}
private static byte[] EncryptString(byte[] key, byte[] iv, string input)
{
if (input == null || input.Length <= 0)
throw new ArgumentNullException(nameof(input));
if (key == null || key.Length <= 0)
throw new ArgumentNullException(nameof(key));
if (iv == null || iv.Length <= 0)
throw new ArgumentNullException(nameof(iv));
byte[] encrypted;
// Create an Aes object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = key;
aesAlg.IV = iv;
// Create an encryptor to perform the stream transform.
var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using var msEncrypt = new MemoryStream();
using var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
using (var swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(input);
}
encrypted = msEncrypt.ToArray();
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
private static string DecryptString(byte[] key, byte[] iv, byte[] input)
{
if (input == null || input.Length <= 0)
throw new ArgumentNullException(nameof(input));
if (key == null || key.Length <= 0)
throw new ArgumentNullException(nameof(key));
if (iv == null || iv.Length <= 0)
throw new ArgumentNullException(nameof(iv));
// Declare the string used to hold
// the decrypted text.
string plaintext;
// Create an Aes object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = key;
aesAlg.IV = iv;
// Create a decryptor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using MemoryStream msDecrypt = new MemoryStream(input);
using CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
return plaintext;
}
private static byte[] CreateHash(byte[] pwd)
{
using var hash = SHA256.Create();
return hash.ComputeHash(pwd);
}
private static byte[] GetSalt(int maximumSaltLength)
{
return RandomNumberGenerator.GetBytes(maximumSaltLength);
}
private const int Iterations = 300;
private static byte[] CreateKey(string password, out byte[] salt, int keyBytes = 16)
{
salt = GetSalt(32);
var keyGenerator = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(password), salt, Iterations);
return keyGenerator.GetBytes(keyBytes);
}
private static byte[] CreateKey(string password, byte[] salt, int keyBytes = 16)
{
var keyGenerator = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(password), salt, Iterations);
return keyGenerator.GetBytes(keyBytes);
}
private static readonly ConcurrentDictionary<string, Info> Info = new ConcurrentDictionary<string, Info>();
private static Task UpdateConsole(CancellationToken token)
{
(int _, int top) = Console.GetCursorPosition();
var mapping = new Dictionary<string, int>();
int highest = 0;
while (true)
{
if (token.IsCancellationRequested)
return Task.CompletedTask;
Thread.Sleep(1000);
foreach ((string? key, var value) in Info)
{
if (token.IsCancellationRequested)
return Task.CompletedTask;
if (!mapping.ContainsKey(key))
mapping.Add(key, highest += 1);
if (value.NewMessage)
{
double percent = (double) value.BytesRead / (double) value.BytesSize;
percent *= 100;
percent = Math.Round(percent, 2);
Console.SetCursorPosition(0, top + mapping[key]);
Console.WriteLine("[INFO] File {0,-30} {1,-5} % / 100 %", key, percent);
value.NewMessage = false;
}
}
}
}
}
public class Info
{
public long BytesSize { get; set; }
public int BytesRead { get; set; }
public bool NewMessage { get; set; }
}
}

7
global.json Normal file
View File

@@ -0,0 +1,7 @@
{
"sdk": {
"version": "6.0",
"rollForward": "latestMajor",
"allowPrerelease": true
}
}