WingMan – Diff between revs 10 and 12

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 10 Rev 12
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;
5   7  
6 namespace WingMan.Utilities 8 namespace WingMan.Utilities
7 { 9 {
8 public static class AES 10 public static class AES
9 { 11 {
-   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;
14 private static readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider(); 17 private static readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider();
15   18  
16 /////////////////////////////////////////////////////////////////////////// 19 ///////////////////////////////////////////////////////////////////////////
17 // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // 20 // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
18 /////////////////////////////////////////////////////////////////////////// 21 ///////////////////////////////////////////////////////////////////////////
19 /// <summary> 22 /// <summary>
20 /// Encrypts a string given a key and initialization vector. 23 /// Encrypts a string given a key and initialization vector.
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;
32 rijdanelManaged.Mode = AesCipherMode; 35 rijdanelManaged.Mode = AesCipherMode;
33 rijdanelManaged.Padding = AesPaddingMode; 36 rijdanelManaged.Padding = AesPaddingMode;
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)) 41 var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations);
39 { -  
40 rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); 42 rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8);
41 rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); 43 rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8);
42   44  
-   45 using (var encryptor = rijdanelManaged.CreateEncryptor(rijdanelManaged.Key, rijdanelManaged.IV))
-   46 {
43 using (var encryptor = rijdanelManaged.CreateEncryptor(rijdanelManaged.Key, rijdanelManaged.IV)) 47 using (var memoryStream = new MemoryStream())
44 { 48 {
45 using (var memoryStream = new MemoryStream()) 49 using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
46 { 50 {
47 using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) 51 using (var inputStream = new MemoryStream(data))
48 { -  
49 using (var inputStream = new MemoryStream(data)) -  
50 { 52 {
51 inputStream.CopyTo(cryptoStream); 53 await inputStream.CopyToAsync(cryptoStream);
52 cryptoStream.FlushFinalBlock(); -  
53   -  
54 inputStream.Position = 0L; 54 cryptoStream.FlushFinalBlock();
55   55  
56 var payload = memoryStream.ToArray(); -  
57   -  
58 var base64Salt = Convert.ToBase64String(salt); -  
59 var base64Payload = Convert.ToBase64String(payload); -  
60   56 inputStream.Position = 0L;
61 return Encoding.UTF8.GetBytes($"{base64Salt}{separator}{base64Payload}"); 57  
62 } 58 return salt.Concat(memoryStream.ToArray()).ToArray();
63 } 59 }
64 } 60 }
65 } 61 }
66 } 62 }
67 } 63 }
68 } 64 }
69   65  
70 /////////////////////////////////////////////////////////////////////////// 66 ///////////////////////////////////////////////////////////////////////////
71 // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // 67 // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
72 /////////////////////////////////////////////////////////////////////////// 68 ///////////////////////////////////////////////////////////////////////////
73 /// <summary> 69 /// <summary>
74 /// Decrypts a Base64 encoded string using AES with a given key and initialization vector. 70 /// Decrypts a Base64 encoded string using AES with a given key and initialization vector.
75 /// </summary> 71 /// </summary>
76 /// <param name="data"> 72 /// <param name="data">
77 /// a string consisting of the cyphertext to decrypt in Base64 and the IV in Base64 separated by the 73 /// a string consisting of the cyphertext to decrypt in Base64 and the IV in Base64 separated by the
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); -  
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;
97 rijdanelManaged.Padding = AesPaddingMode; 89 rijdanelManaged.Padding = AesPaddingMode;
98   90  
99 // Retrieve the key and the IV from the salt. 91 // Retrieve the key and the IV from the salt.
100 using (var derivedKey = new Rfc2898DeriveBytes(key, Convert.FromBase64String(segments[0].Trim()))) 92 var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations);
101 { -  
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  
-   96 using (var decryptor = rijdanelManaged.CreateDecryptor(rijdanelManaged.Key, rijdanelManaged.IV))
-   97 {
105 using (var decryptor = rijdanelManaged.CreateDecryptor(rijdanelManaged.Key, rijdanelManaged.IV)) 98 using (var memoryStream = new MemoryStream(text))
106 { 99 {
107 using (var memoryStream = new MemoryStream(Convert.FromBase64String(segments[1].Trim()))) 100 using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
108 { 101 {
109 using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) 102 using (var outputStream = new MemoryStream())
110 { 103 {
-   104 await cryptoStream.CopyToAsync(outputStream);
111 using (var streamReader = new StreamReader(cryptoStream)) 105  
-   106 outputStream.Position = 0L;
112 { 107  
113 return Encoding.UTF8.GetBytes(streamReader.ReadToEnd()); -  
114 } 108 return outputStream.ToArray();
115 } 109 }
116 } 110 }
117 } 111 }
118 } 112 }
119 } 113 }
120 } 114 }
121   115  
122 public static string ExpandKey(string password, int size = 32) 116 public static string ExpandKey(string password, int size = 32)
123 { 117 {
124 var sb = new StringBuilder(password); 118 var sb = new StringBuilder(password);
125 do 119 do
126 { 120 {
127 sb.Append(password); 121 sb.Append(password);
128 } while (sb.Length < size); 122 } while (sb.Length < size);
129   123  
130 return sb.ToString(0, size); 124 return sb.ToString(0, size);
131 } 125 }
132 } 126 }
133 } 127 }
134   128