From e9b126d24f8d188a224126394a39e7fbe1b26734 Mon Sep 17 00:00:00 2001 From: Fabian Druschke Date: Sun, 10 Mar 2024 16:09:52 -0300 Subject: [PATCH] Several changes, adding AES-128 using libssl in CTR mode as new PRNG, in experimental state. Fixed formatting, fixed AES PRNG header. --- src/Makefile.am | 6 ++--- src/aes/aes_ctr_prng.c | 52 ++++++++++++++++++++++++++++++++++++++++++ src/aes/aes_ctr_prng.h | 22 ++++++++++++++++++ src/gui.c | 24 +++++++++++++++++-- src/options.c | 14 +++++++++++- src/prng.c | 46 +++++++++++++++++++++++++++++++++++++ src/prng.h | 49 +++++++++++++++------------------------ 7 files changed, 176 insertions(+), 37 deletions(-) create mode 100644 src/aes/aes_ctr_prng.c create mode 100644 src/aes/aes_ctr_prng.h diff --git a/src/Makefile.am b/src/Makefile.am index 7d9bb444..c73df5fd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,10 +1,10 @@ # what flags you want to pass to the C compiler & linker #CFLAGS = -lncurses -lparted -AM_CFLAGS = -AM_LDFLAGS = +AM_CFLAGS = +AM_LDFLAGS = -lcrypto # 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 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 aes/aes_ctr_prng.h aes/aes_ctr_prng.c 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_LDADD = $(PARTED_LIBS) $(LIBCONFIG) diff --git a/src/aes/aes_ctr_prng.c b/src/aes/aes_ctr_prng.c new file mode 100644 index 00000000..a5698c50 --- /dev/null +++ b/src/aes/aes_ctr_prng.c @@ -0,0 +1,52 @@ +#include "aes_ctr_prng.h" +#include +#include +// #include // Necessary for printf +#include +#include + +void aes_ctr_prng_init( aes_ctr_state_t* state, unsigned long init_key[], unsigned long key_length ) +{ + unsigned char key[16]; // Expanded to 128 Bit + memset( key, 0, 16 ); + + // printf("Original key length (in unsigned long units): %lu\n", key_length); + // printf("Original key (64 Bit): %016lx\n", init_key[0]); + + // Repeat the 64-bit key to create a 128-bit key. + for( size_t i = 0; i < 16; i++ ) + { + key[i] = ( (unsigned char*) init_key )[i % 8]; + } + + AES_set_encrypt_key( key, 128, &state->aes_key ); // 128 Bit key + memset( state->ivec, 0, AES_BLOCK_SIZE ); + state->num = 0; + memset( state->ecount, 0, AES_BLOCK_SIZE ); +} + +static void next_state( aes_ctr_state_t* state ) +{ + for( int i = 0; i < AES_BLOCK_SIZE; ++i ) + { + if( ++state->ivec[i] ) + break; + } +} + +unsigned long aes_ctr_prng_genrand_uint32( aes_ctr_state_t* state ) +{ + unsigned long result = 0; + + CRYPTO_ctr128_encrypt( (unsigned char*) &result, + (unsigned char*) &result, + sizeof( result ), + &state->aes_key, + state->ivec, + state->ecount, + &state->num, + (block128_f) AES_encrypt ); + next_state( state ); // Ensure this function does not cause errors + + return result & 0xFFFFFFFF; +} diff --git a/src/aes/aes_ctr_prng.h b/src/aes/aes_ctr_prng.h new file mode 100644 index 00000000..34877442 --- /dev/null +++ b/src/aes/aes_ctr_prng.h @@ -0,0 +1,22 @@ +#ifndef AES_CTR_RNG_H +#define AES_CTR_RNG_H + +#include +#include + +// Structure to store the state of the AES-CTR random number generator +typedef struct +{ + AES_KEY aes_key; + unsigned char ivec[AES_BLOCK_SIZE]; + unsigned int num; + unsigned char ecount[AES_BLOCK_SIZE]; +} aes_ctr_state_t; + +// Initializes the AES-CTR random number generator +void init_aes_ctr( aes_ctr_state_t* state, const unsigned char* key ); + +// Generates a 32-bit integer using AES-CTR +unsigned int aes_ctr_generate_uint32( aes_ctr_state_t* state ); + +#endif // AES_CTR_RNG_H diff --git a/src/gui.c b/src/gui.c index 9c34910b..e2316d28 100644 --- a/src/gui.c +++ b/src/gui.c @@ -1599,10 +1599,11 @@ void nwipe_gui_prng( void ) extern nwipe_prng_t nwipe_twister; extern nwipe_prng_t nwipe_isaac; extern nwipe_prng_t nwipe_isaac64; + extern nwipe_prng_t nwipe_aes_ctr_prng; extern int terminate_signal; /* The number of implemented PRNGs. */ - const int count = 3; + const int count = 4; /* The first tabstop. */ const int tab1 = 2; @@ -1636,6 +1637,10 @@ void nwipe_gui_prng( void ) { focus = 2; } + if( nwipe_options.prng == &nwipe_aes_ctr_prng ) + { + focus = 3; + } do { @@ -1651,6 +1656,7 @@ void nwipe_gui_prng( void ) mvwprintw( main_window, yy++, tab1, " %s", nwipe_twister.label ); mvwprintw( main_window, yy++, tab1, " %s", nwipe_isaac.label ); mvwprintw( main_window, yy++, tab1, " %s", nwipe_isaac64.label ); + mvwprintw( main_window, yy++, tab1, " %s", nwipe_aes_ctr_prng.label ); yy++; /* Print the cursor. */ @@ -1733,8 +1739,18 @@ void nwipe_gui_prng( void ) tab1, "Performs best on a 64-bit CPU. Use ISAAC if this system has a 32-bit CPU. " ); break; + case 3: - } /* switch */ + mvwprintw( main_window, + yy++, + tab1, + "AES-CTR Ni Prototype " ); + break; + + } + + + /* switch */ /* Add a border. */ box( main_window, 0, 0 ); @@ -1794,6 +1810,10 @@ void nwipe_gui_prng( void ) { nwipe_options.prng = &nwipe_isaac64; } + if( focus == 3 ) + { + nwipe_options.prng = &nwipe_aes_ctr_prng; + } return; case KEY_BACKSPACE: diff --git a/src/options.c b/src/options.c index 95050db8..8d556f71 100644 --- a/src/options.c +++ b/src/options.c @@ -42,6 +42,7 @@ int nwipe_options_parse( int argc, char** argv ) extern nwipe_prng_t nwipe_twister; extern nwipe_prng_t nwipe_isaac; extern nwipe_prng_t nwipe_isaac64; + extern nwipe_prng_t nwipe_aes_ctr_prng; /* The getopt() result holder. */ int nwipe_opt; @@ -490,6 +491,11 @@ int nwipe_options_parse( int argc, char** argv ) nwipe_options.prng = &nwipe_isaac64; break; } + if( strcmp( optarg, "aes_ctr_prng" ) == 0 ) + { + nwipe_options.prng = &nwipe_aes_ctr_prng; + break; + } /* Else we do not know this PRNG. */ fprintf( stderr, "Error: Unknown prng '%s'.\n", optarg ); @@ -539,6 +545,8 @@ void nwipe_options_log( void ) extern nwipe_prng_t nwipe_twister; extern nwipe_prng_t nwipe_isaac; extern nwipe_prng_t nwipe_isaac64; + extern nwipe_prng_t nwipe_aes_ctr_prng; + /** * Prints a manifest of options to the log. @@ -590,6 +598,10 @@ void nwipe_options_log( void ) { nwipe_log( NWIPE_LOG_NOTICE, " prng = Mersenne Twister" ); } + if( nwipe_options.prng == &nwipe_aes_ctr_prng ) + { + nwipe_log( NWIPE_LOG_NOTICE, " prng = AES-CTR New Instructions (EXPERIMENTAL!)" ); + } else { if( nwipe_options.prng == &nwipe_isaac ) @@ -681,7 +693,7 @@ void display_help() puts( " -l, --logfile=FILE Filename to log to. Default is STDOUT\n" ); puts( " -P, --PDFreportpath=PATH Path to write PDF reports to. Default is \".\"" ); puts( " If set to \"noPDF\" no PDF reports are written.\n" ); - puts( " -p, --prng=METHOD PRNG option (mersenne|twister|isaac|isaac64)\n" ); + puts( " -p, --prng=METHOD PRNG option (mersenne|twister|isaac|isaac64|aes-ctr)\n" ); puts( " -q, --quiet Anonymize logs and the GUI by removing unique data, i.e." ); puts( " serial numbers, LU WWN Device ID, and SMBIOS/DMI data" ); puts( " XXXXXX = S/N exists, ????? = S/N not obtainable\n" ); diff --git a/src/prng.c b/src/prng.c index 45c6cb76..17e3ab29 100644 --- a/src/prng.c +++ b/src/prng.c @@ -25,12 +25,17 @@ #include "mt19937ar-cok/mt19937ar-cok.h" #include "isaac_rand/isaac_rand.h" #include "isaac_rand/isaac64.h" +#include "aes/aes_ctr_prng.h" // AES-NI prototype nwipe_prng_t nwipe_twister = { "Mersenne Twister (mt19937ar-cok)", nwipe_twister_init, nwipe_twister_read }; nwipe_prng_t nwipe_isaac = { "ISAAC (rand.c 20010626)", nwipe_isaac_init, nwipe_isaac_read }; nwipe_prng_t nwipe_isaac64 = { "ISAAC-64 (isaac64.c)", nwipe_isaac64_init, nwipe_isaac64_read }; +/* AES-CTR-NI PRNG Structure */ +nwipe_prng_t nwipe_aes_ctr_prng = { "AES-CTR-PRNG", nwipe_aes_ctr_prng_init, nwipe_aes_ctr_prng_read }; + + /* Print given number of bytes from unsigned integer number to a byte stream buffer starting with low-endian. */ static inline void u32_to_buffer( u8* restrict buffer, u32 val, const int len ) { @@ -250,3 +255,44 @@ int nwipe_isaac64_read( NWIPE_PRNG_READ_SIGNATURE ) return 0; } + + +/* EXPERIMENTAL implementation of AES-128 in counter mode to provide high-quality random numbers */ + +int nwipe_aes_ctr_prng_init( NWIPE_PRNG_INIT_SIGNATURE ) +{ + nwipe_log( NWIPE_LOG_NOTICE, "Initialising AES CTR PRNG" ); + + if( *state == NULL ) + { + /* This is the first time that we have been called. */ + *state = malloc( sizeof( aes_ctr_state_t ) ); + } + aes_ctr_prng_init( (aes_ctr_state_t*) *state, (unsigned long*) ( seed->s ), seed->length / sizeof( unsigned long ) ); + + return 0; +} + +int nwipe_aes_ctr_prng_read( NWIPE_PRNG_READ_SIGNATURE ) +{ + u8* restrict bufpos = buffer; + size_t words = count / SIZE_OF_AES_CTR_PRNG; // the values of aes_ctr_prng_genrand_uint32 is strictly 4 bytes + + /* AES CTR PRNG returns 4-bytes per call, so progress by 4 bytes. */ + for( size_t ii = 0; ii < words; ++ii ) + { + u32_to_buffer( bufpos, aes_ctr_prng_genrand_uint32( (aes_ctr_state_t*) *state ), SIZE_OF_AES_CTR_PRNG ); + bufpos += SIZE_OF_AES_CTR_PRNG; + } + + /* If there is some remainder copy only relevant number of bytes to not overflow the buffer. */ + const size_t remain = count % SIZE_OF_AES_CTR_PRNG; // SIZE_OF_AES_CTR_PRNG is strictly 4 bytes + if( remain > 0 ) + { + u32_to_buffer( bufpos, aes_ctr_prng_genrand_uint32( (aes_ctr_state_t*) *state ), remain ); + } + + return 0; +} + + diff --git a/src/prng.h b/src/prng.h index 8dfa3d72..7063aecd 100644 --- a/src/prng.h +++ b/src/prng.h @@ -1,23 +1,3 @@ -/* - * prng.h: Pseudo Random Number Generator abstractions for nwipe. - * - * Copyright Darik Horn . - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - #ifndef PRNG_H_ #define PRNG_H_ @@ -34,26 +14,30 @@ typedef struct #define NWIPE_PRNG_READ_SIGNATURE void **state, void *buffer, size_t count /* Function pointers for PRNG actions. */ -typedef int ( *nwipe_prng_init_t )( NWIPE_PRNG_INIT_SIGNATURE ); -typedef int ( *nwipe_prng_read_t )( NWIPE_PRNG_READ_SIGNATURE ); +typedef int (*nwipe_prng_init_t)(NWIPE_PRNG_INIT_SIGNATURE); +typedef int (*nwipe_prng_read_t)(NWIPE_PRNG_READ_SIGNATURE); /* The generic PRNG definition. */ typedef struct { - const char* label; // The name of the pseudo random number generator. - nwipe_prng_init_t init; // Inialize the prng state with the seed. - nwipe_prng_read_t read; // Read data from the prng. + const char* label; // The name of the pseudo random number generator. + nwipe_prng_init_t init; // Initialize the prng state with the seed. + nwipe_prng_read_t read; // Read data from the prng. } nwipe_prng_t; /* Mersenne Twister prototypes. */ -int nwipe_twister_init( NWIPE_PRNG_INIT_SIGNATURE ); -int nwipe_twister_read( NWIPE_PRNG_READ_SIGNATURE ); +int nwipe_twister_init(NWIPE_PRNG_INIT_SIGNATURE); +int nwipe_twister_read(NWIPE_PRNG_READ_SIGNATURE); /* ISAAC prototypes. */ -int nwipe_isaac_init( NWIPE_PRNG_INIT_SIGNATURE ); -int nwipe_isaac_read( NWIPE_PRNG_READ_SIGNATURE ); -int nwipe_isaac64_init( NWIPE_PRNG_INIT_SIGNATURE ); -int nwipe_isaac64_read( NWIPE_PRNG_READ_SIGNATURE ); +int nwipe_isaac_init(NWIPE_PRNG_INIT_SIGNATURE); +int nwipe_isaac_read(NWIPE_PRNG_READ_SIGNATURE); +int nwipe_isaac64_init(NWIPE_PRNG_INIT_SIGNATURE); +int nwipe_isaac64_read(NWIPE_PRNG_READ_SIGNATURE); + +/* AES-CTR-NI prototypes. */ +int nwipe_aes_ctr_prng_init(NWIPE_PRNG_INIT_SIGNATURE); +int nwipe_aes_ctr_prng_read(NWIPE_PRNG_READ_SIGNATURE); /* Size of the twister is not derived from the architecture, but it is strictly 4 bytes */ #define SIZE_OF_TWISTER 4 @@ -62,4 +46,7 @@ int nwipe_isaac64_read( NWIPE_PRNG_READ_SIGNATURE ); #define SIZE_OF_ISAAC 4 #define SIZE_OF_ISAAC64 8 +/* Size of the AES-CTR is not derived from the architecture, but it is strictly 4 or 8 bytes */ +#define SIZE_OF_AES_CTR_PRNG 4 + #endif /* PRNG_H_ */