You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

263 lines
9.9 KiB

using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace ndpack
{
class Program
{
static Task<string> ReadPassword(string prompt = null, CancellationToken token = default)
{
TaskCompletionSource<string> comp = new TaskCompletionSource<string>();
List<char> pwd = new List<char>();
bool set = false;
_ = Task.Run(() =>
{
if (prompt != null)
Console.Write(prompt);
try
{
using var _c = token.Register(() =>
{
if (!set)
{
set = true;
comp.SetException(new OperationCanceledException());
}
});
while (true)
{
ConsoleKeyInfo i = Console.ReadKey(true);
if (token.IsCancellationRequested) break;
if (i.Key == ConsoleKey.Enter)
{
Console.WriteLine();
break;
}
else if (i.Key == ConsoleKey.Backspace)
{
if (pwd.Count > 0)
{
pwd.RemoveAt(pwd.Count - 1);
}
}
else if (i.KeyChar != '\u0000')
{
pwd.Add(i.KeyChar);
}
}
if (!set)
{
set = true;
if (token.IsCancellationRequested)
comp.SetException(new OperationCanceledException());
else
comp.SetResult(new string(pwd.ToArray()));
}
}
catch (Exception ex)
{
Console.WriteLine();
pwd.Clear();
if (!set)
{
set = true;
comp.SetException(ex);
}
}
});
return comp.Task;
}
static void usage()
{
Console.WriteLine("Usage: ndpack -c <dump file> <images directory> <output file>");
Console.WriteLine("Usage: ndpack -e <dump file> <images directory> <key> <output file>");
Console.WriteLine("Usage: ndpack -u <archive> <output dir>");
Console.WriteLine("Usage: ndpack -d <archive encrypted> <key file> <output dir>");
}
static async Task CopyDirectory(string SourcePath, string DestinationPath)
{
Exception bad = null;
await Task.Run(() =>
{
try
{
//Now Create all of the directories
foreach (string dirPath in Directory.GetDirectories(SourcePath, "*",
SearchOption.AllDirectories))
Directory.CreateDirectory(dirPath.Replace(SourcePath, DestinationPath));
//Copy all the files & Replaces any files with the same name
foreach (string newPath in Directory.GetFiles(SourcePath, "*",
SearchOption.AllDirectories))
File.Copy(newPath, newPath.Replace(SourcePath, DestinationPath), true);
}catch(Exception ex)
{
bad = ex;
}
});
if (bad != null) throw bad;
}
static async Task create(string output, string dumpf, string dirf)
{
FastZip fs = new FastZip();
using var tdir = new TempDirectory();
await Task.Yield();
Console.WriteLine("Copying dump...");
File.Copy(dumpf, Path.Combine(tdir.Directory.FullName, Path.GetFileName(dumpf)));
Console.WriteLine($"Copying images...");
var ipath = Path.Combine(tdir.Directory.FullName, new DirectoryInfo(dirf).Name);
Directory.CreateDirectory(ipath);
await CopyDirectory(dirf, ipath);
await Task.Yield();
fs.CreateZip(output, tdir.Directory.FullName, true, null, null);
}
static async Task unpack(string inputArchive, string outputDir)
{
if (!Directory.Exists(outputDir))
Directory.CreateDirectory(outputDir);
var fs = new FastZip();
await Task.Yield();
fs.ExtractZip(inputArchive, outputDir, null);
}
static async Task decrypt(string inf, string of, string kf, Func<Task<string>> password)
{
using var infs = new FileStream(inf, FileMode.Open, FileAccess.Read);
using var enc = new encaes.AesEncryptor(infs);
using (var kfs = new FileStream(kf, FileMode.Open, FileAccess.Read))
{
enc.Key = await encaes.AesEncryptor.LoadKey(kfs, () =>
{
var tsk = password();
tsk.Wait();
if (tsk.IsFaulted)
throw tsk.Exception;
else return tsk.Result;
});
}
using var ofs = new FileStream(of, FileMode.Create);
await enc.Decrypt(ofs);
}
static async Task encrypt(string inf, string outf, string kf, Func<Task<string>> password)
{
using var infs = new FileStream(inf, FileMode.Open, FileAccess.Read);
using var enc = new encaes.AesEncryptor(infs);
using (var kfs = new FileStream(kf, FileMode.Open, FileAccess.Read))
{
enc.Key = await encaes.AesEncryptor.LoadKey(kfs, () =>
{
var tsk = password();
tsk.Wait();
if (tsk.IsFaulted)
throw tsk.Exception;
else return tsk.Result;
});
}
using (var ofs = new FileStream(outf, FileMode.Create))
{
await enc.Encrypt(ofs);
}
}
static async Task Main(string[] args)
{
if (args.Length < 3)
{
usage();
return;
}
else
{
switch (args[0].ToLower())
{
case "-c":
if (args.Length < 4)
{
usage();
return;
}
try
{
await create(args[3], args[1], args[2]);
}
catch (Exception ex)
{
Console.WriteLine("Error creating: " + ex.Message);
}
break;
case "-e":
if(args.Length<5)
{
usage();
return;
}
try
{
string realOutput = args[4];
using var tf = TempFile.WithNoStream();
await create(tf.File.FullName, args[1], args[2]);
Console.WriteLine("Encrypting...");
await encrypt(tf.File.FullName, realOutput, args[3], async () =>
{
return await ReadPassword("Password: ");
});
}
catch (Exception ex)
{
Console.WriteLine("Error creating: " + ex.Message);
}
break;
case "-u":
try
{
Console.WriteLine("Unpacking...");
await unpack(args[1], args[2]);
}
catch (Exception ex)
{
Console.WriteLine("Error unpacking: " + ex.Message);
}
break;
case "-d":
if (args.Length < 4)
{
usage();
return;
}
try
{
using var arcfs = TempFile.WithNoStream();
Console.WriteLine("Decrypting...");
await decrypt(args[1], arcfs.File.FullName, args[2], async () =>
{
return await ReadPassword("Password: ");
});
Console.WriteLine("Unpacking...");
await unpack(arcfs.File.FullName, args[3]);
}
catch (Exception ex)
{
Console.WriteLine("Error unpacking: " + ex.Message);
}
break;
default:
usage();
return;
}
}
}
}
}