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

Contents of /trunk/PTD/wptWipeFile.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 53 - (show annotations)
Wed Nov 2 09:01:29 2005 UTC (19 years, 4 months ago) by twoaday
File size: 14619 byte(s)
Deleted GPG specific random generator.
Provide simple generator in the wipe code.


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 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #include <windows.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <sys/stat.h>
37 #include <string.h>
38 #include <ctype.h>
39 #include <direct.h>
40
41 #include "openpgp.h"
42 #include "wptW32API.h"
43 #include "wptErrors.h"
44 #include "wptTypes.h"
45 #include "wptCrypto.h"
46
47 #ifdef _MSC_VER
48 typedef unsigned __int64 DDWORD;
49 #else
50 typedef unsigned long long DDWORD;
51 #endif
52
53 typedef struct {
54 HANDLE fd;
55 DDWORD filesize;
56 DDWORD offset;
57 BYTE *buffer;
58 DWORD buffsize;
59 const char *name;
60 int n_passes;
61 } wipe_context_s;
62
63 struct arcfour_s {
64 BYTE *seed;
65 int pos;
66 BYTE sbox[256];
67 DWORD i;
68 DWORD j;
69 };
70
71
72 void (*progress_cb) (void *, DDWORD, DDWORD);
73 static void *progress_cb_value = NULL;
74
75 void (*unlink_cb)(void *, const char *, int, int, int) = NULL;
76 static void *unlink_cb_value = NULL;
77
78 static int init_done = 0;
79 static struct arcfour_s rnd;
80
81
82 /* Add the random from buffer @buf with the length @buf_len
83 into the seed @seed. The seed length (256) used to
84 emulate a circular movment. */
85 static void
86 add_random (unsigned char *seed, int *seed_pos,
87 unsigned char *buf, int buf_len)
88 {
89 int i, s_pos = *seed_pos;
90
91 for (i=0; i < buf_len; i++)
92 seed[(s_pos++ % 256)] ^= buf[i];
93 *seed_pos = s_pos % 256;
94 }
95
96
97 /* Enumerate all child windows. Store their text, their thread ID,
98 their placement and their dimension. */
99 static BOOL CALLBACK
100 child_proc (HWND h, LPARAM l)
101 {
102 struct arcfour_s *cb = (struct arcfour_s*)l;
103 DWORD a = (DWORD)h;
104 WINDOWPLACEMENT p;
105 RECT r;
106 char buf[256];
107 int n;
108
109 n = GetWindowText (h, buf, 255);
110 if (n > 0)
111 add_random (cb->seed, &cb->pos, (BYTE*)buf, n);
112 add_random (cb->seed, &cb->pos, (BYTE*)&a, 4);
113 a = GetWindowThreadProcessId (h, NULL);
114 add_random (cb->seed, &cb->pos, (BYTE*)&a, 4);
115 GetWindowPlacement (h, &p);
116 add_random (cb->seed, &cb->pos, (BYTE*)&p, sizeof (p));
117 GetWindowRect (h, &r);
118 add_random (cb->seed, &cb->pos, (BYTE*)&r, sizeof (r));
119 return TRUE;
120 }
121
122
123 /* Initialize the seed with all kind of system variables. */
124 static void
125 init_random (unsigned char *seed)
126 {
127 int pos=0;
128 DWORD buf[16];
129 int i=0;
130
131 buf[i++] = (DWORD)GetActiveWindow ();
132 buf[i++] = (DWORD)GetCapture ();
133 buf[i++] = (DWORD)GetClipboardOwner ();
134 buf[i++] = (DWORD)GetClipboardViewer ();
135 buf[i++] = (DWORD)GetCurrentProcess ();
136 buf[i++] = (DWORD)GetCurrentProcessId ();
137 buf[i++] = (DWORD)GetCurrentThread ();
138 buf[i++] = (DWORD)GetDesktopWindow ();
139 buf[i++] = (DWORD)GetFocus ();
140 buf[i++] = (DWORD)GetMessagePos ();
141 buf[i++] = (DWORD)GetOpenClipboardWindow ();
142 buf[i++] = (DWORD)GetProcessHeap ();
143 buf[i++] = (DWORD)GetProcessWindowStation ();
144 buf[i++] = (DWORD)GetQueueStatus (QS_ALLEVENTS);
145 buf[i] = (DWORD)GetTickCount ();
146 add_random (seed, &pos, (BYTE*)buf, 4*i);
147
148 {
149 POINT p;
150 GetCursorPos (&p);
151 add_random (seed, &pos, (BYTE*)&p, sizeof (p));
152 GetCaretPos (&p);
153 add_random (seed, &pos, (BYTE*)&p, sizeof (p));
154 }
155
156 {
157 STARTUPINFO inf;
158 inf.cb = sizeof (inf);
159 GetStartupInfo (&inf);
160 add_random (seed, &pos, (BYTE*)&inf, sizeof (inf));
161 }
162
163 {
164 MEMORYSTATUS st;
165
166 st.dwLength = sizeof (st);
167 GlobalMemoryStatus (&st);
168 add_random (seed, &pos, (BYTE*)&st, sizeof (st));
169 }
170
171 {
172 LARGE_INTEGER in;
173
174 QueryPerformanceFrequency (&in);
175 add_random (seed, &pos, (BYTE*)&in, sizeof (in));
176 QueryPerformanceCounter (&in);
177 add_random (seed, &pos, (BYTE*)&in, sizeof (in));
178 }
179 {
180 rnd.seed = seed;
181 rnd.pos = pos;
182 EnumChildWindows (GetDesktopWindow (), child_proc, (LPARAM)&rnd);
183 }
184
185 }
186
187
188 /* Initialize cipher with the seed as the key. */
189 static void
190 init_arcfour (struct arcfour_s *ctx, BYTE *key)
191 {
192 BYTE t;
193
194 ctx->i = 0;
195 ctx->j = 0;
196 for (ctx->i=0; ctx->i < 256; ctx->i++)
197 ctx->sbox[ctx->i] = (BYTE)ctx->i;
198 for (ctx->i=0; ctx->i < 256; ctx->i++) {
199 ctx->j += (ctx->j+ctx->sbox[ctx->i]+key[ctx->i]);
200 ctx->j &= 255;
201 t = ctx->sbox[ctx->i];
202 ctx->sbox[ctx->i] = ctx->sbox[ctx->j];
203 ctx->sbox[ctx->j] = t;
204 }
205 }
206
207
208 /* Generate a single random byte. If the cipher is not
209 init, do an init first. */
210 static BYTE
211 rnd_byte (void)
212 {
213 struct arcfour_s *ctx = &rnd;
214 BYTE t;
215
216 if (!init_done) {
217 BYTE buf[256];
218 init_random (buf);
219 init_arcfour (ctx, buf);
220 init_done = 1;
221 }
222
223 ctx->i++; ctx->i &= 255;
224 ctx->j += ctx->sbox[ctx->i]; ctx->j &= 255;
225 t = ctx->sbox[ctx->i];
226 ctx->sbox[ctx->i] = ctx->sbox[ctx->j];
227 ctx->sbox[ctx->j] = t;
228 return ctx->sbox[(ctx->sbox[ctx->i] + ctx->sbox[ctx->j]) & 255];
229 }
230
231
232 /* Generate a single alpha-num charactor. */
233 static char
234 random_char (void)
235 {
236 byte c = 0;
237
238 while (!isalnum(c))
239 c = rnd_byte ();
240 return c % 127;
241 }
242
243
244 /* Use the file handle in the context to overwrite a file
245 with prepared buffer contents. */
246 static void
247 overwrite (wipe_context_s *ctx)
248 {
249 DDWORD blocks = 0, mod = 0;
250 DWORD nwritten = 0;
251 LONG size_high = 0;
252
253 blocks = ctx->filesize / ctx->buffsize;
254 mod = ctx->filesize % ctx->buffsize;
255 SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);
256 while (blocks--) {
257 if (!WriteFile (ctx->fd, ctx->buffer, ctx->buffsize, &nwritten, NULL))
258 break;
259 ctx->offset += nwritten;
260 if (unlink_cb)
261 unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,
262 (unsigned)ctx->filesize*ctx->n_passes);
263 }
264 if (mod) {
265 WriteFile (ctx->fd, ctx->buffer, (DWORD)mod, &nwritten, NULL);
266 ctx->offset += nwritten;
267 if (unlink_cb)
268 unlink_cb (unlink_cb_value, ctx->name, 0, (unsigned)ctx->offset,
269 (unsigned)ctx->filesize*ctx->n_passes);
270 }
271 FlushFileBuffers (ctx->fd);
272 SetFilePointer (ctx->fd, 0, &size_high, FILE_BEGIN);
273 }
274
275
276 /* fill the buffer with random of the given level. */
277 static void
278 randomize_buffer (byte *buf, size_t bufsize)
279 {
280 const int blocksize = 512;
281 int blocks = bufsize / blocksize;
282 int mod = bufsize % blocksize;
283 int i;
284
285 while (blocks--) {
286 for (i=0; i < blocksize; i++)
287 buf[i] = rnd_byte ();
288 buf += blocksize;
289 }
290 for (i=0; i < mod; i++)
291 buf[i] = rnd_byte ();
292 }
293
294
295 /* performs a random overwrite. */
296 static void
297 overwrite_random (int npasses, wipe_context_s * ctx)
298 {
299 int i;
300
301 for (i = 0; i < npasses; i++) {
302 randomize_buffer (ctx->buffer, ctx->buffsize);
303 overwrite (ctx);
304 }
305 }
306
307
308 /* perform an overwrite with a specific byte (like 0x00). */
309 static void
310 overwrite_byte (int byte, wipe_context_s * ctx)
311 {
312 memset (ctx->buffer, byte, ctx->buffsize);
313 overwrite (ctx);
314 } /* overwrite_byte */
315
316
317 /* perform an overwrite with a specific byte triple (like 0x00, 0xFF, 0xAA). */
318 static void
319 overwrite_bytes (int byte1, int byte2, int byte3, wipe_context_s * ctx)
320 {
321 DWORD i;
322
323 memset (ctx->buffer, byte1, ctx->buffsize);
324 for (i = 1; i < ctx->buffsize; i += 3) {
325 ctx->buffer[i] = byte2;
326 ctx->buffer[i+1] = byte3;
327 }
328 overwrite (ctx);
329 } /* overwrite_bytes */
330
331
332 /* For the case the file is not a regular file (this is true for
333 devices or directories) this function tries to rename the file
334 to random pattern and then it will be delete (without random!). */
335 extern "C" int
336 rename_unlink (const char *path)
337 {
338 struct stat statbuf;
339 char *new_name = NULL, *p = NULL, c;
340 int i = 0, rc = 0;
341 int is_dir = 0;
342
343 if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)
344 is_dir = 1;
345
346 new_name = new char[strlen (path)+15];
347 if (!new_name)
348 BUG (0);
349
350 strcpy (new_name, path);
351 p = strrchr (new_name, '\\');
352 if (p != NULL) {
353 p++;
354 *p = '\0';
355 }
356 else
357 p = new_name;
358 do {
359 while (i < 14) {
360 c = random_char ();
361 *p = c;
362 p++;
363 i++;
364 }
365 *p = '\0';
366 } while (stat (new_name, &statbuf) == 0);
367
368 if (rename (path, new_name) == -1) {
369 rc = WPTERR_FILE_READ;
370 goto leave;
371 }
372 if (is_dir && RemoveDirectory (new_name) == FALSE)
373 rc = WPTERR_FILE_REMOVE;
374 else if (!DeleteFile (new_name))
375 rc = WPTERR_FILE_REMOVE;
376
377 leave:
378 free_if_alloc (new_name);
379 return rc;
380 }
381
382
383 /* return the filesize as an 64-bit integer. */
384 static DDWORD
385 GetFileSize64 (const char * path)
386 {
387 FILE *fp = fopen (path, "r");
388 if (fp) {
389 struct _stati64 statbuf;
390 if (_fstati64 (fileno (fp), &statbuf) == -1)
391 return -1;
392 fclose (fp);
393 return statbuf.st_size;
394 }
395 return -1;
396 }
397
398
399 static int
400 _secure_unlink (const char * path, int mode, HANDLE *r_fd)
401 {
402 wipe_context_s ctx;
403 LONG size_high = 0;
404
405 if (GetFileAttributes (path) & FILE_ATTRIBUTE_DIRECTORY)
406 return rename_unlink (path);
407
408 memset (&ctx, 0, sizeof (ctx));
409 ctx.name = path;
410 ctx.buffsize = 16384;
411 ctx.buffer = new byte[ctx.buffsize];
412 if (!ctx.buffer)
413 BUG (0);
414
415 ctx.filesize = GetFileSize64 (path);
416 if (!ctx.filesize) {
417 free_if_alloc (ctx.buffer);
418 unlink (path);
419 return 0;
420 }
421
422 ctx.fd = CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
423 OPEN_ALWAYS, 0, NULL);
424 if (ctx.fd == INVALID_HANDLE_VALUE) {
425 free_if_alloc (ctx.buffer);
426 return WPTERR_FILE_OPEN;
427 }
428 else if (r_fd)
429 *r_fd = ctx.fd;
430
431 if (unlink_cb)
432 unlink_cb (unlink_cb_value, ctx.name, 0, 0, 0);
433
434 switch (mode) {
435 case WIPE_MODE_FAST:
436 ctx.n_passes = 1;
437 overwrite_random (1, &ctx);
438 break;
439
440 case WIPE_MODE_SIMPLE:
441 ctx.n_passes = 2;
442 overwrite_random (2, &ctx);
443 break;
444
445 case WIPE_MODE_DOD:
446 ctx.n_passes = 5;
447 overwrite_random (1, &ctx);
448 overwrite_byte ((~1) & 0xFF, &ctx);
449 overwrite_random (1, &ctx);
450 overwrite_byte ((~4) & 0xFF, &ctx);
451 overwrite_random (1, &ctx);
452 break;
453
454 case WIPE_MODE_GUTMANN:
455 ctx.n_passes = 39;
456 overwrite_random (4, &ctx);
457 overwrite_byte( 0x55, &ctx );
458 overwrite_byte ( 0xAA, &ctx );
459 overwrite_bytes( 0x92, 0x49, 0x24, &ctx );
460 overwrite_bytes( 0x49, 0x24, 0x92, &ctx );
461 overwrite_bytes( 0x24, 0x92, 0x49, &ctx );
462 overwrite_byte( 0x00, &ctx );
463 overwrite_byte( 0x11, &ctx );
464 overwrite_byte( 0x22, &ctx );
465 overwrite_byte( 0x33, &ctx );
466 overwrite_byte( 0x44, &ctx );
467 overwrite_byte( 0x55, &ctx );
468 overwrite_byte( 0x66, &ctx );
469 overwrite_byte( 0x77, &ctx );
470 overwrite_byte( 0x88, &ctx );
471 overwrite_byte( 0x99, &ctx );
472 overwrite_byte( 0xAA, &ctx );
473 overwrite_byte( 0xBB, &ctx );
474 overwrite_byte( 0xCC, &ctx );
475 overwrite_byte( 0xDD, &ctx );
476 overwrite_byte( 0xEE, &ctx );
477 overwrite_byte( 0xFF, &ctx );
478 overwrite_bytes( 0x92, 0x49, 0x24, &ctx );
479 overwrite_bytes( 0x49, 0x24, 0x92, &ctx );
480 overwrite_bytes( 0x24, 0x92, 0x49, &ctx );
481 overwrite_bytes( 0x6D, 0xB6, 0xDB, &ctx );
482 overwrite_bytes( 0xB6, 0xDB, 0x6D, &ctx );
483 overwrite_bytes( 0xDB, 0x6D, 0xB6, &ctx );
484 overwrite_random( 4, &ctx );
485 break;
486 }
487
488 /* Set file length to zero so allocated clusters cannot be trailed */
489 SetFilePointer (ctx.fd, 0, &size_high, FILE_BEGIN);
490 SetEndOfFile (ctx.fd);
491 CloseHandle (ctx.fd);
492
493 memset (ctx.buffer, 0, ctx.buffsize); /* burn the last evidence */
494 free_if_alloc (ctx.buffer);
495
496 return rename_unlink (path);
497 }
498
499
500 /* Delete a file in a secure way with the given mode @mode. */
501 extern "C" int
502 secure_unlink (const char *path, int mode)
503 {
504 /* If the file has one of the following attributes, the
505 chance the file really gets overwritten is very low so
506 we just to an unlink to spare time and entropy. */
507 DWORD attr = GetFileAttributes (path);
508 if ((attr & FILE_ATTRIBUTE_COMPRESSED) ||
509 (attr & FILE_ATTRIBUTE_ENCRYPTED) ||
510 (attr & FILE_ATTRIBUTE_SPARSE_FILE))
511 return DeleteFile (path); /* XXX */
512 return _secure_unlink (path, mode, NULL);
513 }
514
515
516 /* Set the callback @cb for the wipe function. The callback is call every time
517 the wipe function writes data to the file. */
518 extern "C" void
519 secure_unlink_set_cb (void (*cb)(void *, const char *, int, int, int),
520 void *cb_value)
521 {
522 unlink_cb = cb;
523 unlink_cb_value = cb_value;
524 }
525
526
527 /* wipe all free space of the given drive by creating a temp file
528 which has the size of the free space. This file will be then
529 overwritten with random and static pattern. */
530 extern "C" int
531 wipe_freespace (const char * drive, HANDLE *r_fd,
532 void (*cb)(void *, DDWORD, DDWORD), void * cb_value)
533 {
534 ULARGE_INTEGER caller, total, frees;
535 LONG hpart=0;
536 HANDLE fd;
537 int disktyp = GetDriveType (drive);
538 int rc;
539 char * file;
540
541 if (disktyp != DRIVE_FIXED && disktyp != DRIVE_REMOVABLE)
542 return -1;
543 if (!GetDiskFreeSpaceEx (drive, &caller, &total, &frees))
544 return -1;
545
546 /* disk is full */
547 if (!frees.LowPart)
548 return 0;
549 file = new char[strlen (drive)+8];
550 if (!file)
551 BUG (0);
552 sprintf (file, "%stemp_winpt.tmp", drive);
553 fd = CreateFile (file,
554 GENERIC_READ|GENERIC_WRITE,
555 FILE_SHARE_READ|FILE_SHARE_WRITE,
556 NULL, CREATE_ALWAYS, 0, NULL);
557 if (fd == INVALID_HANDLE_VALUE) {
558 free_if_alloc (file);
559 return WPTERR_FILE_OPEN;
560 }
561 hpart = frees.HighPart;
562 SetFilePointer (fd, frees.LowPart, &hpart, FILE_BEGIN);
563 SetEndOfFile (fd);
564 CloseHandle (fd);
565
566 if (cb && cb_value) {
567 progress_cb = cb;
568 progress_cb_value = cb_value;
569 }
570 rc = _secure_unlink (file, WIPE_MODE_FAST, r_fd);
571 free_if_alloc (file);
572 return rc;
573 }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26