-
Notifications
You must be signed in to change notification settings - Fork 0
/
Masker.cs
243 lines (183 loc) · 5.83 KB
/
Masker.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
using System.Collections;
using System.Drawing;
using System.IO;
using File_Mask.lib;
using File_Mask.lib.tour;
/**
* File Mask
*
* An open source application written in C# to facilitate the
* merging and extraction of files and/from images.
*
* @author ***REMOVED***
* @version 1.0.2
*/
namespace File_Mask
{
/**
* Masks and unmasks files.
*/
internal class Masker
{
/**
* Returns every pixel in a Bitmap image as a Color object.
*/
private static Color[] GetPixels(Bitmap img)
{
int width = img.Width;
int height = img.Height;
var pixels = new Color[width*height];
//Put pixels in the array from left to right.
for (int y = 0, h = img.Height; y < h; y++)
{
for (int x = 0, w = img.Width; x < w; x++)
{
pixels[y*width + x] = img.GetPixel(x, y);
}
}
return pixels;
}
/**
* Creates a new Bitmap image from an array of Color objects given a width and height.
*/
private static Bitmap CreateImage(int width, int height, Color[] pixels)
{
var img = new Bitmap(width, height);
for (int y = 0, h = height; y < h; y++)
{
for (int x = 0, w = width; x < w; x++)
{
img.SetPixel(x, y, pixels[y*width + x]);
}
}
return img;
}
/**
* Masks a file with an image given a file and image.
*/
public static string[] Mask(string file, string image)
{
//Create a new Bitmap objects and map pixels/bits.
var img = new Bitmap(image);
Color[] pixels = GetPixels(img);
var pixelBits = new int[pixels.Length];
for (int n = 0, length = pixels.Length; n < length; n++)
pixelBits[n] = Util.ColorToBits(pixels[n]);
//Read all bits from the file to mask.
byte[] bytes = File.ReadAllBytes(file);
var bits = new BitArray(bytes);
//Merge bits.
var tour = new Tour(img.Width, img.Height);
pixelBits = Merge(bits, tour, pixelBits);
//Generate pixel colors based on each the merged bits.
for (int n = 0, length = pixelBits.Length; n < length; n++)
pixels[n] = Util.BitsToColor(pixelBits[n]);
Bitmap maskedImage = CreateImage(img.Width, img.Height, pixels);
//Save the new image.
string dir = Path.GetDirectoryName(image);
string name = Path.GetFileNameWithoutExtension(image);
string extension = Path.GetExtension(image);
Benchmark mark = new Benchmark("Time to Write Masked File", true);
maskedImage.Save(dir + "\\" + name + " - Masked" + extension);
mark.Time();
//Generate AES keys and return.
mark = new Benchmark("Time to Generate Encryption Keys", true);
string[] hash = Crypt.Encrypt(Path.GetFileName(file) + ":" + bits.Length + ":" + tour.Export());
mark.Time();
return hash;
}
/**
* Merges colors represented as 32-bit integers with an array of bits
* from a given file.
*/
private static int[] Merge(BitArray bits, Tour tour, int[] pixels)
{
//Clone pixels to prevent destruction.
var newPixels = (int[]) pixels.Clone();
Benchmark mark = new Benchmark("Time to Generate Tour", true);
Square start = tour.CreateTour();
Square current = start;
mark.Time();
mark = new Benchmark("Time to Modify Pixel Channels", true);
for (int n = 0, length = bits.Length; n < length; n += 3)
{
//Calculate the bit depth to use.
int depth = n/newPixels.Length;
//Select the pixel to operate on and get the color channels.
int index = Util.ToIndex(tour.Width, current.X, current.Y);
int pixel = newPixels[index];
//Get channel values and create a bool representation.
int r = (pixel >> 16) & 0xFF;
int g = (pixel >> 8) & 0xFF;
int b = pixel & 0xFF;
bool red = bits[n];
bool green = n + 1 < length && bits[n + 1];
bool blue = n + 2 < length && bits[n + 2];
//Set pixel channel values based on the above bools.
if (red) r = r | 1 << depth;
else r = r & ~(1 << depth);
if (green) g = g | 1 << depth;
else g = g & ~(1 << depth);
if (blue) b = b | 1 << depth;
else b = b & ~(1 << depth);
newPixels[index] = Util.BitsToColor(r, g, b);
//Select the next pixel to manipulate.
current = current.Next ?? start;
}
mark.Time();
return newPixels;
}
/**
* Creates a file given an image and a valid hash and key.
*/
public static void Unmask(string image, string hash, string key)
{
//Create a new Bitmap object and decrypt the AES hash.
var img = new Bitmap(image);
string info = Crypt.Decrypt(hash, key);
if (info != null)
{
string name = info.Split(':')[0];
int size = int.Parse(info.Split(':')[1]);
var tour = new Tour(img.Width, img.Height);
Square path = tour.Import(info.Split(':')[2]);
//Get pixel data and extract bits from the data.
Color[] pixels = GetPixels(img);
var pixelBits = new int[pixels.Length];
for (int n = 0, length = pixels.Length; n < length; n++)
pixelBits[n] = Util.ColorToBits(pixels[n]);
var file = new byte[size/8];
Extract(pixelBits, tour, path, size).CopyTo(file, 0);
//Write the bits to a file.
File.WriteAllBytes(Path.GetDirectoryName(image) + "\\" + name, file);
}
}
/**
* Returns a BitArray object containing the bits extracted from
* the pixel array "bits".
*/
private static BitArray Extract(int[] bits, Tour tour, Square path, int size)
{
var file = new BitArray(size);
Square start = path;
for (int n = 0; n < size; n += 3)
{
int depth = n/bits.Length;
int index = Util.ToIndex(tour.Width, path.X, path.Y);
Color color = Util.BitsToColor(bits[index]);
int r = color.R;
int g = color.G;
int b = color.B;
r = r & 1 << depth;
g = g & 1 << depth;
b = b & 1 << depth;
file.Set(n, Util.IntToBool(r));
if (n + 1 < size) file.Set(n + 1, Util.IntToBool(g));
if (n + 2 < size) file.Set(n + 2, Util.IntToBool(b));
//Select the next pixel to read from.
path = path.Next ?? start;
}
return file;
}
}
}