SlunkCrypt/gui/Process/PasswordGen.cs

140 lines
4.9 KiB
C#
Raw Normal View History

/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;
namespace com.muldersoft.slunkcrypt.gui.process
{
public static class PasswordGen
{
private static readonly TimeSpan TIMEOUT_MSEC = TimeSpan.FromSeconds(90);
private const string COMMAND_PASSWRD = "-p {0:D}";
// =============================================================================
// Exception classes
// =============================================================================
public class GenerationFailedException : IOException
{
public GenerationFailedException(string message, Exception innerException) : base(message, innerException)
{
}
}
// =============================================================================
// Public methods
// =============================================================================
public static async Task<string> GeneratePassword(int length)
{
using (FileStream executableFile = ExecutableHelper.GetExecutableFile())
{
try
{
string password = await StartProcess(executableFile, length);
if (IsWeakPassword(password))
{
throw new InvalidDataException("The generated password string is invalid!");
}
return password;
}
catch (Exception e)
{
throw new GenerationFailedException("Failed to generate password string!", e);
}
}
}
public static bool IsWeakPassword(string password)
{
int flags = 0;
if (!string.IsNullOrEmpty(password))
{
foreach (char c in password)
{
if (char.IsLetter(c))
{
flags |= char.IsUpper(c) ? 0x2 : 0x1;
}
else
{
flags |= char.IsDigit(c) ? 0x8 : 0x4;
}
}
}
return (flags != 0xF);
}
// =============================================================================
// Internal methods
// =============================================================================
private static async Task<string> StartProcess(FileStream executableFile, int length)
{
using (Process process = new Process())
{
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.StandardOutputEncoding = Encoding.UTF8;
process.StartInfo.FileName = executableFile.Name;
process.StartInfo.Arguments = string.Format(COMMAND_PASSWRD, length);
process.Start();
Stack<string> outputLines = await WaitForExit(process, TIMEOUT_MSEC);
if (process.ExitCode == 0)
{
while (outputLines.Count > 0)
{
string line = outputLines.Pop();
if (line.Length >= length)
{
return line;
}
}
}
return string.Empty;
}
}
private static async Task<Stack<string>> WaitForExit(Process process, TimeSpan timeout)
{
Task<Stack<string>> readTask;
await Task.WhenAny(readTask = Task.Run(() => ReadOutput(process)), Task.Delay(timeout));
if (!process.WaitForExit(125))
{
process.Kill();
process.WaitForExit();
}
return await readTask;
}
private static Stack<string> ReadOutput(Process process)
{
Stack<string> result = new Stack<string>();
using (StreamReader reader = process.StandardOutput)
{
string line;
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (line.Length != 0)
{
result.Push(line.Trim());
}
}
}
return result;
}
}
}