WingMan – Blame information for rev 10

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