OSDN Git Service

9592b0fd2ef7baa57d9963179de7a14e8a48b8cd
[slunkcrypt/SlunkCrypt.git] / gui / Process / PasswordGen.cs
1 /******************************************************************************/
2 /* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de>                                */
3 /* This work has been released under the CC0 1.0 Universal license!           */
4 /******************************************************************************/
5
6 using System;
7 using System.Collections.Generic;
8 using System.Diagnostics;
9 using System.IO;
10 using System.Text;
11 using System.Threading.Tasks;
12
13 namespace com.muldersoft.slunkcrypt.gui.process
14 {
15     public static class PasswordGen
16     {
17         private static readonly TimeSpan TIMEOUT_MSEC = TimeSpan.FromSeconds(90);
18
19         private const string COMMAND_PASSWRD = "-p {0:D}";
20
21         // =============================================================================
22         // Exception classes
23         // =============================================================================
24
25         public class GenerationFailedException : IOException
26         {
27             public GenerationFailedException(string message, Exception innerException) : base(message, innerException)
28             {
29             }
30         }
31
32         // =============================================================================
33         // Public methods
34         // =============================================================================
35
36         public static async Task<string> GeneratePassword(int length)
37         {
38             using (FileStream executableFile = ExecutableHelper.GetExecutableFile())
39             {
40                 try
41                 {
42                     string password = await StartProcess(executableFile, length);
43                     if (IsWeakPassword(password))
44                     {
45                         throw new InvalidDataException("The generated password string is invalid!");
46                     }
47                     return password;
48                 }
49                 catch (Exception e)
50                 {
51                     throw new GenerationFailedException("Failed to generate password string!", e);
52                 }
53             }
54         }
55
56         public static bool IsWeakPassword(string password)
57         {
58             int flags = 0;
59             if (!string.IsNullOrEmpty(password))
60             {
61                 foreach (char c in password)
62                 {
63                     if (char.IsLetter(c))
64                     {
65                         flags |= char.IsUpper(c) ? 0x2 : 0x1;
66                     }
67                     else
68                     {
69                         flags |= char.IsDigit(c) ? 0x8 : 0x4;
70                     }
71                 }
72             }
73             return (flags != 0xF);
74         }
75
76         // =============================================================================
77         // Internal methods
78         // =============================================================================
79
80         private static async Task<string> StartProcess(FileStream executableFile, int length)
81         {
82             using (Process process = new Process())
83             {
84                 process.StartInfo.UseShellExecute = false;
85                 process.StartInfo.CreateNoWindow = true;
86                 process.StartInfo.RedirectStandardOutput = true;
87                 process.StartInfo.StandardOutputEncoding = Encoding.UTF8;
88                 process.StartInfo.FileName = executableFile.Name;
89                 process.StartInfo.Arguments = string.Format(COMMAND_PASSWRD, length);
90                 process.Start();
91
92                 Stack<string> outputLines = await WaitForExit(process, TIMEOUT_MSEC);
93
94                 if (process.ExitCode == 0)
95                 {
96                     while (outputLines.Count > 0)
97                     {
98                         string line = outputLines.Pop();
99                         if (line.Length >= length)
100                         {
101                             return line;
102                         }
103                     }
104                 }
105                 return string.Empty;
106             }
107         }
108
109         private static async Task<Stack<string>> WaitForExit(Process process, TimeSpan timeout)
110         {
111             Task<Stack<string>> readTask;
112             await Task.WhenAny(readTask = Task.Run(() => ReadOutput(process)), Task.Delay(timeout));
113             if (!process.WaitForExit(125))
114             {
115                 process.Kill();
116                 process.WaitForExit();
117             }
118             return await readTask;
119         }
120
121         private static Stack<string> ReadOutput(Process process)
122         {
123             Stack<string> result = new Stack<string>();
124             using (StreamReader reader = process.StandardOutput)
125             {
126                 string line;
127                 while ((line = reader.ReadLine()) != null)
128                 {
129                     line = line.Trim();
130                     if (line.Length != 0)
131                     {
132                         result.Push(line.Trim());
133                     }
134                 }
135             }
136             return result;
137         }
138     }
139 }