void *nwipe_dod522022m( void *ptr ) { /** * United States Department of Defense 5220.22-M standard wipe. * */ nwipe_context_t *c; c = (nwipe_context_t *) ptr; /* A result holder. */ int r; /* Random characters. (Elements 2 and 6 are unused.) */ char dod [7]; nwipe_pattern_t patterns [] = { { 1, &dod[0] }, /* Pass 1: A random character. */ { 1, &dod[1] }, /* Pass 2: The bitwise complement of pass 1. */ { -1, "" }, /* Pass 3: A random stream. */ { 1, &dod[3] }, /* Pass 4: A random character. */ { 1, &dod[4] }, /* Pass 5: A random character. */ { 1, &dod[5] }, /* Pass 6: The bitwise complement of pass 5. */ { -1, "" }, /* Pass 7: A random stream. */ { 0, NULL } }; /* Load the array with random characters. */ r = read( c->entropy_fd, &dod, sizeof( dod ) ); /* NOTE: Only the random data in dod[0], dod[3], and dod[4] is actually used. */ /* Check the result. */ if( r != sizeof( dod ) ) { r = errno; nwipe_perror( r, __FUNCTION__, "read" ); nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the %s method.", nwipe_dod522022m_label ); /* Ensure a negative return. */ if( r < 0 ) { c->result = r; return NULL; } else { c->result = -1; return NULL; } } /* Pass 2 is the bitwise complement of Pass 1. */ dod[1] = ~ dod[0]; /* Pass 4 is the bitwise complement of Pass 3. */ dod[5] = ~ dod[4]; /* Run the DoD 5220.22-M method. */ c->result = nwipe_runmethod( c, patterns ); /* Finished. Set the thread ID to 0 so that the GUI knows */ c->thread = 0; return NULL; } /* nwipe_dod522022m */
int check_device( nwipe_context_t*** c, PedDevice* dev, int dcount ) { /* Populate this struct, then assign it to overall array of structs. */ nwipe_context_t* next_device; /* Try opening the device to see if it's valid. Close on completion. */ if (!ped_device_open(dev)) return 0; ped_device_close(dev); /* New device, reallocate memory for additional struct pointer */ *c = realloc (*c, (dcount+1) * sizeof(nwipe_context_t *)); next_device = malloc (sizeof(nwipe_context_t)); /* Check the allocation. */ if( ! next_device ) { nwipe_perror( errno, __FUNCTION__, "malloc" ); nwipe_log( NWIPE_LOG_FATAL, "Unable to create the array of enumeration contexts." ); return 0; } /* Zero the allocation. */ memset( next_device , 0, sizeof( nwipe_context_t ) ); /* Get device information */ next_device->label = dev->model; next_device->device_name = dev->path; next_device->device_size = dev->length * dev->sector_size; /* Attempt to get serial number of device. */ ioctl(next_device->device_fd, HDIO_GET_IDENTITY, &next_device->identity); (*c)[dcount] = next_device; return 1; }
int nwipe_runmethod( nwipe_context_t* c, nwipe_pattern_t* patterns ) { /** * Writes patterns to the device. * */ /* The result holder. */ int r; /* An index variable. */ int i = 0; /* The zero-fill pattern for the final pass of most methods. */ nwipe_pattern_t pattern_zero = { 1, "\x00" }; /* Create the PRNG state buffer. */ c->prng_seed.length = NWIPE_KNOB_PRNG_STATE_LENGTH; c->prng_seed.s = malloc( c->prng_seed.length ); /* Check the memory allocation. */ if( ! c->prng_seed.s ) { nwipe_perror( errno, __FUNCTION__, "malloc" ); nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate memory for the prng seed buffer." ); return -1; } /* Count the number of patterns in the array. */ while( patterns[i].length ) { i += 1; } /* Tell the parent the number of device passes that will be run in one round. */ c->pass_count = i; /* Set the number of bytes that will be written across all passes in one round. */ c->pass_size = c->pass_count * c->device_size; if( nwipe_options.verify == NWIPE_VERIFY_ALL ) { /* We must read back all passes, so double the byte count. */ c->pass_size *= 2; } /* Tell the parent the number of rounds that will be run. */ c->round_count = nwipe_options.rounds; /* Set the number of bytes that will be written across all rounds. */ c->round_size = c->round_count * c->pass_size; /* The final pass is always a zero fill, except ops2 which is random. */ /* Do not add if there is no blanking pass. */ if ( nwipe_options.noblank == 0 ) { c->round_size += c->device_size; } /* Set the round total count down */ c->result = c->round_size; if((nwipe_options.verify == NWIPE_VERIFY_LAST || nwipe_options.verify == NWIPE_VERIFY_ALL) && nwipe_options.noblank == 0 ) { /* We must read back the last pass to verify it. */ c->round_size += c->device_size; } /* Initialize the working round counter. */ c->round_working = 0; nwipe_log( NWIPE_LOG_NOTICE, "Invoking method '%s' on device '%s'.", \ nwipe_method_label( nwipe_options.method ), c->device_name ); while( c->round_working < c->round_count ) { /* Increment the round counter. */ c->round_working += 1; nwipe_log( NWIPE_LOG_NOTICE, "Starting round %i of %i on device '%s'.", \ c->round_working, c->round_count, c->device_name ); /* Initialize the working pass counter. */ c->pass_working = 0; for( i = 0 ; i < c->pass_count ; i++ ) { /* Increment the working pass. */ c->pass_working += 1; nwipe_log( NWIPE_LOG_NOTICE, "Starting pass %i of %i, round %i of %i, on device '%s'.", \ c->pass_working, c->pass_count, c->round_working, c->round_count, c->device_name ); if( patterns[i].length == 0 ) { /* Caught insanity. */ nwipe_log( NWIPE_LOG_SANITY, "nwipe_runmethod: A non-terminating pattern element has zero length." ); return -1; } if( patterns[i].length > 0 ) { /* Write a static pass. */ c->pass_type = NWIPE_PASS_WRITE; r = nwipe_static_pass( c, &patterns[i] ); c->pass_type = NWIPE_PASS_NONE; /* Log number of bytes written to disk */ nwipe_log( NWIPE_LOG_NOTICE, "%llu bytes written to device '%s'.", \ c->pass_done, c->device_name ); /* Check for a fatal error. */ if( r < 0 ) { return r; } if( nwipe_options.verify == NWIPE_VERIFY_ALL ) { nwipe_log( NWIPE_LOG_NOTICE, "Verifying pass %i of %i, round %i of %i, on device '%s'.", \ c->pass_working, c->pass_count, c->round_working, c->round_count, c->device_name ); /* Verify this pass. */ c->pass_type = NWIPE_PASS_VERIFY; r = nwipe_static_verify( c, &patterns[i] ); c->pass_type = NWIPE_PASS_NONE; /* Check for a fatal error. */ if( r < 0 ) { return r; } nwipe_log( NWIPE_LOG_NOTICE, "Verified pass %i of %i, round %i of %i, on device '%s'.", \ c->pass_working, c->pass_count, c->round_working, c->round_count, c->device_name ); } } /* static pass */ else { c->pass_type = NWIPE_PASS_WRITE; /* Seed the PRNG. */ r = read( c->entropy_fd, c->prng_seed.s, c->prng_seed.length ); /* Check the result. */ if( r < 0 ) { c->pass_type = NWIPE_PASS_NONE; nwipe_perror( errno, __FUNCTION__, "read" ); nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the PRNG." ); return -1; } /* Check for a partial read. */ if( r != c->prng_seed.length ) { /* TODO: Handle partial reads. */ nwipe_log( NWIPE_LOG_FATAL, "Insufficient entropy is available." ); return -1; } /* Write the random pass. */ r = nwipe_random_pass( c ); c->pass_type = NWIPE_PASS_NONE; /* Log number of bytes written to disk */ nwipe_log( NWIPE_LOG_NOTICE, "%llu bytes written to device '%s'.", \ c->pass_done, c->device_name ); /* Check for a fatal error. */ if( r < 0 ) { return r; } if( nwipe_options.verify == NWIPE_VERIFY_ALL ) { nwipe_log( NWIPE_LOG_NOTICE, "Verifying pass %i of %i, round %i of %i, on device '%s'.", \ c->pass_working, c->pass_count, c->round_working, c->round_count, c->device_name ); /* Verify this pass. */ c->pass_type = NWIPE_PASS_VERIFY; r = nwipe_random_verify( c ); c->pass_type = NWIPE_PASS_NONE; /* Check for a fatal error. */ if( r < 0 ) { return r; } nwipe_log( NWIPE_LOG_NOTICE, "Verified pass %i of %i, round %i of %i, on device '%s'.", \ c->pass_working, c->pass_count, c->round_working, c->round_count, nwipe_method_label( nwipe_options.method ) ); } } /* random pass */ nwipe_log( NWIPE_LOG_NOTICE, "Finished pass %i of %i, round %i of %i, on device '%s'.", \ c->pass_working, c->pass_count, c->round_working, c->round_count, c->device_name ); } /* for passes */ nwipe_log( NWIPE_LOG_NOTICE, "Finished round %i of %i on device '%s'.", \ c->round_working, c->round_count, c->device_name ); } /* while rounds */ if( nwipe_options.method == &nwipe_ops2 ) { /* NOTE: The OPS-II method specifically requires that a random pattern be left on the device. */ /* Tell the parent that we are running the final pass. */ c->pass_type = NWIPE_PASS_FINAL_OPS2; /* Seed the PRNG. */ r = read( c->entropy_fd, c->prng_seed.s, c->prng_seed.length ); /* Check the result. */ if( r < 0 ) { nwipe_perror( errno, __FUNCTION__, "read" ); nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the PRNG." ); return -1; } /* Check for a partial read. */ if( r != c->prng_seed.length ) { /* TODO: Handle partial reads. */ nwipe_log( NWIPE_LOG_FATAL, "Insufficient entropy is available." ); return -1; } nwipe_log( NWIPE_LOG_NOTICE, "Writing final random pattern to '%s'.", c->device_name ); /* The final ops2 pass. */ r = nwipe_random_pass( c ); /* Check for a fatal error. */ if( r < 0 ) { return r; } if( nwipe_options.verify == NWIPE_VERIFY_LAST || nwipe_options.verify == NWIPE_VERIFY_ALL ) { nwipe_log( NWIPE_LOG_NOTICE, "Verifying the final random pattern on '%s' is empty.", c->device_name ); /* Verify the final zero pass. */ r = nwipe_random_verify( c ); /* Check for a fatal error. */ if( r < 0 ) { return r; } nwipe_log( NWIPE_LOG_NOTICE, "Verified the final random pattern on '%s' is empty.", c->device_name ); } nwipe_log( NWIPE_LOG_NOTICE, "Wrote final random pattern to '%s'.", c->device_name ); } /* final ops2 */ else if (nwipe_options.noblank == 0) { /* Tell the user that we are on the final pass. */ c->pass_type = NWIPE_PASS_FINAL_BLANK; nwipe_log( NWIPE_LOG_NOTICE, "Blanking device '%s'.", c->device_name ); /* The final zero pass. */ r = nwipe_static_pass( c, &pattern_zero ); /* Check for a fatal error. */ if( r < 0 ) { return r; } if( nwipe_options.verify == NWIPE_VERIFY_LAST || nwipe_options.verify == NWIPE_VERIFY_ALL ) { nwipe_log( NWIPE_LOG_NOTICE, "Verifying that '%s' is empty.", c->device_name ); /* Verify the final zero pass. */ r = nwipe_static_verify( c, &pattern_zero ); /* Check for a fatal error. */ if( r < 0 ) { return r; } nwipe_log( NWIPE_LOG_NOTICE, "Verified that '%s' is empty.", c->device_name ); } nwipe_log( NWIPE_LOG_NOTICE, "Blanked device '%s'.", c->device_name ); } /* final blank */ /* Release the state buffer. */ c->prng_seed.length = 0; free( c->prng_seed.s ); /* Tell the parent that we have fininshed the final pass. */ c->pass_type = NWIPE_PASS_NONE; if( c->verify_errors > 0 ) { /* We finished, but with non-fatal verification errors. */ nwipe_log( NWIPE_LOG_ERROR, "%llu verification errors on device '%s'.", c->verify_errors, c->device_name ); } if( c->pass_errors > 0 ) { /* We finished, but with non-fatal wipe errors. */ nwipe_log( NWIPE_LOG_ERROR, "%llu wipe errors on device '%s'.", c->pass_errors, c->device_name ); } /* FIXME: The 'round_errors' context member is not being used. */ if( c->pass_errors > 0 || c->round_errors > 0 || c->verify_errors > 0 ) { /* We finished, but with non-fatal errors. */ return 1; } /* We finished successfully. */ return 0; } /* nwipe_runmethod */
void *nwipe_ops2( void *ptr ) { /** * Royal Canadian Mounted Police * Technical Security Standard for Information Technology * Appendix OPS-II: Media Sanitization * * NOTE: The last pass of this method is specially handled by nwipe_runmethod. * */ nwipe_context_t *c; c = (nwipe_context_t *) ptr; /* A generic array index. */ int i; /* A generic result buffer. */ int r; /* A buffer for random characters. */ char* s; /* A buffer for the bitwise complements of 's'. */ char* t; /* The element count of 's' and 't'. */ u32 u; /* The pattern array for this method is dynamically allocated. */ nwipe_pattern_t* patterns; /* The element count of 'patterns'. */ u32 q; /* We need one random character per round. */ u = 1 * nwipe_options.rounds; /* Allocate the array of random characters. */ s = malloc( sizeof( char ) * u ); if( s == NULL ) { nwipe_perror( errno, __FUNCTION__, "malloc" ); nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate the random character array." ); c->result = -1; return NULL; } /* Allocate the array of complement characters. */ t = malloc( sizeof( char ) * u ); if( t == NULL ) { nwipe_perror( errno, __FUNCTION__, "malloc" ); nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate the complement character array." ); c->result = -1; free(s); return NULL; } /* We need eight pattern elements per round, plus one for padding. */ q = 8 * u + 1; /* Allocate the pattern array. */ patterns = malloc( sizeof( nwipe_pattern_t ) * q ); if( patterns == NULL ) { nwipe_perror( errno, __FUNCTION__, "malloc" ); nwipe_log( NWIPE_LOG_FATAL, "Unable to allocate the pattern array." ); c->result = -1; free(s); free(t); return NULL; } /* Load the array of random characters. */ r = read( c->entropy_fd, s, u ); if( r != u ) { r = errno; nwipe_perror( r, __FUNCTION__, "read" ); nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the %s method.", nwipe_ops2_label ); if( r < 0 ) { c->result = r; free(s); free(t); free(patterns); return NULL; } else { c->result = -1; free(s); free(t); free(patterns); return NULL; } } for( i = 0 ; i < u ; i += 1 ) { /* Populate the array of complements. */ t[i] = ~s[i]; } for( i = 0 ; i < u ; i += 8 ) { /* Populate the array of patterns. */ /* Even elements point to the random characters. */ patterns[i*4 +0].length = 1; patterns[i*4 +0].s = &s[i]; patterns[i*4 +2].length = 1; patterns[i*4 +2].s = &s[i]; patterns[i*4 +4].length = 1; patterns[i*4 +4].s = &s[i]; patterns[i*4 +6].length = 1; patterns[i*4 +6].s = &s[i]; /* Odd elements point to the complement characters. */ patterns[i*4 +1].length = 1; patterns[i*4 +1].s = &t[i]; patterns[i*4 +3].length = 1; patterns[i*4 +3].s = &t[i]; patterns[i*4 +5].length = 1; patterns[i*4 +5].s = &t[i]; patterns[i*4 +7].length = 1; patterns[i*4 +7].s = &t[i]; } /* Ensure that the array is terminated. */ patterns[q-1].length = 0; patterns[q-1].s = NULL; /* Run the TSSIT OPS-II method. */ r = nwipe_runmethod( c, patterns ); /* Release the random character buffer. */ free( s ); /* Release the complement character buffer */ free( t ); /* Release the pattern buffer. */ free( patterns ); /* We're done. */ c->result = nwipe_runmethod( c, patterns ); /* Finished. Set the thread ID to 0 so that the GUI knows */ c->thread = 0; return NULL; } /* nwipe_ops2 */
void *nwipe_gutmann( void *ptr ) { /** * Peter Gutmann's wipe. * */ nwipe_context_t *c; c = (nwipe_context_t *) ptr; /* A result buffer. */ int r; /* The number of patterns in the Guttman Wipe, also used to index the 'patterns' array. */ int i = 35; /* An index into the 'book' array. */ int j; /* The N-th element that has not been used. */ int n; /* Define the Gutmann method. */ nwipe_pattern_t book [] = { { -1, "" }, /* Random pass. */ { -1, "" }, /* Random pass. */ { -1, "" }, /* Random pass. */ { -1, "" }, /* Random pass. */ { 3, "\x55\x55\x55" }, /* Static pass: 0x555555 01010101 01010101 01010101 */ { 3, "\xAA\xAA\xAA" }, /* Static pass: 0XAAAAAA 10101010 10101010 10101010 */ { 3, "\x92\x49\x24" }, /* Static pass: 0x924924 10010010 01001001 00100100 */ { 3, "\x49\x24\x92" }, /* Static pass: 0x492492 01001001 00100100 10010010 */ { 3, "\x24\x92\x49" }, /* Static pass: 0x249249 00100100 10010010 01001001 */ { 3, "\x00\x00\x00" }, /* Static pass: 0x000000 00000000 00000000 00000000 */ { 3, "\x11\x11\x11" }, /* Static pass: 0x111111 00010001 00010001 00010001 */ { 3, "\x22\x22\x22" }, /* Static pass: 0x222222 00100010 00100010 00100010 */ { 3, "\x33\x33\x33" }, /* Static pass: 0x333333 00110011 00110011 00110011 */ { 3, "\x44\x44\x44" }, /* Static pass: 0x444444 01000100 01000100 01000100 */ { 3, "\x55\x55\x55" }, /* Static pass: 0x555555 01010101 01010101 01010101 */ { 3, "\x66\x66\x66" }, /* Static pass: 0x666666 01100110 01100110 01100110 */ { 3, "\x77\x77\x77" }, /* Static pass: 0x777777 01110111 01110111 01110111 */ { 3, "\x88\x88\x88" }, /* Static pass: 0x888888 10001000 10001000 10001000 */ { 3, "\x99\x99\x99" }, /* Static pass: 0x999999 10011001 10011001 10011001 */ { 3, "\xAA\xAA\xAA" }, /* Static pass: 0xAAAAAA 10101010 10101010 10101010 */ { 3, "\xBB\xBB\xBB" }, /* Static pass: 0xBBBBBB 10111011 10111011 10111011 */ { 3, "\xCC\xCC\xCC" }, /* Static pass: 0xCCCCCC 11001100 11001100 11001100 */ { 3, "\xDD\xDD\xDD" }, /* Static pass: 0xDDDDDD 11011101 11011101 11011101 */ { 3, "\xEE\xEE\xEE" }, /* Static pass: 0xEEEEEE 11101110 11101110 11101110 */ { 3, "\xFF\xFF\xFF" }, /* Static pass: 0xFFFFFF 11111111 11111111 11111111 */ { 3, "\x92\x49\x24" }, /* Static pass: 0x924924 10010010 01001001 00100100 */ { 3, "\x49\x24\x92" }, /* Static pass: 0x492492 01001001 00100100 10010010 */ { 3, "\x24\x92\x49" }, /* Static pass: 0x249249 00100100 10010010 01001001 */ { 3, "\x6D\xB6\xDB" }, /* Static pass: 0x6DB6DB 01101101 10110110 11011011 */ { 3, "\xB6\xDB\x6D" }, /* Static pass: 0xB6DB6D 10110110 11011011 01101101 */ { 3, "\xDB\x6D\xB6" }, /* Static pass: 0XDB6DB6 11011011 01101101 10110110 */ { -1, "" }, /* Random pass. */ { -1, "" }, /* Random pass. */ { -1, "" }, /* Random pass. */ { -1, "" }, /* Random pass. */ { 0, NULL } }; /* Put the book array into this array in random order. */ nwipe_pattern_t patterns [36]; /* An entropy buffer. */ u16 s [i]; /* Load the array with random characters. */ r = read( c->entropy_fd, &s, sizeof( s ) ); if( r != sizeof( s ) ) { r = errno; nwipe_perror( r, __FUNCTION__, "read" ); nwipe_log( NWIPE_LOG_FATAL, "Unable to seed the %s method.", nwipe_gutmann_label ); /* Ensure a negative return. */ if( r < 0 ) { c->result = r; return NULL; } else { c->result = -1; return NULL; } } while( --i >= 0 ) { /* Get a random integer that is less than the first index 'i'. */ n = (int)( (double)( s[i] ) / (double)( 0x0000FFFF + 1 ) * (double)( i + 1 ) ); /* Initialize the secondary index. */ j = -1; while( n-- >= 0 ) { /* Advance 'j' by 'n' positions... */ j += 1; /* ... but don't count 'book' elements that have already been copied. */ while( book[j].length == 0 ) { j += 1; } } /* Copy the element. */ patterns[i] = book[j]; /* Mark this element as having been used. */ book[j].length = 0; nwipe_log( NWIPE_LOG_DEBUG, "nwipe_gutmann: Set patterns[%i] = book[%i].", i, j ); } /* Ensure that the array is terminated. */ patterns[35].length = 0; patterns[35].s = NULL; /* Run the Gutmann method. */ c->result = nwipe_runmethod( c, patterns ); /* Finished. Set the thread ID to 0 so that the GUI knows */ c->thread = 0; return NULL; } /* nwipe_gutmann */