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

Contents of /trunk/PTD/wptWipeFile.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26