-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCipher.cs
154 lines (130 loc) · 6.56 KB
/
Cipher.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
using System;
using System.Security.Cryptography;
using System.IO;
using System.Linq;
namespace Cipher {
class Cipher {
// Never hard-code a password within your source code. Hard-coded passwords can be retrieved from an assembly
// by using the Ildasm.exe (IL Disassembler), by using a hexadecimal editor, or by simply opening up the
// assembly in a text editor such as Notepad.exe.
// Reference:
//https://msdn.microsoft.com/en-us/library/system.security.cryptography.passwordderivebytes(v=vs.110).aspx
// Make sure the work factor is proportional to the importance of the information you are protecting.
/// <summary>
/// Generate symmetric key for encryption and decryption.
/// </summary>
/// <param name="password">
/// User provided password for key generation purpose.
/// Use a passphrase for improved security.
/// </param>
/// <param name="keySize">
/// The key length.
/// </param>
/// <returns>
/// The symmetric key.
/// </returns>
private static byte[] GenerateSymmetricKey(string password, int keySize) {
// Do not use this salt sample. Replace this salt with one generated by
// SaveArraySampleToDisk() method.
byte[] salt = new byte[] { 220, 20, 232, 128, 36, 70, 7, 53, 36, 116, 80, 197, 21, 57, 148, 116, 60, 189, 192, 132, 198, 32, 205, 246, 79, 225, 197, 110, 8, 29, 180, 55, 133, 161, 9, 168, 59, 137, 246, 101, 16, 54, 43, 174, 21, 4, 14, 157, 50, 213, 114, 210, 154, 133, 60, 51, 2, 48, 1, 120, 235, 126, 9, 164 };
var iterationCount = 10000;
// Use the password, salt, and iteration count to generate the simmetric key.
DeriveBytes deriveBytes = new Rfc2898DeriveBytes(password, salt, iterationCount);
return deriveBytes.GetBytes(keySize >> 3);
}
/// <summary>
/// Encrypts a document file.
/// </summary>
/// <param name="data">The byte array file to be encrypted.</param>
/// <param name="password">The password to encrypt the byte array.</param>
/// <returns>
/// A byte array representing the encrypted document.
/// </returns>
public static byte[] Encrypt(byte[] data, string password) {
// Initialize array.
byte[] encryptedData = null;
using (var provider = Aes.Create ()) {
provider.GenerateIV();
provider.Key = GenerateSymmetricKey(password, provider.KeySize);
provider.Mode = CipherMode.CBC;
provider.Padding = PaddingMode.PKCS7;
using (MemoryStream memStream = new MemoryStream(data.Length)) {
memStream.Write(provider.IV, 0, 16);
using (ICryptoTransform encryptor = provider.CreateEncryptor(provider.Key, provider.IV)) {
using (CryptoStream cryptoStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write)) {
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
}
}
encryptedData = memStream.ToArray();
}
}
return encryptedData;
}
/// <summary>
/// Decrypts a document file.
/// </summary>
/// <param name="data">The byte array file to be decrypted.</param>
/// <param name="password">The password to decrypt the byte array.</param>
/// <returns>
/// A byte array representing the decrypted document.
/// </returns>
public static byte[] Decrypt(byte[] data, string password) {
// Initialize array.
byte[] decryptedData = new byte[data.Length];
using (var provider = Aes.Create ()) {
provider.Key = GenerateSymmetricKey(password, provider.KeySize);
provider.Mode = CipherMode.CBC;
provider.Padding = PaddingMode.PKCS7;
using (MemoryStream memStream = new MemoryStream(data)) {
byte[] iv = new byte[16];
memStream.Read(iv, 0, 16);
using (ICryptoTransform decryptor = provider.CreateDecryptor(provider.Key, iv)) {
using (CryptoStream cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read)) {
cryptoStream.Read(decryptedData, 0, decryptedData.Length);
}
}
}
}
return decryptedData;
}
/// <summary>
/// Generates a random cryptographic array.
/// </summary>
/// <returns></returns>
public static byte[] CreateArray() {
using (RandomNumberGenerator rng = RandomNumberGenerator.Create() ) {
byte[] byteArray = new byte[64];
rng.GetBytes(byteArray);
return byteArray;
}
}
/// <summary>
/// Displays and saves a byte array to be used to generate random numbers.
/// Rather than using the byte[] for the salt shown on the code, use this generator to create your own array.
/// The salt array is needed to encrypt/decrypt the file. If you use different arrays, you must keep track of what
/// salt you used for a file. We recommend use a large password (a passphrase) to encrypt/decrypt.
/// </summary>
/// <param name="size">The length of the array.</param>
/// <returns>
/// None.
/// </returns>
public static void SaveArraySampleToDisk() {
byte[] byteArray = CreateArray();
// Initialize string array to save it to disk.
string bytes = "byte[] salt = new byte[] { ";
// Format string array.
foreach (int b in byteArray) {
// If byte is the last item on the array, add a closing brace. Otherwise, add a comma.
if (b == byteArray.Last()) {
bytes += b.ToString() + " };";
} else {
bytes += b.ToString() + ", ";
}
}
// Save file to disk.
var fileName = "array_" + Guid.NewGuid().ToString() + ".txt";
File.WriteAllText(Path.Combine(Utility.directory, fileName), bytes);
}
}
}