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

Annotation of /trunk/PTD/wptWipeFile.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 53 - (hide 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 werner 46 /* 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 twoaday 53 #ifdef _MSC_VER
48 werner 46 typedef unsigned __int64 DDWORD;
49 twoaday 53 #else
50     typedef unsigned long long DDWORD;
51     #endif
52 werner 46
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 twoaday 53 struct arcfour_s {
64     BYTE *seed;
65     int pos;
66     BYTE sbox[256];
67     DWORD i;
68     DWORD j;
69     };
70 werner 46
71 twoaday 53
72 werner 46 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 twoaday 53 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 werner 46 /* 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 twoaday 53 randomize_buffer (byte *buf, size_t bufsize)
279 werner 46 {
280     const int blocksize = 512;
281     int blocks = bufsize / blocksize;
282     int mod = bufsize % blocksize;
283 twoaday 53 int i;
284    
285 werner 46 while (blocks--) {
286 twoaday 53 for (i=0; i < blocksize; i++)
287     buf[i] = rnd_byte ();
288 werner 46 buf += blocksize;
289     }
290 twoaday 53 for (i=0; i < mod; i++)
291     buf[i] = rnd_byte ();
292 werner 46 }
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 twoaday 53 randomize_buffer (ctx->buffer, ctx->buffsize);
303 werner 46 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 twoaday 53 c = random_char ();
361 werner 46 *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 twoaday 53 static DDWORD
385 werner 46 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 twoaday 53 /* Delete a file in a secure way with the given mode @mode. */
501 werner 46 extern "C" int
502     secure_unlink (const char *path, int mode)
503     {
504 twoaday 53 /* 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 werner 46 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