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