Hash-Based MAC

Module Functionality
Provides hashed-based message authentication code (HMAC) functionality. HMAC is essentially a hash with its state transformed using a key before and after the data is hashed. Standard hashes verify that data has not changed. HMAC also ensures that only an entity with the key can sign and verify the message.

Enumerations

enum cryptx_hash_algorithms

Supported hash algorithms.

Values:

enumerator SHA256

algorithm type identifier for SHA-256

enumerator SHA1

algorithm type identifier for SHA-1

Macros

CRYPTX_DIGESTLEN_SHA1

digest length for SHA-1 hash

CRYPTX_DIGESTLEN_SHA256

digest length for SHA-256 hash

Functions

bool cryptx_hmac_init(struct cryptx_hmac_ctx *context, const void *key, size_t keylen, uint8_t hash_alg)

Initializes a context for a specific HMAC algorithm.

Parameters
  • context – Pointer to a context.

  • key – Pointer to a key used to initialize the HMAC state.

  • keylen – Length of the key.

  • hash_alg – The numeric ID of the hashing algorithm to use. See cryptx_hash_algorithms.

Returns

true if initialized succeeded, false if failed.

void cryptx_hmac_update(struct cryptx_hmac_ctx *context, const void *data, size_t len)

Updates the context for a given block of data.

Parameters
  • context – Pointer to an HMAC-state context.

  • data – Pointer to a block of data to hash..

  • len – Size of the data to hash.

void cryptx_hmac_digest(struct cryptx_hmac_ctx *context, void *digest)

Output digest for current context (preserves state).

Parameters
  • context – Pointer to a context.

  • digest – Pointer to a buffer to write digest to.

char *msg = "Hash this string";
crytx_hmac_ctx h;
#define HMAC_KLEN 16
uint8_t hmac_key[HMAC_KLEN];
cryptx_csrand_fill(hmac_key, HMAC_KLEN);

// initialize hash
cryptx_hmac_init(&h, hmac_key, HMAC_KEN, SHA256);

// allocate buffer for digest
uint8_t digest[h.digest_len];

// hash the string
cryptx_hmac_update(&h, msg, strlen(msg));

// return the digest
cryptx_hmac_digest(&h, digest);

Password-Based Key Derivation

Password-Based Key Derivation Function Two (PBKDF2) is a function that uses an HMAC algorithm to generate a key from a password. This is normally used to generate encryption keys. You can also probably get away with using to encrypt passwords for storage on your calculator. It’s certainly not the most secure password hashing algorithm, but for most on-calculator uses, it’s probably fine.

void cryptx_hmac_pbkdf2(const char *password, size_t passlen, const void *salt, size_t saltlen, uint8_t *key, size_t keylen, size_t rounds, uint8_t hash_alg)

Derives a key from a password, salt, and round count.

Parameters
  • password – Pointer to a string containing the password.

  • passlen – Byte length of the password.

  • salt – A psuedo-random string to use in each round of key derivation.

  • saltlen – Byte length of the salt.

  • rounds – The number of times to iterate the HMAC function per block of keylen.

  • key – Pointer to buffer to write key to.

  • keylen – Length of key to generate.

  • hash_alg – The numeric ID of the hashing algorithm to use. See cryptx_hash_algorithms.

// user inputs a password
char *passwd = io_GetUserInput();

// define salt of length equal to SHA256 digest for max security
uint8_t salt[SHA256_DIGESTLEN];
cryptx_csrand_fill(salt, SHA256_DIGESTLEN);

uint8_t hpasswd[SHA256_DIGESTLEN];

// hash the password using pbkdf2_hmac
cryptx_hmac_pbkdf2(passwd, strlen(passwd),
                  salt, SHA256_DIGESTLEN,
                  hpasswd, SHA256_DIGESTLEN,
                  SHA256);

// the contents of `hpasswd` can be used as an encryption key for AES
// or can be dumped along with `salt` as an encrypted password

Note

For maximum security/entropy your salt should be the same length as the digest of the hash algorithm selected. This isn’t enforced; you can use a smaller salt if you don’t care but be aware that the absolute minimum recommended is 16 bytes/128 bits. This is a NIST 1 recommendation.


Notes

  1. After initialization the hmac context holds the digest length for the selected algorithm. You can read it by accessing context.digest_len. This is the only reason you should be accessing a member of the hmac context.

  2. This API uses 516 bytes of fastMem starting at 0xE30800 for scratch memory. Do not use it for anything else if you are using this module.


1

National Institute of Standards and Technology