diff --git a/src/Makefile.am b/src/Makefile.am index 58ae282..83d60e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,5 +6,5 @@ AM_LDFLAGS = # this lists the binaries to produce, the (non-PHONY, binary) targets in # the previous manual Makefile bin_PROGRAMS = nwipe -nwipe_SOURCES = context.h logging.h options.h prng.h version.h temperature.h nwipe.c gui.c method.h pass.c device.c gui.h isaac_rand/isaac_standard.h isaac_rand/isaac_rand.h isaac_rand/isaac_rand.c isaac_rand/isaac64.h isaac_rand/isaac64.c mt19937ar-cok/mt19937ar-cok.c nwipe.h mt19937ar-cok/mt19937ar-cok.h alfg/add_lagg_fibonacci_prng.h alfg/add_lagg_fibonacci_prng.c xor/xoroshiro256_prng.h xor/xoroshiro256_prng.c aes/aes_ctr_prng.h aes/aes_ctr_prng.cpp pass.h device.h logging.c method.c options.c prng.c version.c temperature.c PDFGen/pdfgen.h PDFGen/pdfgen.c create_pdf.c create_pdf.h embedded_images/shred_db.jpg.c embedded_images/shred_db.jpg.h embedded_images/tick_erased.jpg.c embedded_images/tick_erased.jpg.h embedded_images/redcross.c embedded_images/redcross.h hpa_dco.h hpa_dco.c miscellaneous.h miscellaneous.c embedded_images/nwipe_exclamation.jpg.h embedded_images/nwipe_exclamation.jpg.c conf.h conf.c customers.h customers.c hddtemp_scsi/hddtemp.h hddtemp_scsi/scsi.h hddtemp_scsi/scsicmds.h hddtemp_scsi/get_scsi_temp.c hddtemp_scsi/scsi.c hddtemp_scsi/scsicmds.c +nwipe_SOURCES = context.h logging.h options.h prng.h version.h temperature.h nwipe.c gui.c method.h pass.c device.c gui.h isaac_rand/isaac_standard.h isaac_rand/isaac_rand.h isaac_rand/isaac_rand.c isaac_rand/isaac64.h isaac_rand/isaac64.c mt19937ar-cok/mt19937ar-cok.c nwipe.h mt19937ar-cok/mt19937ar-cok.h alfg/add_lagg_fibonacci_prng.h alfg/add_lagg_fibonacci_prng.c xor/xoroshiro256_prng.h xor/xoroshiro256_prng.c aes/aes_ctr_prng.h aes/aes_ctr_prng.cpp pass.h device.h logging.c method.c options.c prng.c version.c temperature.c PDFGen/pdfgen.h PDFGen/pdfgen.c create_pdf.c create_pdf.h embedded_images/shred_db.jpg.c embedded_images/shred_db.jpg.h embedded_images/tick_erased.jpg.c embedded_images/tick_erased.jpg.h embedded_images/redcross.c embedded_images/redcross.h hpa_dco.h hpa_dco.c miscellaneous.h miscellaneous.c embedded_images/nwipe_exclamation.jpg.h embedded_images/nwipe_exclamation.jpg.c conf.h conf.c customers.h customers.c hddtemp_scsi/hddtemp.h hddtemp_scsi/scsi.h hddtemp_scsi/scsicmds.h hddtemp_scsi/get_scsi_temp.c hddtemp_scsi/scsi.c hddtemp_scsi/scsicmds.c cpu_features.h cpu_features.c nwipe_LDADD = $(PARTED_LIBS) $(LIBCONFIG) diff --git a/src/cpu_features.c b/src/cpu_features.c new file mode 100644 index 0000000..eeb5ef7 --- /dev/null +++ b/src/cpu_features.c @@ -0,0 +1,44 @@ +#include "cpu_features.h" + +/* + * Executes the CPUID instruction and fills out the provided variables with the results. + * eax: The function/subfunction number to query with CPUID. + * *eax_out, *ebx_out, *ecx_out, *edx_out: Pointers to variables where the CPUID output will be stored. + */ +void cpuid( uint32_t eax, uint32_t* eax_out, uint32_t* ebx_out, uint32_t* ecx_out, uint32_t* edx_out ) +{ +#if defined( __i386__ ) || defined( __x86_64__ ) /* only on x86 */ +#if defined( _MSC_VER ) /* MSVC */ + int r[4]; + __cpuid( r, eax ); + *eax_out = r[0]; + *ebx_out = r[1]; + *ecx_out = r[2]; + *edx_out = r[3]; +#elif defined( __GNUC__ ) /* GCC/Clang */ + __asm__ __volatile__( "cpuid" + : "=a"( *eax_out ), "=b"( *ebx_out ), "=c"( *ecx_out ), "=d"( *edx_out ) + : "a"( eax ) ); +#else +#error "Unsupported compiler" +#endif +#else /* not-x86 */ + (void) eax; + *eax_out = *ebx_out = *ecx_out = *edx_out = 0; /* CPUID = 0 */ +#endif +} + +/* + * Checks if the AES-NI instruction set is supported by the processor. + * Returns 1 (true) if supported, 0 (false) otherwise. + */ +int has_aes_ni( void ) +{ +#if defined( __i386__ ) || defined( __x86_64__ ) /* only for x86 */ + uint32_t eax, ebx, ecx, edx; + cpuid( 1, &eax, &ebx, &ecx, &edx ); + return ( ecx & ( 1u << 25 ) ) != 0; /* Bit 25 = AES-NI */ +#else /* ARM, RISC-V … */ + return 0; /* no AES-NI */ +#endif +} diff --git a/src/cpu_features.h b/src/cpu_features.h new file mode 100644 index 0000000..979a85c --- /dev/null +++ b/src/cpu_features.h @@ -0,0 +1,18 @@ +#ifndef NWIPE_CPU_FEATURES_H +#define NWIPE_CPU_FEATURES_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void cpuid( uint32_t eax, uint32_t* eax_out, uint32_t* ebx_out, uint32_t* ecx_out, uint32_t* edx_out ); + +int has_aes_ni( void ); + +#ifdef __cplusplus +} +#endif + +#endif /* NWIPE_CPU_FEATURES_H */ diff --git a/src/gui.c b/src/gui.c index 8f8155a..bbbe3cd 100644 --- a/src/gui.c +++ b/src/gui.c @@ -64,6 +64,7 @@ #include "customers.h" #include "conf.h" #include "unistd.h" +#include "cpu_features.h" #define NWIPE_GUI_PANE 8 @@ -1647,6 +1648,7 @@ void nwipe_gui_prng( void ) extern int terminate_signal; /* The number of implemented PRNGs. */ + const int aes_ctr_available = has_aes_ni(); const int count = 6; /* The first tabstop. */ @@ -1709,7 +1711,19 @@ void nwipe_gui_prng( void ) mvwprintw( main_window, yy++, tab1, " %s", nwipe_isaac64.label ); mvwprintw( main_window, yy++, tab1, " %s", nwipe_add_lagg_fibonacci_prng.label ); mvwprintw( main_window, yy++, tab1, " %s", nwipe_xoroshiro256_prng.label ); - mvwprintw( main_window, yy++, tab1, " %s", nwipe_aes_ctr_prng.label ); + /* AES-CTR: visually indicate “not available” if no AES-NI */ + if( aes_ctr_available ) + { + mvwprintw( main_window, yy++, tab1, " %s", nwipe_aes_ctr_prng.label ); + } + else + { + /* Dim + “(N/A)” suffix. You can also combine A_REVERSE + * when focused; here only text is dimmed. */ + wattron( main_window, A_DIM ); + mvwprintw( main_window, yy++, tab1, " %s (N/A)", nwipe_aes_ctr_prng.label ); + wattroff( main_window, A_DIM ); + } yy++; /* Print the cursor. */ @@ -1884,33 +1898,64 @@ void nwipe_gui_prng( void ) tab1, "especially for legacy systems, due to its efficiency and minimal demands. " ); break; - case 5: - mvwprintw( - main_window, yy++, tab1, "AES-256 in Counter Mode (CTR), securely implemented by Fabian Druschke" ); - mvwprintw( main_window, yy++, tab1, "using the Linux kernel's AF_ALG cryptographic API for efficient" ); - mvwprintw( main_window, yy++, tab1, "pseudo-random data generation with minimal user-space overhead." ); - mvwprintw( main_window, - yy++, - tab1, - " " ); - mvwprintw( - main_window, yy++, tab1, "This integration leverages potential hardware acceleration via AES-NI," ); - mvwprintw( - main_window, yy++, tab1, "making AES-256 CTR ideal for secure and fast data wiping in nwipe." ); - mvwprintw( main_window, - yy++, - tab1, - " " ); - mvwprintw( main_window, - yy++, - tab1, - "Compliant with NIST SP 800-38A, it is a global standard for encryption." ); - mvwprintw( - main_window, yy++, tab1, "Designed for 64-bit Linux systems with kernel CryptoAPI support." ); - break; - } + case 5: { + extern int has_aes_ni( void ); + const int aes_ctr_available = has_aes_ni(); - /* switch */ + if( aes_ctr_available ) + { + mvwprintw( main_window, + yy++, + tab1, + "AES-256 in Counter Mode (CTR), securely implemented by Fabian Druschke" ); + mvwprintw( + main_window, yy++, tab1, "using the Linux kernel's AF_ALG cryptographic API for efficient" ); + mvwprintw( + main_window, yy++, tab1, "pseudo-random data generation with minimal user-space overhead." ); + mvwprintw( main_window, + yy++, + tab1, + " " ); + mvwprintw( main_window, + yy++, + tab1, + "This integration leverages potential hardware acceleration via AES-NI," ); + mvwprintw( + main_window, yy++, tab1, "making AES-256 CTR ideal for secure and fast data wiping in nwipe." ); + mvwprintw( main_window, + yy++, + tab1, + " " ); + mvwprintw( main_window, + yy++, + tab1, + "Compliant with NIST SP 800-38A, it is a global standard for encryption." ); + mvwprintw( + main_window, yy++, tab1, "Designed for 64-bit Linux systems with kernel CryptoAPI support." ); + } + else + { + /* Dimmed, shortened explanation when AES-NI is not available. */ + wattron( main_window, A_DIM ); + + mvwprintw( main_window, yy++, tab1, "AES-256 in Counter Mode (CTR) PRNG (N/A on this system)" ); + mvwprintw( + main_window, yy++, tab1, "This PRNG uses AES-NI acceleration via the Linux kernel CryptoAPI." ); + mvwprintw( main_window, yy++, tab1, "It is not available because your CPU does not support the" ); + mvwprintw( main_window, yy++, tab1, "required AES-NI instruction set." ); + mvwprintw( main_window, + yy++, + tab1, + " " ); + mvwprintw( + main_window, yy++, tab1, "You can still use all other PRNGs (e.g. xoroshiro-256, ISAAC, MT)." ); + + wattroff( main_window, A_DIM ); + } + + break; + } + } /* Add a border. */ box( main_window, 0, 0 ); @@ -1928,9 +1973,9 @@ void nwipe_gui_prng( void ) * sluggish, any slower and more time is spent unnecessarily looping * which wastes CPU cycles. */ - timeout( 250 ); // block getch() for 250ms. - keystroke = getch(); // Get a keystroke. - timeout( -1 ); // Switch back to blocking mode. + timeout( 250 ); /* block getch() for 250ms */ + keystroke = getch(); /* Get a keystroke. */ + timeout( -1 ); /* Switch back to blocking mode. */ switch( keystroke ) { @@ -1956,34 +2001,60 @@ void nwipe_gui_prng( void ) case KEY_ENTER: case ' ': - case 10: + case 10: { + int selection_made = 0; if( focus == 0 ) { nwipe_options.prng = &nwipe_twister; + selection_made = 1; } - if( focus == 1 ) + else if( focus == 1 ) { nwipe_options.prng = &nwipe_isaac; + selection_made = 1; } - if( focus == 2 ) + else if( focus == 2 ) { nwipe_options.prng = &nwipe_isaac64; + selection_made = 1; } - if( focus == 3 ) + else if( focus == 3 ) { nwipe_options.prng = &nwipe_add_lagg_fibonacci_prng; + selection_made = 1; } - if( focus == 4 ) + else if( focus == 4 ) { nwipe_options.prng = &nwipe_xoroshiro256_prng; + selection_made = 1; } - if( focus == 5 ) + else if( focus == 5 ) { - nwipe_options.prng = &nwipe_aes_ctr_prng; + if( aes_ctr_available ) + { + /* AES-CTR selectable only when AES-NI is available. */ + nwipe_options.prng = &nwipe_aes_ctr_prng; + selection_made = 1; + } + else + { + /* Visible but disabled: do not change selection and + * do not close the dialog. Give feedback only. */ + beep(); + selection_made = 0; + } } - return; + if( selection_made ) + { + /* Close the dialog only on a valid selection. */ + return; + } + + /* No valid selection (e.g. AES-CTR without AES-NI): stay in dialog. */ + break; + } case KEY_BACKSPACE: case KEY_BREAK: diff --git a/src/options.c b/src/options.c index f47ac9a..d29bca5 100644 --- a/src/options.c +++ b/src/options.c @@ -28,53 +28,11 @@ #include "logging.h" #include "version.h" #include "conf.h" +#include "cpu_features.h" /* The global options struct. */ nwipe_options_t nwipe_options; -/* - * Executes the CPUID instruction and fills out the provided variables with the results. - * eax: The function/subfunction number to query with CPUID. - * *eax_out, *ebx_out, *ecx_out, *edx_out: Pointers to variables where the CPUID output will be stored. - */ -void cpuid( uint32_t eax, uint32_t* eax_out, uint32_t* ebx_out, uint32_t* ecx_out, uint32_t* edx_out ) -{ -#if defined( __i386__ ) || defined( __x86_64__ ) /* only on x86 */ -#if defined( _MSC_VER ) /* MSVC */ - int r[4]; - __cpuid( r, eax ); - *eax_out = r[0]; - *ebx_out = r[1]; - *ecx_out = r[2]; - *edx_out = r[3]; -#elif defined( __GNUC__ ) /* GCC/Clang */ - __asm__ __volatile__( "cpuid" - : "=a"( *eax_out ), "=b"( *ebx_out ), "=c"( *ecx_out ), "=d"( *edx_out ) - : "a"( eax ) ); -#else -#error "Unsupported compiler" -#endif -#else /* not-x86 */ - (void) eax; - *eax_out = *ebx_out = *ecx_out = *edx_out = 0; /* CPUID = 0 */ -#endif -} - -/* - * Checks if the AES-NI instruction set is supported by the processor. - * Returns 1 (true) if supported, 0 (false) otherwise. - */ -int has_aes_ni( void ) -{ -#if defined( __i386__ ) || defined( __x86_64__ ) /* only for x86 */ - uint32_t eax, ebx, ecx, edx; - cpuid( 1, &eax, &ebx, &ecx, &edx ); - return ( ecx & ( 1u << 25 ) ) != 0; /* Bit 25 = AES-NI */ -#else /* ARM, RISC-V … */ - return 0; /* no AES-NI */ -#endif -} - int nwipe_options_parse( int argc, char** argv ) { extern char* optarg; // The working getopt option argument. @@ -661,7 +619,17 @@ int nwipe_options_parse( int argc, char** argv ) } if( strcmp( optarg, "aes_ctr_prng" ) == 0 ) { - nwipe_options.prng = &nwipe_aes_ctr_prng; + if( has_aes_ni() ) + { + nwipe_options.prng = &nwipe_aes_ctr_prng; + } + else + { + fprintf( stderr, + "Error: aes_ctr_prng requires AES-NI on this build, " + "but your CPU does not support AES-NI.\n" ); + exit( EINVAL ); + } break; }