WingMan – Diff between revs 34 and 36

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 34 Rev 36
1 using System.IO; 1 using System.IO;
2 using System.Linq; 2 using System.Linq;
3 using System.Security.Cryptography; 3 using System.Security.Cryptography;
4 using System.Text; -  
5 using System.Threading.Tasks; 4 using System.Threading.Tasks;
6   5  
7 namespace WingMan.Utilities 6 namespace WingMan.Utilities
8 { 7 {
9 public static class AES 8 public static class Aes
10 { 9 {
-   10 private const int AesKeySize = 256;
11 private const int AesKeyIterations = 4096; 11 private const int AesKeyIterations = 4096;
12 private const int AesBlockSize = 128; 12 private const int AesBlockSize = 128;
13 private const CipherMode AesCipherMode = CipherMode.CBC; 13 private const CipherMode AesCipherMode = CipherMode.CBC;
14 private const PaddingMode AesPaddingMode = PaddingMode.PKCS7; 14 private const PaddingMode AesPaddingMode = PaddingMode.PKCS7;
15 private const int AesKeySaltBytes = 16; 15 private const int AesKeySaltBytes = 16;
16 private static readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider(); 16 private static readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider();
17   17  
18 /////////////////////////////////////////////////////////////////////////// 18 ///////////////////////////////////////////////////////////////////////////
19 // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // 19 // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
20 /////////////////////////////////////////////////////////////////////////// 20 ///////////////////////////////////////////////////////////////////////////
21 /// <summary> 21 /// <summary>
22 /// Encrypts an input stream given a key and initialization vector. 22 /// Encrypts an input stream given a key and initialization vector.
23 /// </summary> 23 /// </summary>
24 /// <param name="inputStream">the stream to encrypt</param> 24 /// <param name="inputStream">the stream to encrypt</param>
25 /// <param name="key">the encryption key</param> 25 /// <param name="key">the encryption key</param>
26 /// <returns>an encrypted stream containing the salt and the data</returns> 26 /// <returns>an encrypted stream containing the salt and the data</returns>
27 public static async Task<MemoryStream> Encrypt(Stream inputStream, string key) 27 public static async Task<MemoryStream> Encrypt(Stream inputStream, string key)
28 { 28 {
29 var outputStream = new MemoryStream(); 29 var outputStream = new MemoryStream();
30   30  
31 using (var rijdanelManaged = new RijndaelManaged()) 31 using (var aesManaged = new AesManaged())
32 { 32 {
33 // FIPS-197 / CBC 33 // FIPS-197 / CBC
34 rijdanelManaged.BlockSize = AesBlockSize; 34 aesManaged.BlockSize = AesBlockSize;
35 rijdanelManaged.Mode = AesCipherMode; 35 aesManaged.Mode = AesCipherMode;
-   36 aesManaged.Padding = AesPaddingMode;
36 rijdanelManaged.Padding = AesPaddingMode; 37 aesManaged.KeySize = AesKeySize;
37   38  
38 // Compute the salt and the IV from the key. 39 // Compute the salt and the IV from the key.
39 var salt = new byte[AesKeySaltBytes]; 40 var salt = new byte[AesKeySaltBytes];
40 Rng.GetBytes(salt); 41 Rng.GetBytes(salt);
41 var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations); 42 var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations);
42 rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); 43 aesManaged.Key = derivedKey.GetBytes(aesManaged.KeySize / 8);
43 rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); 44 aesManaged.IV = derivedKey.GetBytes(aesManaged.BlockSize / 8);
44   45  
45 using (var encryptor = rijdanelManaged.CreateEncryptor(rijdanelManaged.Key, rijdanelManaged.IV)) 46 using (var encryptor = aesManaged.CreateEncryptor(aesManaged.Key, aesManaged.IV))
46 { 47 {
47 using (var memoryStream = new MemoryStream()) 48 using (var memoryStream = new MemoryStream())
48 { 49 {
49 using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) 50 using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
50 { 51 {
51 await inputStream.CopyToAsync(cryptoStream); 52 await inputStream.CopyToAsync(cryptoStream);
52 cryptoStream.FlushFinalBlock(); 53 cryptoStream.FlushFinalBlock();
53   54  
54 memoryStream.Position = 0L; 55 memoryStream.Position = 0L;
55   56  
56 await outputStream.WriteAsync(salt, 0, AesKeySaltBytes); 57 await outputStream.WriteAsync(salt, 0, AesKeySaltBytes);
57 await memoryStream.CopyToAsync(outputStream); 58 await memoryStream.CopyToAsync(outputStream);
58   59  
59 outputStream.Position = 0L; 60 outputStream.Position = 0L;
60   61  
61 return outputStream; 62 return outputStream;
62 } 63 }
63 } 64 }
64 } 65 }
65 } 66 }
66 } 67 }
67   68  
68 /////////////////////////////////////////////////////////////////////////// 69 ///////////////////////////////////////////////////////////////////////////
69 // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // 70 // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
70 /////////////////////////////////////////////////////////////////////////// 71 ///////////////////////////////////////////////////////////////////////////
71 /// <summary> 72 /// <summary>
72 /// Encrypts a byte array given a key and initialization vector. 73 /// Encrypts a byte array given a key and initialization vector.
73 /// </summary> 74 /// </summary>
74 /// <param name="data">the byte array to encrypt</param> 75 /// <param name="data">the byte array to encrypt</param>
75 /// <param name="key">the encryption key</param> 76 /// <param name="key">the encryption key</param>
76 /// <returns>an encrypted byte array</returns> 77 /// <returns>an encrypted byte array</returns>
77 public static async Task<byte[]> Encrypt(byte[] data, string key) 78 public static async Task<byte[]> Encrypt(byte[] data, string key)
78 { 79 {
79 using (var rijdanelManaged = new RijndaelManaged()) 80 using (var aesManaged = new AesManaged())
80 { 81 {
81 // FIPS-197 / CBC 82 // FIPS-197 / CBC
82 rijdanelManaged.BlockSize = AesBlockSize; 83 aesManaged.BlockSize = AesBlockSize;
83 rijdanelManaged.Mode = AesCipherMode; 84 aesManaged.Mode = AesCipherMode;
84 rijdanelManaged.Padding = AesPaddingMode; 85 aesManaged.Padding = AesPaddingMode;
-   86 aesManaged.KeySize = AesKeySize;
85   87  
86 // Compute the salt and the IV from the key. 88 // Compute the salt and the IV from the key.
87 var salt = new byte[AesKeySaltBytes]; 89 var salt = new byte[AesKeySaltBytes];
88 Rng.GetBytes(salt); 90 Rng.GetBytes(salt);
89 var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations); 91 var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations);
90 rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); 92 aesManaged.Key = derivedKey.GetBytes(aesManaged.KeySize / 8);
91 rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); 93 aesManaged.IV = derivedKey.GetBytes(aesManaged.BlockSize / 8);
92   94  
93 using (var encryptor = rijdanelManaged.CreateEncryptor(rijdanelManaged.Key, rijdanelManaged.IV)) 95 using (var encryptor = aesManaged.CreateEncryptor(aesManaged.Key, aesManaged.IV))
94 { 96 {
95 using (var memoryStream = new MemoryStream()) 97 using (var memoryStream = new MemoryStream())
96 { 98 {
97 using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) 99 using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
98 { 100 {
99 using (var inputStream = new MemoryStream(data)) 101 using (var inputStream = new MemoryStream(data))
100 { 102 {
101 await inputStream.CopyToAsync(cryptoStream); 103 await inputStream.CopyToAsync(cryptoStream);
102 cryptoStream.FlushFinalBlock(); 104 cryptoStream.FlushFinalBlock();
103   105  
104 memoryStream.Position = 0L; 106 memoryStream.Position = 0L;
105   107  
106 return salt.Concat(memoryStream.ToArray()).ToArray(); 108 return salt.Concat(memoryStream.ToArray()).ToArray();
107 } 109 }
108 } 110 }
109 } 111 }
110 } 112 }
111 } 113 }
112 } 114 }
113   115  
114 /////////////////////////////////////////////////////////////////////////// 116 ///////////////////////////////////////////////////////////////////////////
115 // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // 117 // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
116 /////////////////////////////////////////////////////////////////////////// 118 ///////////////////////////////////////////////////////////////////////////
117 /// <summary> 119 /// <summary>
118 /// Decrypts a byte array using a salt and a key. 120 /// Decrypts a byte array using a salt and a key.
119 /// </summary> 121 /// </summary>
120 /// <param name="inputStream">a salt and data stream to decrypt</param> 122 /// <param name="inputStream">a salt and data stream to decrypt</param>
121 /// <param name="key">the encryption key</param> 123 /// <param name="key">the encryption key</param>
122 /// <returns>a memory stream containing the decrypted data</returns> 124 /// <returns>a memory stream containing the decrypted data</returns>
123 public static async Task<MemoryStream> Decrypt(Stream inputStream, string key) 125 public static async Task<MemoryStream> Decrypt(Stream inputStream, string key)
124 { 126 {
125 var outputStream = new MemoryStream(); 127 var outputStream = new MemoryStream();
126   128  
127 var salt = new byte[AesKeySaltBytes]; 129 var salt = new byte[AesKeySaltBytes];
128 await inputStream.ReadAsync(salt, 0, AesKeySaltBytes); 130 await inputStream.ReadAsync(salt, 0, AesKeySaltBytes);
129   131  
130 var text = new byte[inputStream.Length - AesKeySaltBytes]; 132 var text = new byte[inputStream.Length - AesKeySaltBytes];
131 await inputStream.ReadAsync(text, 0, (int) (inputStream.Length - AesKeySaltBytes)); 133 await inputStream.ReadAsync(text, 0, (int) (inputStream.Length - AesKeySaltBytes));
132   134  
133 //var salt = data.Take(AesKeySaltBytes).ToArray(); 135 //var salt = data.Take(AesKeySaltBytes).ToArray();
134 //var text = data.Skip(AesKeySaltBytes).ToArray(); 136 //var text = data.Skip(AesKeySaltBytes).ToArray();
135   137  
136 using (var rijdanelManaged = new RijndaelManaged()) 138 using (var aesManaged = new AesManaged())
137 { 139 {
138 // FIPS-197 / CBC 140 // FIPS-197 / CBC
139 rijdanelManaged.BlockSize = AesBlockSize; 141 aesManaged.BlockSize = AesBlockSize;
140 rijdanelManaged.Mode = AesCipherMode; 142 aesManaged.Mode = AesCipherMode;
-   143 aesManaged.Padding = AesPaddingMode;
141 rijdanelManaged.Padding = AesPaddingMode; 144 aesManaged.KeySize = AesKeySize;
142   145  
143 // Retrieve the key and the IV from the salt. 146 // Retrieve the key and the IV from the salt.
144 var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations); 147 var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations);
145 rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); 148 aesManaged.Key = derivedKey.GetBytes(aesManaged.KeySize / 8);
146 rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); 149 aesManaged.IV = derivedKey.GetBytes(aesManaged.BlockSize / 8);
147   150  
148 using (var decryptor = rijdanelManaged.CreateDecryptor(rijdanelManaged.Key, rijdanelManaged.IV)) 151 using (var decryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.IV))
149 { 152 {
150 using (var memoryStream = new MemoryStream(text)) 153 using (var memoryStream = new MemoryStream(text))
151 { 154 {
152 using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) 155 using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
153 { 156 {
154 await cryptoStream.CopyToAsync(outputStream); 157 await cryptoStream.CopyToAsync(outputStream);
155   158  
156 outputStream.Position = 0L; 159 outputStream.Position = 0L;
157   160  
158 return outputStream; 161 return outputStream;
159 } 162 }
160 } 163 }
161 } 164 }
162 } 165 }
163 } 166 }
164   167  
165 /////////////////////////////////////////////////////////////////////////// 168 ///////////////////////////////////////////////////////////////////////////
166 // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // 169 // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
167 /////////////////////////////////////////////////////////////////////////// 170 ///////////////////////////////////////////////////////////////////////////
168 /// <summary> 171 /// <summary>
169 /// Decrypts a byte array using a salt and a key. 172 /// Decrypts a byte array using a salt and a key.
170 /// </summary> 173 /// </summary>
171 /// <param name="data">a salt and data byte array to decrypt</param> 174 /// <param name="data">a salt and data byte array to decrypt</param>
172 /// <param name="key">the encryption key</param> 175 /// <param name="key">the encryption key</param>
173 /// <returns>a byte array containing the decrypted data</returns> 176 /// <returns>a byte array containing the decrypted data</returns>
174 public static async Task<byte[]> Decrypt(byte[] data, string key) 177 public static async Task<byte[]> Decrypt(byte[] data, string key)
175 { 178 {
176 var salt = data.Take(AesKeySaltBytes).ToArray(); 179 var salt = data.Take(AesKeySaltBytes).ToArray();
177 var text = data.Skip(AesKeySaltBytes).ToArray(); 180 var text = data.Skip(AesKeySaltBytes).ToArray();
178   181  
179 using (var rijdanelManaged = new RijndaelManaged()) 182 using (var aesManaged = new AesManaged())
180 { 183 {
181 // FIPS-197 / CBC 184 // FIPS-197 / CBC
182 rijdanelManaged.BlockSize = AesBlockSize; 185 aesManaged.BlockSize = AesBlockSize;
183 rijdanelManaged.Mode = AesCipherMode; 186 aesManaged.Mode = AesCipherMode;
-   187 aesManaged.Padding = AesPaddingMode;
184 rijdanelManaged.Padding = AesPaddingMode; 188 aesManaged.KeySize = AesKeySize;
185   189  
186 // Retrieve the key and the IV from the salt. 190 // Retrieve the key and the IV from the salt.
187 var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations); 191 var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations);
188 rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); 192 aesManaged.Key = derivedKey.GetBytes(aesManaged.KeySize / 8);
189 rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); 193 aesManaged.IV = derivedKey.GetBytes(aesManaged.BlockSize / 8);
190   194  
191 using (var decryptor = rijdanelManaged.CreateDecryptor(rijdanelManaged.Key, rijdanelManaged.IV)) 195 using (var decryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.IV))
192 { 196 {
193 using (var memoryStream = new MemoryStream(text)) 197 using (var memoryStream = new MemoryStream(text))
194 { 198 {
195 using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) 199 using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
196 { 200 {
197 using (var outputStream = new MemoryStream()) 201 using (var outputStream = new MemoryStream())
198 { 202 {
199 await cryptoStream.CopyToAsync(outputStream); 203 await cryptoStream.CopyToAsync(outputStream);
200   204  
201 outputStream.Position = 0L; 205 outputStream.Position = 0L;
202   206  
203 return outputStream.ToArray(); 207 return outputStream.ToArray();
204 } 208 }
205 } 209 }
206 } 210 }
207 } 211 }
208 } 212 }
209 } 213 }
210   214  
211 public static string ExpandKey(string password, int size = 32) 215 public static string ExpandKey(string password, int length = 32)
212 { 216 {
213 var sb = new StringBuilder(password); -  
214 do -  
215 { 217 if (length <= password.Length) return password.Substring(0, length);
216 sb.Append(password); 218 while (password.Length * 2 <= length) password += password;
217 } while (sb.Length < size); -  
218   219 if (password.Length < length) password += password.Substring(0, length - password.Length);
219 return sb.ToString(0, size); 220 return password;
220 } 221 }
221 } 222 }
222 } 223 }
223   224