Hush – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | using System.IO; |
2 | using System.Linq; |
||
3 | using System.Security.Cryptography; |
||
4 | using System.Threading.Tasks; |
||
5 | |||
6 | namespace Hush.Utilities |
||
7 | { |
||
8 | public static class Aes |
||
9 | { |
||
10 | private const int AesKeySize = 256; |
||
11 | private const int AesKeyIterations = 4096; |
||
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> |
||
22 | /// Encrypts an input stream given a key and initialization vector. |
||
23 | /// </summary> |
||
24 | /// <param name="inputStream">the stream to encrypt</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 aesManaged = new AesManaged()) |
||
32 | { |
||
33 | // FIPS-197 / CBC |
||
34 | aesManaged.BlockSize = AesBlockSize; |
||
35 | aesManaged.Mode = AesCipherMode; |
||
36 | aesManaged.Padding = AesPaddingMode; |
||
37 | aesManaged.KeySize = AesKeySize; |
||
38 | |||
39 | // Compute the salt and the IV from the key. |
||
40 | var salt = new byte[AesKeySaltBytes]; |
||
41 | Rng.GetBytes(salt); |
||
42 | var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations); |
||
43 | aesManaged.Key = derivedKey.GetBytes(aesManaged.KeySize / 8); |
||
44 | aesManaged.IV = derivedKey.GetBytes(aesManaged.BlockSize / 8); |
||
45 | |||
46 | using (var encryptor = aesManaged.CreateEncryptor(aesManaged.Key, aesManaged.IV)) |
||
47 | { |
||
48 | using (var memoryStream = new MemoryStream()) |
||
49 | { |
||
50 | using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) |
||
51 | { |
||
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 | { |
||
80 | using (var aesManaged = new AesManaged()) |
||
81 | { |
||
82 | // FIPS-197 / CBC |
||
83 | aesManaged.BlockSize = AesBlockSize; |
||
84 | aesManaged.Mode = AesCipherMode; |
||
85 | aesManaged.Padding = AesPaddingMode; |
||
86 | aesManaged.KeySize = AesKeySize; |
||
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); |
||
92 | aesManaged.Key = derivedKey.GetBytes(aesManaged.KeySize / 8); |
||
93 | aesManaged.IV = derivedKey.GetBytes(aesManaged.BlockSize / 8); |
||
94 | |||
95 | using (var encryptor = aesManaged.CreateEncryptor(aesManaged.Key, aesManaged.IV)) |
||
96 | { |
||
97 | using (var memoryStream = new MemoryStream()) |
||
98 | { |
||
99 | using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) |
||
100 | { |
||
101 | using (var inputStream = new MemoryStream(data)) |
||
102 | { |
||
103 | await inputStream.CopyToAsync(cryptoStream); |
||
104 | cryptoStream.FlushFinalBlock(); |
||
105 | |||
106 | memoryStream.Position = 0L; |
||
107 | |||
108 | return salt.Concat(memoryStream.ToArray()).ToArray(); |
||
109 | } |
||
110 | } |
||
111 | } |
||
112 | } |
||
113 | } |
||
114 | } |
||
115 | |||
116 | /////////////////////////////////////////////////////////////////////////// |
||
117 | // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // |
||
118 | /////////////////////////////////////////////////////////////////////////// |
||
119 | /// <summary> |
||
120 | /// Decrypts a byte array using a salt and a key. |
||
121 | /// </summary> |
||
122 | /// <param name="inputStream">a salt and data stream to decrypt</param> |
||
123 | /// <param name="key">the encryption key</param> |
||
124 | /// <returns>a memory stream containing the decrypted data</returns> |
||
125 | public static async Task<MemoryStream> Decrypt(Stream inputStream, string key) |
||
126 | { |
||
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 | |||
138 | using (var aesManaged = new AesManaged()) |
||
139 | { |
||
140 | // FIPS-197 / CBC |
||
141 | aesManaged.BlockSize = AesBlockSize; |
||
142 | aesManaged.Mode = AesCipherMode; |
||
143 | aesManaged.Padding = AesPaddingMode; |
||
144 | aesManaged.KeySize = AesKeySize; |
||
145 | |||
146 | // Retrieve the key and the IV from the salt. |
||
147 | var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations); |
||
148 | aesManaged.Key = derivedKey.GetBytes(aesManaged.KeySize / 8); |
||
149 | aesManaged.IV = derivedKey.GetBytes(aesManaged.BlockSize / 8); |
||
150 | |||
151 | using (var decryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.IV)) |
||
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 | { |
||
179 | var salt = data.Take(AesKeySaltBytes).ToArray(); |
||
180 | var text = data.Skip(AesKeySaltBytes).ToArray(); |
||
181 | |||
182 | using (var aesManaged = new AesManaged()) |
||
183 | { |
||
184 | // FIPS-197 / CBC |
||
185 | aesManaged.BlockSize = AesBlockSize; |
||
186 | aesManaged.Mode = AesCipherMode; |
||
187 | aesManaged.Padding = AesPaddingMode; |
||
188 | aesManaged.KeySize = AesKeySize; |
||
189 | |||
190 | // Retrieve the key and the IV from the salt. |
||
191 | var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations); |
||
192 | aesManaged.Key = derivedKey.GetBytes(aesManaged.KeySize / 8); |
||
193 | aesManaged.IV = derivedKey.GetBytes(aesManaged.BlockSize / 8); |
||
194 | |||
195 | using (var decryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.IV)) |
||
196 | { |
||
197 | using (var memoryStream = new MemoryStream(text)) |
||
198 | { |
||
199 | using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) |
||
200 | { |
||
201 | using (var outputStream = new MemoryStream()) |
||
202 | { |
||
203 | await cryptoStream.CopyToAsync(outputStream); |
||
204 | |||
205 | outputStream.Position = 0L; |
||
206 | |||
207 | return outputStream.ToArray(); |
||
208 | } |
||
209 | } |
||
210 | } |
||
211 | } |
||
212 | } |
||
213 | } |
||
214 | |||
215 | public static string ExpandKey(string password, int length = 32) |
||
216 | { |
||
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; |
||
221 | } |
||
222 | } |
||
223 | } |