Passa al contenuto principale

8. C Code for SHAs, HMAC, and HKDF (Codice C per SHA, HMAC e HKDF)

Di seguito è riportata un'implementazione dimostrativa di queste funzioni hash sicure in C. La sezione 8.1 contiene il file di intestazione sha.h che dichiara tutte le costanti, strutture e funzioni utilizzate dalle funzioni SHA e HMAC. Include condizionali basati sullo stato di definizione di USE_32BIT_ONLY che, se quel simbolo è definito al momento della compilazione, evita operazioni a 64 bit. Contiene anche sha-private.h che fornisce alcune dichiarazioni comuni a tutte le funzioni SHA. La sezione 8.2 contiene il codice C per sha1.c, sha224-256.c, sha384-512.c e usha.c. La sezione 8.3 contiene il codice C per le funzioni HMAC e la sezione 8.4 contiene il codice C per HKDF. La sezione 8.5 contiene un driver di test per esercitare il codice.

Panoramica API (API Overview)

Per ciascuna delle lunghezze di digest $$$, esiste il seguente insieme di costanti, una struttura e funzioni:

Costanti (Constants):

  • SHA$$$HashSize - numero di ottetti nell'hash
  • SHA$$$HashSizeBits - numero di bit nell'hash
  • SHA$$$_Message_Block_Size - numero di ottetti utilizzati nei blocchi di messaggio intermedi

La maggior parte delle funzioni restituisce un valore di enumerazione che è uno dei seguenti:

  • shaSuccess(0) - in caso di successo
  • shaNull(1) - quando viene presentato un parametro puntatore nullo
  • shaInputTooLong(2) - quando i dati di input sono troppo lunghi
  • shaStateError(3) - quando SHA$$$Input viene chiamato dopo SHA$$$FinalBits o SHA$$$Result

Struttura (Structure):

typedef SHA$$$Context

Una struttura opaca che contiene lo stato completo per produrre l'hash

Funzioni (Functions):

int SHA$$$Reset(SHA$$$Context *context);

Ripristinare lo stato del contesto hash.

int SHA$$$Input(SHA$$$Context *context, const uint8_t *octets,
unsigned int bytecount);

Incorporare bytecount ottetti nell'hash.

int SHA$$$FinalBits(SHA$$$Context *, const uint8_t octet,
unsigned int bitcount);

Incorporare bitcount bit nell'hash. I bit si trovano nella porzione superiore dell'ottetto. SHA$$$Input() non può essere chiamato dopo questo.

int SHA$$$Result(SHA$$$Context *,
uint8_t Message_Digest[SHA$$$HashSize]);

Eseguire i calcoli finali sull'hash e copiare il valore in Message_Digest.

Interfaccia USHA (USHA Interface)

Inoltre, vengono fornite funzioni con il prefisso USHA che accettano un valore SHAversion (SHA$$$) per selezionare la suite di funzioni SHA. Aggiungono le seguenti costanti, struttura e funzioni:

Costanti (Constants):

  • shaBadParam(4) - costante restituita dalle funzioni USHA quando viene presentato un parametro SHAversion (SHA$$$) errato o altri valori di parametro illegali
  • USAMaxHashSize - massimo delle dimensioni hash SHA
  • SHA$$$ - valori di enumerazione SHAversion, utilizzati dalle funzioni USHA, HMAC e HKDF per selezionare la suite di funzioni SHA

Struttura (Structure):

typedef USHAContext

Una struttura opaca che contiene lo stato completo per produrre l'hash

Funzioni (Functions):

int USHAReset(USHAContext *context, SHAversion whichSha);

Ripristinare lo stato del contesto hash.

int USHAInput(USHAContext context*,
const uint8_t *bytes, unsigned int bytecount);

Incorporare bytecount ottetti nell'hash.

int USHAFinalBits(USHAContext *context,
const uint8_t bits, unsigned int bitcount);

Incorporare bitcount bit nell'hash.

int USHAResult(USHAContext *context,
uint8_t Message_Digest[USHAMaxHashSize]);

Eseguire i calcoli finali sull'hash e copiare il valore in Message_Digest. Gli ottetti in Message_Digest oltre USHAHashSize(whichSha) vengono lasciati intatti.

int USHAHashSize(enum SHAversion whichSha);

Il numero di ottetti nell'hash dato.

int USHAHashSizeBits(enum SHAversion whichSha);

Il numero di bit nell'hash dato.

int USHABlockSize(enum SHAversion whichSha);

La dimensione del blocco interno per l'hash dato.

const char *USHAHashName(enum SHAversion whichSha);

Questa funzione restituirà il nome dell'algoritmo SHA dato come stringa.

Interfaccia HMAC (HMAC Interface)

Le funzioni HMAC seguono lo stesso schema per consentire l'utilizzo di qualsiasi lunghezza di input di testo.

Struttura (Structure):

typedef HMACContext

Una struttura opaca che contiene lo stato completo per produrre il digest di messaggio con chiave (MAC)

Funzioni (Functions):

int hmacReset(HMACContext *ctx, enum SHAversion whichSha,
const unsigned char *key, int key_len);

Ripristinare lo stato del contesto MAC.

int hmacInput(HMACContext *ctx, const unsigned char *text,
int text_len);

Incorporare text_len ottetti nel MAC.

int hmacFinalBits(HMACContext *ctx, const uint8_t bits,
unsigned int bitcount);

Incorporare bitcount bit nel MAC.

int hmacResult(HMACContext *ctx,
uint8_t Message_Digest[USHAMaxHashSize]);

Eseguire i calcoli finali sul MAC e copiare il valore in Message_Digest.

Inoltre, vengono fornite interfacce combinate, simili a quelle mostrate in [RFC2104], che consentono l'utilizzo di un input di testo a lunghezza fissa:

int hmac(SHAversion whichSha,
const unsigned char *text, int text_len,
const unsigned char *key, int key_len,
uint8_t digest[USHAMaxHashSize])

Questa interfaccia combinata esegue il calcolo HMAC completo. Le variabili sono le stesse delle chiamate separate di cui sopra.

Interfaccia HKDF (HKDF Interface)

Le funzioni HKDF sono strutturate in modo simile alle funzioni HMAC.

Struttura (Structure):

typedef HKDFContext

Una struttura opaca che contiene lo stato completo per eseguire la derivazione di chiavi HKDF extract-and-expand

Funzioni (Functions):

int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
const unsigned char *salt, int salt_len);

Ripristinare lo stato del contesto HKDF.

int hkdfInput(HKDFContext *context, const unsigned char *ikm,
int ikm_len);

Incorporare ikm_len ottetti nell'estrattore di entropia.

int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
unsigned int ikm_bit_count)

Incorporare ikm_bit_count bit nell'estrattore di entropia.

int hkdfResult(HKDFContext *context,
uint8_t prk[USHAMaxHashSize],
const unsigned char *info, int info_len,
uint8_t okm[ ], int okm_len)

Completare l'estrazione HKDF ed eseguire l'espansione HKDF finale, memorizzando gli okm_len ottetti nel materiale chiave di output (okm). Memorizzare opzionalmente la chiave pseudocasuale (prk) generata internamente.

Inoltre, vengono fornite interfacce combinate, simili a quelle mostrate in [RFC5869], che consentono l'utilizzo di un input di testo a lunghezza fissa:

int hkdfExtract(SHAversion whichSha,
const unsigned char *salt, int salt_len,
const unsigned char *ikm, int ikm_len,
uint8_t prk[USHAMaxHashSize])

Eseguire l'estrazione HKDF, combinando gli salt_len ottetti del sale opzionale con gli ikm_len ottetti del materiale chiave di input (ikm) per formare la chiave pseudocasuale prk. L'output prk deve essere abbastanza grande da contenere gli ottetti appropriati per il tipo di hash dato.

int hkdfExpand(SHAversion whichSha,
const uint8_t prk[ ], int prk_len,
const unsigned char *info, int info_len,
uint8_t okm[ ], int okm_len)

Eseguire l'espansione HKDF, combinando gli prk_len ottetti della chiave pseudocasuale prk con gli info_len ottetti di info per formare gli okm_len ottetti memorizzati in okm.

int hkdf(SHAversion whichSha,
const unsigned char *salt, int salt_len,
const unsigned char *ikm, int ikm_len,
const unsigned char *info, int info_len,
uint8_t okm[ ], int okm_len)

Questa interfaccia combinata esegue sia l'estrazione che l'espansione HKDF. Le variabili sono le stesse di hkdfExtract() e hkdfExpand().

Sottosezioni (Subsections)