Skip to content
Snippets Groups Projects
keystore.h 3.75 KiB
#pragma once

#include <string.h>
#include <avr/io.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <../common/i2c_master.h>
#include <../common/sha1/sha1.h>
#include "../common/cardreader_interface-common.h"
#include "random.h"

#define KEY_COUNT 32 //eeprom has space for 1008 keys, but RAM for hash precalc is limited.

// #define KEYSTORE_DEBUG

#define EEPROM_TABLE_OFFSET 0  //table listing used and unused keyslots
#define EEPROM_KEY_OFFSET 1024 //keys start here

#define KEYSLOT_USED     0xBB
#define KEYSLOT_EMPTY    0xFF
#define KEYSLOT_DISABLED 0xDD
#define KEYSLOT_ERROR    0x00

#define KEY_MAIN_EEPROM 0xa0
#define KEY_BACKUP_EEPROM 0xa2

#define EEPROM_WRITE_PROTECT_PORT   PORTD
#define EEPROM_WRITE_PROTECT_DDR    DDRD
#define EEPROM_WRITE_PROTECT_MAIN   (1 << 6)
#define EEPROM_WRITE_PROTECT_BACKUP (1 << 7)

typedef uint8_t HASH_HEAD[4];

/**
 * Initializes the Keystore (including I²C, RNG)
 */
void keystore_init(void);

/**
 * Returns the current salt of the keystore
 * After 3 queries a new salt will be generated
 */
uint8_t* keystore_get_salt(void);

/**
 * Looks for key matching to the given key hash
 * The keyhash is SHA1(key + salt)
 */
int16_t keystore_find_key(HASH keyhash);

/**
 * Generates a new salt
 */
void keystore_update_salt(void);

/**
 * List keystore content (stubs)
 */
void keystore_list(void);

/**
 * Generates a byte string of sizeof(KEY) length which is used to update
 * the card key. new_key = current_key XOR keydelta
 * 
 * @param keydelta: will be filled with sizeof(KEY) random bytes.
 */
void keystore_gen_keydelta(KEY keydelta);

/**
 * Updates the given keyslot with new_key = current_key XOR keydelta
 * @param index number of the keyslot to update
 * @param keydelta xor of old and new key. Must be sizeof(KEY) bytes long
 */
uint8_t keystore_update_slot(uint16_t index, KEY keydelta);

/**
 * Calculates sha1(key + salt) for the key in the given keyslot
 * @param index number of the keyslot to calculate the hash for
 * @param salt salt used for hash calc
 * @param keyhash result will be written here (must be sizeof(HASH) in length)
 */
uint8_t keystore_calc_keyhash(uint16_t index, SALT salt, HASH keyhash);


/**
 * Returns the number of the first empty slot in the keystore
 * or 0xFFFF if the keystore if full
 */
uint16_t keystore_find_empty_slot(void);

/**
 * Initializes a slot with a new, random key.
 * @param index number of the keyslot to initialize
 * @param keyout the generated key will be written here (must be sizeof(KEY) in length)
 */
uint8_t keystore_init_slot(uint16_t index, KEY keyout);

/**
 * Clears the given keyslot (sets it to unused state)
 */
uint8_t keystore_clear_slot(uint16_t index);

/**
 * Disables the given keyslot (sets it from USED to DISABLED state)
 */
uint8_t keystore_disable_slot(uint16_t index);

/**
 * Disables the given keyslot (sets it from DISABLED to USED state)
 */
uint8_t keystore_enable_slot(uint16_t index);

/**
 * Updates the status of a keyslot.
 * @param index number of the keyslot to update
 * @param key_status new status of the slot: KEYSLOT_USED or KEYSLOT_EMPTY
 */
uint8_t keystore_write_slot_status(uint16_t index, uint8_t key_status);

/**
 * Returns the status of a keyslot.
 * @param index number of the keyslot to read
 * @return KEYSLOT_USED, KEYSLOT_EMPTY or KEYSLOT_ERROR
 */
uint8_t keystore_read_slot_status(uint16_t index);

/**
 * Reads the key of a keyslot
 * @param index number of the keyslot to read
 * @param key   buffer for the key
 * @return 1 if read successful, 0 otherwise.
 */
uint8_t keystore_read_key(uint16_t index, KEY key);

/**
 * Restores the key slot content to the last successful auth key
 * @param index number of the keyslot to restore
 */
uint8_t keystore_restore_slot(uint16_t index);