/[winpt]/trunk/PTD/wptWipeFile.cpp
ViewVC logotype

Contents of /trunk/PTD/wptWipeFile.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (show annotations)
Fri Sep 30 10:10:16 2005 UTC (19 years, 5 months ago) by twoaday
File size: 10434 byte(s)
Almost finished phase 1 of the WinPT GPGME port.
Still need more cleanup, comments and tests.


1 /* wptWipeFile.cpp - Secure file removal
2 * Copyright (C) 2001-2005 Timo Schulz
3 * Copyright (C) 2000 Matt Gauthier
4 *
5 * WinPT software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * WinPT is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with WinPT; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18 *
19 **************************************************************************
20 * This code based on the sunlink.c file from the SRM project, but *
21 * it was heavily modified to work with W32 and with added GCRYPT *
22 * support for gathering random bytes. *
23 * *
24 * The original code was placed under the GNU Lesser Public License, *
25 * even so I decide to put this file under the GNU General Public License.*
26 **************************************************************************
27 */
28
29 #include <windows.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/stat.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <direct.h>
36
37 #include "openpgp.h"
38 #include "wptW32API.h"
39 #include "wptErrors.h"
40 #include "wptTypes.h"
41
42
43 typedef unsigned __int64 DDWORD;
44
45 typedef struct {
46 HANDLE fd;
47 DDWORD filesize;
48 DDWORD offset;
49 BYTE *buffer;
50 DWORD buffsize;
51 const char *name;
52 int n_passes;
53 } wipe_context_s;
54
55
56 void (*progress_cb) (void *, DDWORD, DDWORD);
57 static void *progress_cb_value = NULL;
58
59 void (*unlink_cb)(void *, const char *, int, int, int) = NULL;
60 static void *unlink_cb_value = NULL;
61
62 /* Use the file handle in the context to overwrite a file
63 with prepared buffer contents. */
64 static void
65 overwrite (wipe_context_s *ctx)
66 {
67 DDWORD blocks = 0, mod = 0;
68 DWORD nwritten = 0;
69 LONG size_high = 0;
70
71 blocks = ctx->filesize / ctx->buffsize;
72 mod = ctx->filesize % ctx->buffsize;
73 SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);
74 while (blocks--) {
75 if (!WriteFile (ctx->fd, ctx->buffer, ctx->buffsize, &nwritten, NULL))
76 break;
77 ctx->offset += nwritten;
78 if (unlink_cb)
79 unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,
80 (unsigned)ctx->filesize*ctx->n_passes);
81 }
82 if (mod) {
83 WriteFile (ctx->fd, ctx->buffer, (DWORD)mod, &nwritten, NULL);
84 ctx->offset += nwritten;
85 if (unlink_cb)
86 unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,
87 (unsigned)ctx->filesize*ctx->n_passes);
88 }
89 FlushFileBuffers (ctx->fd);
90 SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);
91 }
92
93
94 /* fill the buffer with random of the given level. */
95 static void
96 randomize_buffer (byte *buf, size_t bufsize, int level)
97 {
98 const int blocksize = 512;
99 int blocks = bufsize / blocksize;
100 int mod = bufsize % blocksize;
101
102 while (blocks--) {
103 gpg_randomize (buf, blocksize, level);
104 buf += blocksize;
105 }
106 if (mod)
107 gpg_randomize (buf, mod, level);
108 }
109
110
111 /* performs a random overwrite. */
112 static void
113 overwrite_random (int npasses, wipe_context_s * ctx)
114 {
115 int i;
116
117 for (i = 0; i < npasses; i++) {
118 randomize_buffer (ctx->buffer, ctx->buffsize, 0);
119 overwrite (ctx);
120 }
121 }
122
123
124 /* perform an overwrite with a specific byte (like 0x00). */
125 static void
126 overwrite_byte (int byte, wipe_context_s * ctx)
127 {
128 memset (ctx->buffer, byte, ctx->buffsize);
129 overwrite (ctx);
130 } /* overwrite_byte */
131
132
133 /* perform an overwrite with a specific byte triple (like 0x00, 0xFF, 0xAA). */
134 static void
135 overwrite_bytes (int byte1, int byte2, int byte3, wipe_context_s * ctx)
136 {
137 DWORD i;
138
139 memset (ctx->buffer, byte1, ctx->buffsize);
140 for (i = 1; i < ctx->buffsize; i += 3) {
141 ctx->buffer[i] = byte2;
142 ctx->buffer[i+1] = byte3;
143 }
144 overwrite (ctx);
145 } /* overwrite_bytes */
146
147
148 /* For the case the file is not a regular file (this is true for
149 devices or directories) this function tries to rename the file
150 to random pattern and then it will be delete (without random!). */
151 int
152 rename_unlink (const char *path)
153 {
154 struct stat statbuf;
155 char *new_name = NULL, *p = NULL, c;
156 int i = 0, rc = 0;
157 int is_dir = 0;
158
159 if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)
160 is_dir = 1;
161
162 new_name = new char[strlen (path)+15];
163 if (!new_name)
164 BUG (0);
165
166 strcpy (new_name, path);
167 p = strrchr (new_name, '\\');
168 if (p != NULL) {
169 p++;
170 *p = '\0';
171 }
172 else
173 p = new_name;
174 do {
175 while (i < 14) {
176 c = gpg_random_char (1);
177 *p = c;
178 p++;
179 i++;
180 }
181 *p = '\0';
182 } while (stat (new_name, &statbuf) == 0);
183
184 if (rename (path, new_name) == -1) {
185 rc = WPTERR_FILE_READ;
186 goto leave;
187 }
188 if (is_dir && RemoveDirectory (new_name) == FALSE)
189 rc = WPTERR_FILE_REMOVE;
190 else if (!DeleteFile (new_name))
191 rc = WPTERR_FILE_REMOVE;
192
193 leave:
194 free_if_alloc (new_name);
195 return rc;
196 }
197
198
199 /* return the filesize as an 64-bit integer. */
200 static __int64
201 GetFileSize64 (const char * path)
202 {
203 FILE *fp = fopen (path, "r");
204 if (fp) {
205 struct _stati64 statbuf;
206 if (_fstati64 (fileno (fp), &statbuf) == -1)
207 return -1;
208 fclose (fp);
209 return statbuf.st_size;
210 }
211 return -1;
212 }
213
214
215 static int
216 _secure_unlink (const char * path, int mode, HANDLE *r_fd)
217 {
218 wipe_context_s ctx;
219 LONG size_high = 0;
220
221 if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)
222 return rename_unlink (path);
223
224 memset (&ctx, 0, sizeof (ctx));
225 ctx.name = path;
226 ctx.buffsize = 16384;
227 ctx.buffer = new byte[ctx.buffsize];
228 if (!ctx.buffer)
229 BUG (0);
230
231 ctx.filesize = GetFileSize64 (path);
232 if (!ctx.filesize) {
233 free_if_alloc (ctx.buffer);
234 unlink (path);
235 return 0;
236 }
237
238 ctx.fd = CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
239 OPEN_ALWAYS, 0, NULL);
240 if (ctx.fd == INVALID_HANDLE_VALUE) {
241 free_if_alloc (ctx.buffer);
242 return WPTERR_FILE_OPEN;
243 }
244 else if (r_fd)
245 *r_fd = ctx.fd;
246
247 gpg_quick_random_gen (1);
248 if (unlink_cb)
249 unlink_cb (unlink_cb_value, ctx.name, 0, 0, 0);
250
251 switch (mode) {
252 case WIPE_MODE_FAST:
253 ctx.n_passes = 1;
254 overwrite_random (1, &ctx);
255 break;
256
257 case WIPE_MODE_SIMPLE:
258 ctx.n_passes = 2;
259 overwrite_random (2, &ctx);
260 break;
261
262 case WIPE_MODE_DOD:
263 ctx.n_passes = 5;
264 overwrite_random (1, &ctx);
265 overwrite_byte ((~1) & 0xFF, &ctx);
266 overwrite_random (1, &ctx);
267 overwrite_byte ((~4) & 0xFF, &ctx);
268 overwrite_random (1, &ctx);
269 break;
270
271 case WIPE_MODE_GUTMANN:
272 ctx.n_passes = 39;
273 overwrite_random (4, &ctx);
274 overwrite_byte( 0x55, &ctx );
275 overwrite_byte ( 0xAA, &ctx );
276 overwrite_bytes( 0x92, 0x49, 0x24, &ctx );
277 overwrite_bytes( 0x49, 0x24, 0x92, &ctx );
278 overwrite_bytes( 0x24, 0x92, 0x49, &ctx );
279 overwrite_byte( 0x00, &ctx );
280 overwrite_byte( 0x11, &ctx );
281 overwrite_byte( 0x22, &ctx );
282 overwrite_byte( 0x33, &ctx );
283 overwrite_byte( 0x44, &ctx );
284 overwrite_byte( 0x55, &ctx );
285 overwrite_byte( 0x66, &ctx );
286 overwrite_byte( 0x77, &ctx );
287 overwrite_byte( 0x88, &ctx );
288 overwrite_byte( 0x99, &ctx );
289 overwrite_byte( 0xAA, &ctx );
290 overwrite_byte( 0xBB, &ctx );
291 overwrite_byte( 0xCC, &ctx );
292 overwrite_byte( 0xDD, &ctx );
293 overwrite_byte( 0xEE, &ctx );
294 overwrite_byte( 0xFF, &ctx );
295 overwrite_bytes( 0x92, 0x49, 0x24, &ctx );
296 overwrite_bytes( 0x49, 0x24, 0x92, &ctx );
297 overwrite_bytes( 0x24, 0x92, 0x49, &ctx );
298 overwrite_bytes( 0x6D, 0xB6, 0xDB, &ctx );
299 overwrite_bytes( 0xB6, 0xDB, 0x6D, &ctx );
300 overwrite_bytes( 0xDB, 0x6D, 0xB6, &ctx );
301 overwrite_random( 4, &ctx );
302 break;
303 }
304
305 /* Set file length to zero so allocated clusters cannot be trailed */
306 SetFilePointer (ctx.fd, 0, &size_high, FILE_BEGIN);
307 SetEndOfFile (ctx.fd);
308 CloseHandle (ctx.fd);
309
310 memset (ctx.buffer, 0, ctx.buffsize); /* burn the last evidence */
311 free_if_alloc (ctx.buffer);
312
313 return rename_unlink (path);
314 }
315
316
317 /* Delete a file in a secure way with the given mode. */
318 int
319 secure_unlink (const char *path, int mode)
320 {
321 return _secure_unlink (path, mode, NULL);
322 }
323
324
325 /* Set the callback @cb for the wipe function. The callback is call every time
326 the wipe function writes data to the file. */
327 void
328 secure_unlink_set_cb (void (*cb)(void *, const char *, int, int, int),
329 void *cb_value)
330 {
331 unlink_cb = cb;
332 unlink_cb_value = cb_value;
333 }
334
335
336 /* wipe all free space of the given drive by creating a temp file
337 which has the size of the free space. This file will be then
338 overwritten with random and static pattern. */
339 int
340 wipe_freespace (const char * drive, HANDLE *r_fd,
341 void (*cb)(void *, DDWORD, DDWORD), void * cb_value)
342 {
343 ULARGE_INTEGER caller, total, frees;
344 LONG hpart=0;
345 HANDLE fd;
346 int disktyp = GetDriveType (drive);
347 int rc;
348 char * file;
349
350 if (disktyp != DRIVE_FIXED && disktyp != DRIVE_REMOVABLE)
351 return -1;
352 if (!GetDiskFreeSpaceEx (drive, &caller, &total, &frees))
353 return -1;
354
355 /* disk is full */
356 if (!frees.LowPart)
357 return 0;
358 file = new char[strlen (drive)+8];
359 if (!file)
360 BUG (0);
361 sprintf (file, "%stemp_winpt.tmp", drive);
362 fd = CreateFile (file,
363 GENERIC_READ|GENERIC_WRITE,
364 FILE_SHARE_READ|FILE_SHARE_WRITE,
365 NULL, CREATE_ALWAYS, 0, NULL);
366 if (fd == INVALID_HANDLE_VALUE) {
367 free_if_alloc (file);
368 return WPTERR_FILE_OPEN;
369 }
370 hpart = frees.HighPart;
371 SetFilePointer (fd, frees.LowPart, &hpart, FILE_BEGIN);
372 SetEndOfFile (fd);
373 CloseHandle (fd);
374
375 if (cb && cb_value) {
376 progress_cb = cb;
377 progress_cb_value = cb_value;
378 }
379 rc = _secure_unlink (file, WIPE_MODE_FAST, r_fd);
380 free_if_alloc (file);
381 return rc;
382 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26