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