Hush – Blame information for rev 1

Subversion Repositories:
Rev:
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 }