WingMan – Diff between revs 10 and 12
?pathlinks?
Rev 10 | Rev 12 | |||
---|---|---|---|---|
Line 1... | Line 1... | |||
1 | using System; |
1 | using System; |
|
2 | using System.IO; |
2 | using System.IO; |
|
- | 3 | using System.Linq; |
||
3 | using System.Security.Cryptography; |
4 | using System.Security.Cryptography; |
|
4 | using System.Text; |
5 | using System.Text; |
|
- | 6 | using System.Threading.Tasks; |
||
Line 5... | Line 7... | |||
5 | |
7 | |
|
6 | namespace WingMan.Utilities |
8 | namespace WingMan.Utilities |
|
7 | { |
9 | { |
|
8 | public static class AES |
10 | public static class AES |
|
- | 11 | { |
||
9 | { |
12 | private const int AesKeyIterations = 4096; |
|
10 | private const int AesBlockSize = 128; |
13 | private const int AesBlockSize = 128; |
|
11 | private const CipherMode AesCipherMode = CipherMode.CBC; |
14 | private const CipherMode AesCipherMode = CipherMode.CBC; |
|
12 | private const PaddingMode AesPaddingMode = PaddingMode.PKCS7; |
15 | private const PaddingMode AesPaddingMode = PaddingMode.PKCS7; |
|
13 | private const int AesKeySaltBytes = 16; |
16 | private const int AesKeySaltBytes = 16; |
|
Line 21... | Line 24... | |||
21 | /// </summary> |
24 | /// </summary> |
|
22 | /// <param name="data">the string to encrypt</param> |
25 | /// <param name="data">the string to encrypt</param> |
|
23 | /// <param name="key">the encryption key</param> |
26 | /// <param name="key">the encryption key</param> |
|
24 | /// <param name="separator">the separator to use between the cyphertext and the IV</param> |
27 | /// <param name="separator">the separator to use between the cyphertext and the IV</param> |
|
25 | /// <returns>Base64 encoded encrypted data</returns> |
28 | /// <returns>Base64 encoded encrypted data</returns> |
|
26 | public static byte[] Encrypt(byte[] data, string key, string separator = ":") |
29 | public static async Task<byte[]> Encrypt(byte[] data, string key, string separator = ":") |
|
27 | { |
30 | { |
|
28 | using (var rijdanelManaged = new RijndaelManaged()) |
31 | using (var rijdanelManaged = new RijndaelManaged()) |
|
29 | { |
32 | { |
|
30 | // FIPS-197 / CBC |
33 | // FIPS-197 / CBC |
|
31 | rijdanelManaged.BlockSize = AesBlockSize; |
34 | rijdanelManaged.BlockSize = AesBlockSize; |
|
Line 33... | Line 36... | |||
33 | rijdanelManaged.Padding = AesPaddingMode; |
36 | rijdanelManaged.Padding = AesPaddingMode; |
|
Line 34... | Line 37... | |||
34 | |
37 | |
|
35 | // Compute the salt and the IV from the key. |
38 | // Compute the salt and the IV from the key. |
|
36 | var salt = new byte[AesKeySaltBytes]; |
39 | var salt = new byte[AesKeySaltBytes]; |
|
37 | Rng.GetBytes(salt); |
40 | Rng.GetBytes(salt); |
|
38 | using (var derivedKey = new Rfc2898DeriveBytes(key, salt)) |
- | ||
39 | { |
41 | var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations); |
|
40 | rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); |
42 | rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); |
|
Line 41... | Line 43... | |||
41 | rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); |
43 | rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); |
|
42 | |
44 | |
|
Line 46... | Line 48... | |||
46 | { |
48 | { |
|
47 | using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) |
49 | using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) |
|
48 | { |
50 | { |
|
49 | using (var inputStream = new MemoryStream(data)) |
51 | using (var inputStream = new MemoryStream(data)) |
|
50 | { |
52 | { |
|
51 | inputStream.CopyTo(cryptoStream); |
53 | await inputStream.CopyToAsync(cryptoStream); |
|
52 | cryptoStream.FlushFinalBlock(); |
54 | cryptoStream.FlushFinalBlock(); |
|
Line 53... | Line 55... | |||
53 | |
55 | |
|
Line 54... | Line 56... | |||
54 | inputStream.Position = 0L; |
56 | inputStream.Position = 0L; |
|
55 | |
- | ||
56 | var payload = memoryStream.ToArray(); |
- | ||
57 | |
- | ||
58 | var base64Salt = Convert.ToBase64String(salt); |
- | ||
59 | var base64Payload = Convert.ToBase64String(payload); |
- | ||
60 | |
- | ||
61 | return Encoding.UTF8.GetBytes($"{base64Salt}{separator}{base64Payload}"); |
57 | |
|
62 | } |
58 | return salt.Concat(memoryStream.ToArray()).ToArray(); |
|
63 | } |
59 | } |
|
64 | } |
60 | } |
|
65 | } |
61 | } |
|
Line 78... | Line 74... | |||
78 | /// separator |
74 | /// separator |
|
79 | /// </param> |
75 | /// </param> |
|
80 | /// <param name="key">the encryption key</param> |
76 | /// <param name="key">the encryption key</param> |
|
81 | /// <param name="separator">the separator to use between the cyphertext and the IV</param> |
77 | /// <param name="separator">the separator to use between the cyphertext and the IV</param> |
|
82 | /// <returns>the decrypted data</returns> |
78 | /// <returns>the decrypted data</returns> |
|
83 | public static byte[] Decrypt(byte[] data, string key, string separator = ":") |
79 | public static async Task<byte[]> Decrypt(byte[] data, string key, string separator = ":") |
|
84 | { |
80 | { |
|
85 | var input = Encoding.UTF8.GetString(data); |
81 | var salt = data.Take(AesKeySaltBytes).ToArray(); |
|
86 | |
- | ||
87 | // retrieve the salt from the data. |
- | ||
88 | var segments = input.Split(new[] {separator}, StringSplitOptions.None); |
82 | var text = data.Skip(AesKeySaltBytes).ToArray(); |
|
89 | if (segments.Length != 2) |
- | ||
90 | throw new ArgumentException("Invalid data: " + input); |
- | ||
Line 91... | Line 83... | |||
91 | |
83 | |
|
92 | using (var rijdanelManaged = new RijndaelManaged()) |
84 | using (var rijdanelManaged = new RijndaelManaged()) |
|
93 | { |
85 | { |
|
94 | // FIPS-197 / CBC |
86 | // FIPS-197 / CBC |
|
95 | rijdanelManaged.BlockSize = AesBlockSize; |
87 | rijdanelManaged.BlockSize = AesBlockSize; |
|
96 | rijdanelManaged.Mode = AesCipherMode; |
88 | rijdanelManaged.Mode = AesCipherMode; |
|
Line 97... | Line 89... | |||
97 | rijdanelManaged.Padding = AesPaddingMode; |
89 | rijdanelManaged.Padding = AesPaddingMode; |
|
98 | |
90 | |
|
99 | // Retrieve the key and the IV from the salt. |
- | ||
100 | using (var derivedKey = new Rfc2898DeriveBytes(key, Convert.FromBase64String(segments[0].Trim()))) |
91 | // Retrieve the key and the IV from the salt. |
|
101 | { |
92 | var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations); |
|
Line 102... | Line 93... | |||
102 | rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); |
93 | rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); |
|
103 | rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); |
94 | rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); |
|
104 | |
95 | |
|
105 | using (var decryptor = rijdanelManaged.CreateDecryptor(rijdanelManaged.Key, rijdanelManaged.IV)) |
96 | using (var decryptor = rijdanelManaged.CreateDecryptor(rijdanelManaged.Key, rijdanelManaged.IV)) |
|
106 | { |
97 | { |
|
107 | using (var memoryStream = new MemoryStream(Convert.FromBase64String(segments[1].Trim()))) |
98 | using (var memoryStream = new MemoryStream(text)) |
|
108 | { |
99 | { |
|
109 | using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) |
100 | using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) |
|
110 | { |
101 | { |
|
- | 102 | using (var outputStream = new MemoryStream()) |
||
111 | using (var streamReader = new StreamReader(cryptoStream)) |
103 | { |
|
- | 104 | await cryptoStream.CopyToAsync(outputStream); |
||
- | 105 | |
||
112 | { |
106 | outputStream.Position = 0L; |
|
113 | return Encoding.UTF8.GetBytes(streamReader.ReadToEnd()); |
107 | |
|
114 | } |
108 | return outputStream.ToArray(); |
|
115 | } |
109 | } |
|
116 | } |
110 | } |