WingMan – Blame information for rev 10
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
8 | office | 1 | using System; |
2 | using System.IO; |
||
3 | using System.Security.Cryptography; |
||
4 | using System.Text; |
||
5 | |||
6 | namespace WingMan.Utilities |
||
7 | { |
||
8 | public static class AES |
||
9 | { |
||
10 | private const int AesBlockSize = 128; |
||
11 | private const CipherMode AesCipherMode = CipherMode.CBC; |
||
12 | private const PaddingMode AesPaddingMode = PaddingMode.PKCS7; |
||
13 | private const int AesKeySaltBytes = 16; |
||
14 | private static readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider(); |
||
15 | |||
16 | /////////////////////////////////////////////////////////////////////////// |
||
17 | // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // |
||
18 | /////////////////////////////////////////////////////////////////////////// |
||
19 | /// <summary> |
||
20 | /// Encrypts a string given a key and initialization vector. |
||
21 | /// </summary> |
||
22 | /// <param name="data">the string to encrypt</param> |
||
23 | /// <param name="key">the encryption key</param> |
||
24 | /// <param name="separator">the separator to use between the cyphertext and the IV</param> |
||
25 | /// <returns>Base64 encoded encrypted data</returns> |
||
10 | office | 26 | public static byte[] Encrypt(byte[] data, string key, string separator = ":") |
8 | office | 27 | { |
28 | using (var rijdanelManaged = new RijndaelManaged()) |
||
29 | { |
||
30 | // FIPS-197 / CBC |
||
31 | rijdanelManaged.BlockSize = AesBlockSize; |
||
32 | rijdanelManaged.Mode = AesCipherMode; |
||
33 | rijdanelManaged.Padding = AesPaddingMode; |
||
34 | |||
35 | // Compute the salt and the IV from the key. |
||
36 | var salt = new byte[AesKeySaltBytes]; |
||
37 | Rng.GetBytes(salt); |
||
10 | office | 38 | using (var derivedKey = new Rfc2898DeriveBytes(key, salt)) |
39 | { |
||
40 | rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); |
||
41 | rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); |
||
8 | office | 42 | |
10 | office | 43 | using (var encryptor = rijdanelManaged.CreateEncryptor(rijdanelManaged.Key, rijdanelManaged.IV)) |
8 | office | 44 | { |
10 | office | 45 | using (var memoryStream = new MemoryStream()) |
8 | office | 46 | { |
10 | office | 47 | using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) |
8 | office | 48 | { |
10 | office | 49 | using (var inputStream = new MemoryStream(data)) |
50 | { |
||
51 | inputStream.CopyTo(cryptoStream); |
||
52 | cryptoStream.FlushFinalBlock(); |
||
8 | office | 53 | |
10 | office | 54 | inputStream.Position = 0L; |
8 | office | 55 | |
10 | office | 56 | var payload = memoryStream.ToArray(); |
8 | office | 57 | |
10 | office | 58 | var base64Salt = Convert.ToBase64String(salt); |
59 | var base64Payload = Convert.ToBase64String(payload); |
||
8 | office | 60 | |
10 | office | 61 | return Encoding.UTF8.GetBytes($"{base64Salt}{separator}{base64Payload}"); |
62 | } |
||
8 | office | 63 | } |
64 | } |
||
65 | } |
||
66 | } |
||
67 | } |
||
68 | } |
||
69 | |||
70 | /////////////////////////////////////////////////////////////////////////// |
||
71 | // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // |
||
72 | /////////////////////////////////////////////////////////////////////////// |
||
73 | /// <summary> |
||
74 | /// Decrypts a Base64 encoded string using AES with a given key and initialization vector. |
||
75 | /// </summary> |
||
76 | /// <param name="data"> |
||
77 | /// a string consisting of the cyphertext to decrypt in Base64 and the IV in Base64 separated by the |
||
78 | /// separator |
||
79 | /// </param> |
||
80 | /// <param name="key">the encryption key</param> |
||
81 | /// <param name="separator">the separator to use between the cyphertext and the IV</param> |
||
82 | /// <returns>the decrypted data</returns> |
||
10 | office | 83 | public static byte[] Decrypt(byte[] data, string key, string separator = ":") |
8 | office | 84 | { |
85 | var input = Encoding.UTF8.GetString(data); |
||
86 | |||
87 | // retrieve the salt from the data. |
||
88 | var segments = input.Split(new[] {separator}, StringSplitOptions.None); |
||
89 | if (segments.Length != 2) |
||
10 | office | 90 | throw new ArgumentException("Invalid data: " + input); |
8 | office | 91 | |
92 | using (var rijdanelManaged = new RijndaelManaged()) |
||
93 | { |
||
94 | // FIPS-197 / CBC |
||
95 | rijdanelManaged.BlockSize = AesBlockSize; |
||
96 | rijdanelManaged.Mode = AesCipherMode; |
||
97 | rijdanelManaged.Padding = AesPaddingMode; |
||
98 | |||
99 | // Retrieve the key and the IV from the salt. |
||
10 | office | 100 | using (var derivedKey = new Rfc2898DeriveBytes(key, Convert.FromBase64String(segments[0].Trim()))) |
101 | { |
||
102 | rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); |
||
103 | rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); |
||
8 | office | 104 | |
10 | office | 105 | using (var decryptor = rijdanelManaged.CreateDecryptor(rijdanelManaged.Key, rijdanelManaged.IV)) |
8 | office | 106 | { |
10 | office | 107 | using (var memoryStream = new MemoryStream(Convert.FromBase64String(segments[1].Trim()))) |
8 | office | 108 | { |
10 | office | 109 | using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) |
8 | office | 110 | { |
10 | office | 111 | using (var streamReader = new StreamReader(cryptoStream)) |
112 | { |
||
113 | return Encoding.UTF8.GetBytes(streamReader.ReadToEnd()); |
||
114 | } |
||
8 | office | 115 | } |
116 | } |
||
117 | } |
||
118 | } |
||
119 | } |
||
120 | } |
||
121 | |||
10 | office | 122 | public static string ExpandKey(string password, int size = 32) |
8 | office | 123 | { |
124 | var sb = new StringBuilder(password); |
||
125 | do |
||
126 | { |
||
127 | sb.Append(password); |
||
128 | } while (sb.Length < size); |
||
129 | |||
130 | return sb.ToString(0, size); |
||
131 | } |
||
132 | } |
||
133 | } |