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

Annotation of /trunk/PTD/wptWipeFile.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (hide 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 twoaday 2 /* 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 twoaday 23 void (*unlink_cb)(void *, const char *, int, int, int) = NULL;
60 twoaday 2 static void *unlink_cb_value = NULL;
61    
62 twoaday 23 /* Use the file handle in the context to overwrite a file
63     with prepared buffer contents. */
64 twoaday 2 static void
65 twoaday 23 overwrite (wipe_context_s *ctx)
66 twoaday 2 {
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 twoaday 23 }
92 twoaday 2
93    
94 twoaday 23 /* fill the buffer with random of the given level. */
95 twoaday 2 static void
96 twoaday 23 randomize_buffer (byte *buf, size_t bufsize, int level)
97 twoaday 2 {
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 twoaday 23 }
109 twoaday 2
110    
111 twoaday 23 /* performs a random overwrite. */
112     static void
113 twoaday 2 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 twoaday 23 }
122 twoaday 2
123    
124 twoaday 23 /* perform an overwrite with a specific byte (like 0x00). */
125 twoaday 2 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 twoaday 23 /* perform an overwrite with a specific byte triple (like 0x00, 0xFF, 0xAA). */
134 twoaday 2 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 twoaday 23 /* 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 twoaday 2 int
152 twoaday 23 rename_unlink (const char *path)
153 twoaday 2 {
154     struct stat statbuf;
155 twoaday 23 char *new_name = NULL, *p = NULL, c;
156 twoaday 2 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 twoaday 23 p++;
179 twoaday 2 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 twoaday 23 }
197 twoaday 2
198    
199 twoaday 23 /* return the filesize as an 64-bit integer. */
200 twoaday 2 static __int64
201     GetFileSize64 (const char * path)
202     {
203     FILE *fp = fopen (path, "r");
204     if (fp) {
205     struct _stati64 statbuf;
206 twoaday 23 if (_fstati64 (fileno (fp), &statbuf) == -1)
207     return -1;
208 twoaday 2 fclose (fp);
209     return statbuf.st_size;
210     }
211     return -1;
212 twoaday 23 }
213 twoaday 2
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 twoaday 5 unlink (path);
235     return 0;
236 twoaday 2 }
237    
238 twoaday 23 ctx.fd = CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
239 twoaday 2 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 twoaday 23
317     /* Delete a file in a secure way with the given mode. */
318 twoaday 2 int
319     secure_unlink (const char *path, int mode)
320     {
321     return _secure_unlink (path, mode, NULL);
322 twoaday 23 }
323 twoaday 2
324    
325 twoaday 23 /* Set the callback @cb for the wipe function. The callback is call every time
326     the wipe function writes data to the file. */
327 twoaday 2 void
328 twoaday 23 secure_unlink_set_cb (void (*cb)(void *, const char *, int, int, int),
329 twoaday 2 void *cb_value)
330     {
331     unlink_cb = cb;
332     unlink_cb_value = cb_value;
333 twoaday 23 }
334 twoaday 2
335    
336 twoaday 23 /* 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 twoaday 2 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 twoaday 23 return -1;
354 twoaday 2
355 twoaday 5 /* disk is full */
356 twoaday 2 if (!frees.LowPart)
357 twoaday 5 return 0;
358 twoaday 2 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 twoaday 23 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26