mirror of
https://github.com/martijnvanbrummelen/nwipe.git
synced 2026-02-20 13:42:14 +00:00
Refactor CPUID/AES-NI detection into cpu_features module and hide AES-CTR PRNG on unsupported platforms (#695)
* Refactor CPUID/AES-NI detection into cpu_features module and hide AES-CTR PRNG on unsupported platforms This commit improves CPU feature handling and PRNG selection logic in three ways: 1. Introduces a dedicated cpu_features.c/.h module that encapsulates CPUID and AES-NI detection. The previous duplicated inline implementations scattered across multiple files have been removed to prevent multiple-definition issues and ensure consistent CPU capability probing. 2. The AES-CTR PRNG is now selectable only when the running platform supports AES-NI. The ncurses GUI automatically hides the AES-CTR option when AES-NI is not available, preventing users from choosing a PRNG that would fall back to software mode or incur unnecessary slowdown. CLI selection (--prng=aes_ctr_prng) is also blocked on non-AES-NI CPUs with a clear error. 3. All modules (options, GUI, PRNG initialisation) now use the central has_aes_ni() function, ensuring uniform and future-proof feature detection. * cpu_features.* missing in commit * AES-CTR not removed, but disabled when not available on platform
This commit is contained in:
@@ -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)
|
||||
|
||||
44
src/cpu_features.c
Normal file
44
src/cpu_features.c
Normal file
@@ -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
|
||||
}
|
||||
18
src/cpu_features.h
Normal file
18
src/cpu_features.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef NWIPE_CPU_FEATURES_H
|
||||
#define NWIPE_CPU_FEATURES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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 */
|
||||
147
src/gui.c
147
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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user