666 lines
16 KiB
C
666 lines
16 KiB
C
![]() |
#include <string.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include <avr/io.h>
|
||
|
#include <avr/interrupt.h>
|
||
|
#include <avr/wdt.h>
|
||
|
#include <avr/pgmspace.h>
|
||
|
#include <avr/eeprom.h>
|
||
|
#include <util/delay.h>
|
||
|
|
||
|
#include <usbdrv.h>
|
||
|
|
||
|
#include "hidekey.h"
|
||
|
|
||
|
int descriptorStringSerial[MAX_SERIAL_LEN+1]; /* plus 1 for USB_STRING_DESCRIPTOR_HEADER() byte */
|
||
|
int descriptorStringSerial_e[MAX_SERIAL_LEN+1] EEMEM = {
|
||
|
USB_STRING_DESCRIPTOR_HEADER(1), '0' /* this is the default serial number and should be changed prior shipping */
|
||
|
};
|
||
|
|
||
|
|
||
|
uint16_t counter_e EEMEM = 0; /* how often the stick has been started/enumerated */
|
||
|
struct slot slots_e[MAX_SLOTS] EEMEM; /* is intitialized dynamically during first enumeration */
|
||
|
|
||
|
#ifdef ENCRYPTION
|
||
|
#include "key.h"
|
||
|
#else
|
||
|
#warning "Encryption is DISABLED! This should only be done for debugging purposes."
|
||
|
#endif /* ENCRYPTION */
|
||
|
|
||
|
struct status status; /* status for USBRQ_VENDOR_GET_STATUS */
|
||
|
|
||
|
struct slot currentSlot;
|
||
|
struct slot updateSlot;
|
||
|
|
||
|
uint16_t currentSlotIndex = 0;
|
||
|
uint16_t updateSlotIndex;
|
||
|
|
||
|
/* used by usbFunctionWrite() */
|
||
|
uint8_t bytesRemaining;
|
||
|
uint8_t bytesOffset;
|
||
|
|
||
|
/* USB report descriptor (length is defined in usbconfig.h)
|
||
|
This has been changed to conform to the USB keyboard boot protocol */
|
||
|
char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] PROGMEM = {
|
||
|
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
||
|
0x09, 0x06, // USAGE (Keyboard)
|
||
|
0xa1, 0x01, // COLLECTION (Application)
|
||
|
0x05, 0x07, // USAGE_PAGE (Keyboard)
|
||
|
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
|
||
|
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
|
||
|
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
||
|
0x25, 0x01, // LOGICAL_MAXIMUM (1)
|
||
|
0x75, 0x01, // REPORT_SIZE (1)
|
||
|
0x95, 0x08, // REPORT_COUNT (8)
|
||
|
0x81, 0x02, // INPUT (Data,Var,Abs)
|
||
|
0x95, 0x01, // REPORT_COUNT (1)
|
||
|
0x75, 0x08, // REPORT_SIZE (8)
|
||
|
0x81, 0x03, // INPUT (Cnst,Var,Abs)
|
||
|
0x95, 0x05, // REPORT_COUNT (5)
|
||
|
0x75, 0x01, // REPORT_SIZE (1)
|
||
|
0x05, 0x08, // USAGE_PAGE (LEDs)
|
||
|
0x19, 0x01, // USAGE_MINIMUM (Num Lock)
|
||
|
0x29, 0x05, // USAGE_MAXIMUM (Kana)
|
||
|
0x91, 0x02, // OUTPUT (Data,Var,Abs)
|
||
|
0x95, 0x01, // REPORT_COUNT (1)
|
||
|
0x75, 0x03, // REPORT_SIZE (3)
|
||
|
0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
|
||
|
0x95, 0x06, // REPORT_COUNT (6)
|
||
|
0x75, 0x08, // REPORT_SIZE (8)
|
||
|
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
||
|
0x25, 0x65, // LOGICAL_MAXIMUM (101)
|
||
|
0x05, 0x07, // USAGE_PAGE (Keyboard)
|
||
|
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
|
||
|
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
|
||
|
0x81, 0x00, // INPUT (Data,Ary,Abs)
|
||
|
0xc0 // END_COLLECTION
|
||
|
};
|
||
|
|
||
|
/* ASCII to USB scan/usage codes according to German keyboard layout!
|
||
|
Keep in mind to change these for other keyboard layouts! */
|
||
|
const uint8_t asciiKeyMap[][2] PROGMEM = {
|
||
|
{0x2C, 0}, // SPACE (ASCII: 32)
|
||
|
{0x1E, SHIFT_R}, // !
|
||
|
{0x1F, SHIFT_R}, // "
|
||
|
{0x32, 0}, // #
|
||
|
{0x21, SHIFT_R}, // $
|
||
|
{0x22, SHIFT_R}, // %
|
||
|
{0x23, SHIFT_R}, // &
|
||
|
{0x32, SHIFT_R}, // '
|
||
|
{0x25, SHIFT_R}, // (
|
||
|
{0x26, SHIFT_R}, // )
|
||
|
{0x30, SHIFT_R}, // *
|
||
|
{0x30, 0}, // +
|
||
|
{0x36, 0}, // ,
|
||
|
{0x38, 0}, // -
|
||
|
{0x37, 0}, // .
|
||
|
{0x24, SHIFT_R}, // /
|
||
|
{0x27, 0}, // 0
|
||
|
{0x1E, 0}, // 1
|
||
|
{0x1F, 0}, // 2
|
||
|
{0x20, 0}, // 3
|
||
|
{0x21, 0}, // 4
|
||
|
{0x22, 0}, // 5
|
||
|
{0x23, 0}, // 6
|
||
|
{0x24, 0}, // 7
|
||
|
{0x25, 0}, // 8
|
||
|
{0x26, 0}, // 9
|
||
|
{0x37, SHIFT_R}, // :
|
||
|
{0x36, SHIFT_R}, // ;
|
||
|
{0x64, 0}, // <
|
||
|
{0x27, SHIFT_R}, // =
|
||
|
{0x64, SHIFT_R}, // >
|
||
|
{0x2D, SHIFT_R}, // ?
|
||
|
{0x14, ALT_R}, // @
|
||
|
{0x04, SHIFT_R}, // A
|
||
|
{0x05, SHIFT_R}, // B
|
||
|
{0x06, SHIFT_R}, // C
|
||
|
{0x07, SHIFT_R}, // D
|
||
|
{0x08, SHIFT_R}, // E
|
||
|
{0x09, SHIFT_R}, // F
|
||
|
{0x0A, SHIFT_R}, // G
|
||
|
{0x0B, SHIFT_R}, // H
|
||
|
{0x0C, SHIFT_R}, // I
|
||
|
{0x0D, SHIFT_R}, // J
|
||
|
{0x0E, SHIFT_R}, // K
|
||
|
{0x0F, SHIFT_R}, // L
|
||
|
{0x10, SHIFT_R}, // M
|
||
|
{0x11, SHIFT_R}, // N
|
||
|
{0x12, SHIFT_R}, // O
|
||
|
{0x13, SHIFT_R}, // P
|
||
|
{0x14, SHIFT_R}, // Q
|
||
|
{0x15, SHIFT_R}, // R
|
||
|
{0x16, SHIFT_R}, // S
|
||
|
{0x17, SHIFT_R}, // T
|
||
|
{0x18, SHIFT_R}, // U
|
||
|
{0x19, SHIFT_R}, // V
|
||
|
{0x1A, SHIFT_R}, // W
|
||
|
{0x1B, SHIFT_R}, // X
|
||
|
{0x1D, SHIFT_R}, // Y
|
||
|
{0x1C, SHIFT_R}, // Z
|
||
|
{0x25, ALT_R}, // [
|
||
|
{0x2D, ALT_R}, // \ '\\'
|
||
|
{0x26, ALT_R}, // ]
|
||
|
{0x35, SHIFT_R}, // ^
|
||
|
{0x38, SHIFT_R}, // _
|
||
|
{0x2E, 0}, // `
|
||
|
{0x04, 0}, // a
|
||
|
{0x05, 0}, // b
|
||
|
{0x06, 0}, // c
|
||
|
{0x07, 0}, // d
|
||
|
{0x08, 0}, // e
|
||
|
{0x09, 0}, // f
|
||
|
{0x0A, 0}, // g
|
||
|
{0x0B, 0}, // h
|
||
|
{0x0C, 0}, // i
|
||
|
{0x0D, 0}, // j
|
||
|
{0x0E, 0}, // k
|
||
|
{0x0F, 0}, // l
|
||
|
{0x10, 0}, // m
|
||
|
{0x11, 0}, // n
|
||
|
{0x12, 0}, // o
|
||
|
{0x13, 0}, // p
|
||
|
{0x14, 0}, // q
|
||
|
{0x15, 0}, // r
|
||
|
{0x16, 0}, // s
|
||
|
{0x17, 0}, // t
|
||
|
{0x18, 0}, // u
|
||
|
{0x19, 0}, // v
|
||
|
{0x1A, 0}, // w
|
||
|
{0x1B, 0}, // x
|
||
|
{0x1D, 0}, // y
|
||
|
{0x1C, 0}, // z
|
||
|
{0x24, ALT_R}, // {
|
||
|
{0x64, ALT_R}, // |
|
||
|
{0x27, ALT_R}, // }
|
||
|
{0x30, ALT_R} // ~ (ASCII: 126)
|
||
|
};
|
||
|
|
||
|
static uint8_t reportBuffer[8]; /* contains the USB HID report sent to the PC */
|
||
|
static uint8_t idleRate = 0; /* in 4 ms units */
|
||
|
static uint8_t protocolVer = 1; /* 0 is boot protocol, 1 is report protocol */
|
||
|
|
||
|
void pgm_read_block(uint8_t *pTarget, const uint8_t *pSource, size_t len) {
|
||
|
for(size_t i = 0; i < len; i++) {
|
||
|
*pTarget++ = pgm_read_byte(pSource++);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void getPassword(struct slot *slot, char *str, size_t n) {
|
||
|
switch (slot->type) {
|
||
|
case SLOT_STRING:
|
||
|
case SLOT_GENERATE:
|
||
|
memcpy(str, slot->pass.string, n);
|
||
|
break;
|
||
|
|
||
|
case SLOT_OTP:
|
||
|
snprintf(str, n, "s%u", slot->pass.otp.sequence);
|
||
|
break;
|
||
|
|
||
|
case SLOT_RANDOM:
|
||
|
genPassword(str, MAX_PASS_LEN/2);
|
||
|
break;
|
||
|
|
||
|
default: /* unknown password mode */
|
||
|
str[0] = '\0'; /* empty string */
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
str[n-1] = '\0';
|
||
|
}
|
||
|
|
||
|
void genPassword(char *str, size_t n) {
|
||
|
uint8_t i;
|
||
|
|
||
|
for (i = 0; i < n-1; i++) {
|
||
|
str[i] = '!' + rand() % ('!' - '~'); /* all printable ASCII characters */
|
||
|
}
|
||
|
|
||
|
str[n-1] = '\0';
|
||
|
}
|
||
|
|
||
|
char convToMultiASCII(uint8_t in) {
|
||
|
in -= '!';
|
||
|
in += (in >= 67) ? 94*rand(2) : 94*rand(3);
|
||
|
|
||
|
return in;
|
||
|
}
|
||
|
|
||
|
char convFromMultiASCII(uint8_t in) {
|
||
|
in = in % 94;
|
||
|
in += '!';
|
||
|
return in;
|
||
|
}
|
||
|
|
||
|
void setSlot(struct slot *slot, uint16_t index) {
|
||
|
struct slot tmpSlot = *slot; // TODO workaround?
|
||
|
uint8_t *slotRaw = (uint8_t *) &tmpSlot;
|
||
|
|
||
|
/* prepare slot, on-stick password generation */
|
||
|
if (slot->type == SLOT_GENERATE) {
|
||
|
genPassword(tmpSlot.pass.string, MAX_PASS_LEN/2);
|
||
|
}
|
||
|
|
||
|
#ifdef ENCRYPTION
|
||
|
/* read key */
|
||
|
uint8_t key[sizeof(struct slot)];
|
||
|
pgm_read_block(key, (uint8_t *)(key_p + sizeof(struct slot) * index), sizeof(struct slot));
|
||
|
|
||
|
/* encrypt slot */
|
||
|
for (uint16_t i = 0; i < sizeof(struct slot); i++) {
|
||
|
slotRaw[i] ^= key[i];
|
||
|
}
|
||
|
#endif /* ENCRYPTION */
|
||
|
|
||
|
/* store slot */
|
||
|
eeprom_write_block(slotRaw, &slots_e[index], sizeof(struct slot));
|
||
|
}
|
||
|
|
||
|
void getSlot(struct slot *slot, uint16_t index) {
|
||
|
/* read slot */
|
||
|
uint8_t *slotRaw = (uint8_t *) slot;
|
||
|
eeprom_read_block(slotRaw, &slots_e[index], sizeof(struct slot));
|
||
|
|
||
|
#ifdef ENCRYPTION
|
||
|
/* read key */
|
||
|
uint8_t key[sizeof(struct slot)];
|
||
|
pgm_read_block(key, (uint8_t *)(key_p + sizeof(struct slot) * index), sizeof(struct slot));
|
||
|
|
||
|
/* decrypt key */
|
||
|
for (uint16_t i = 0; i < sizeof(struct slot); i++) {
|
||
|
slotRaw[i] ^= key[i];
|
||
|
}
|
||
|
#endif /* ENCRYPTION */
|
||
|
}
|
||
|
|
||
|
void usbReset() {
|
||
|
DDRB |= (1 << PB0) | (1 << PB1); /* enable USB pins as output */
|
||
|
_delay_ms(15); /* sleeping for 15ms */
|
||
|
DDRB &= ~(1 << PB0) & ~(1 << PB1); /* disbale USB pins as output */
|
||
|
}
|
||
|
|
||
|
void hardwareInit() {
|
||
|
usbReset();
|
||
|
|
||
|
/* LEDs */
|
||
|
DDRC |= (1 << PC0) | (1 << PC1); /* set LED pins as output */
|
||
|
PORTC &= ~(1 << PC0) & ~(1 << PC1); /* set LEDs (active low) */
|
||
|
|
||
|
/* push button */
|
||
|
BTN_DDR &= ~(1 << BTN_BIT1); /* set button pin as input */
|
||
|
BTN_DDR |= (1 << BTN_BIT2); /* set button pin as output */
|
||
|
BTN_PORT |= (1 << BTN_BIT1); /* enable pullup for button */
|
||
|
BTN_PORT &= ~(1 << BTN_BIT2);
|
||
|
|
||
|
#ifdef WRITE_PROTECTION
|
||
|
/* write protect jumper */
|
||
|
WRLOCK_DDR &= ~(1 << WRLOCK_BIT);
|
||
|
WRLOCK_PORT |= (1 << WRLOCK_BIT); /* enable pullup for button */
|
||
|
#endif /* WRITE_PROTECTION */
|
||
|
|
||
|
TCCR0 = (1 << CS02); /* CPU prescaler = 512 */
|
||
|
}
|
||
|
|
||
|
void hidBuildReport(char chr) {
|
||
|
for (int i = 0; i < 8; i++) {
|
||
|
reportBuffer[i] = 0x0; /* clear report */
|
||
|
}
|
||
|
|
||
|
if (chr >= ' ' && chr <= '~') {
|
||
|
uint16_t map = pgm_read_word(asciiKeyMap[chr - ' ']);
|
||
|
|
||
|
reportBuffer[0] = map >> 8; /* modifier */
|
||
|
reportBuffer[2] = map & 0xff; /* key */
|
||
|
}
|
||
|
else switch (chr) {
|
||
|
case 0x8E: // Ä
|
||
|
reportBuffer[0] = SHIFT_R;
|
||
|
case 0x84: // ä
|
||
|
reportBuffer[2] = 0x34;
|
||
|
break;
|
||
|
|
||
|
case 0x99: // Ö
|
||
|
reportBuffer[0] = SHIFT_R;
|
||
|
case 0x94: // ö
|
||
|
reportBuffer[2] = 0x33;
|
||
|
break;
|
||
|
|
||
|
case 0x9A: // Ü
|
||
|
reportBuffer[0] = SHIFT_R;
|
||
|
case 0x81: // ü
|
||
|
reportBuffer[2] = 0x2F;
|
||
|
break;
|
||
|
|
||
|
case '\b':
|
||
|
reportBuffer[2] = 0x2A;
|
||
|
break;
|
||
|
|
||
|
case '\t':
|
||
|
reportBuffer[2] = 0x2B;
|
||
|
break;
|
||
|
|
||
|
case '\n':
|
||
|
reportBuffer[2] = 0x28;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void hidSendChar(char chr) {
|
||
|
while (!usbInterruptIsReady()); /* wait until previous transmission is finished */
|
||
|
|
||
|
hidBuildReport(chr); /* build HID report buffer for one character */
|
||
|
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
|
||
|
}
|
||
|
|
||
|
void hidSendString(char *str) {
|
||
|
while (*str) {
|
||
|
hidSendChar(*str); /* send character string one by one */
|
||
|
hidSendChar(0); /* release any keys */
|
||
|
str++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) {
|
||
|
usbMsgLen_t len = 0;
|
||
|
usbMsgPtr = NULL;
|
||
|
|
||
|
/* 3 is the type of string descriptor, in this case the device serial number */
|
||
|
if (rq->wValue.bytes[1] == USBDESCR_STRING && rq->wValue.bytes[0] == 3) {
|
||
|
/* read serial number from eeprom */
|
||
|
eeprom_read_block(descriptorStringSerial, descriptorStringSerial_e, sizeof(descriptorStringSerial));
|
||
|
|
||
|
usbMsgPtr = (uint8_t *) descriptorStringSerial;
|
||
|
len = *((uint8_t *) descriptorStringSerial);
|
||
|
}
|
||
|
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
uint8_t usbFunctionSetup(uint8_t data[8]) {
|
||
|
usbRequest_t *rq = (void *)data;
|
||
|
usbMsgPtr = reportBuffer;
|
||
|
|
||
|
if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) {
|
||
|
switch (rq->bRequest) {
|
||
|
case USBRQ_HID_GET_IDLE:
|
||
|
usbMsgPtr = &idleRate;
|
||
|
return 1;
|
||
|
|
||
|
case USBRQ_HID_SET_IDLE:
|
||
|
idleRate = rq->wValue.bytes[1];
|
||
|
return 0;
|
||
|
|
||
|
case USBRQ_HID_GET_REPORT:
|
||
|
hidBuildReport(0);
|
||
|
return sizeof(reportBuffer);
|
||
|
|
||
|
case USBRQ_HID_SET_REPORT:
|
||
|
if (rq->wLength.word == 1) {
|
||
|
status.mode = EXPECT_REPORT;
|
||
|
return USB_NO_MSG;
|
||
|
}
|
||
|
return 0;
|
||
|
|
||
|
case USBRQ_HID_SET_PROTOCOL:
|
||
|
if (rq->wValue.bytes[1] < 1) {
|
||
|
protocolVer = rq->wValue.bytes[1];
|
||
|
}
|
||
|
return 0;
|
||
|
|
||
|
case USBRQ_HID_GET_PROTOCOL:
|
||
|
usbMsgPtr = &protocolVer;
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
else if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_VENDOR) {
|
||
|
switch (rq->bRequest) {
|
||
|
case USBRQ_VENDOR_SET_SERIAL:
|
||
|
if (writable()) {
|
||
|
status.mode = EXPECT_SERIAL;
|
||
|
bytesRemaining = rq->wLength.word & 0xff; /* string length */
|
||
|
bytesOffset = 1; /* first index is reserved for USB_STRING_DESCRIPTOR_HEADER() */
|
||
|
|
||
|
if (bytesRemaining > MAX_SERIAL_LEN) {
|
||
|
status.error = ERROR_OVERFLOW;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PORTC &= ~(1 << PC1); /* set LED */
|
||
|
return USB_NO_MSG; /* use usbFunctionWrite() */
|
||
|
}
|
||
|
else {
|
||
|
status.error = ERROR_LOCKED;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
case USBRQ_VENDOR_SET_SLOT:
|
||
|
if (writable() || !WRITE_PROTECTION) {
|
||
|
status.mode = EXPECT_SLOT;
|
||
|
updateSlotIndex = rq->wIndex.word;
|
||
|
bytesRemaining = sizeof(struct slot);
|
||
|
bytesOffset = 0;
|
||
|
|
||
|
if (updateSlotIndex >= MAX_SLOTS) {
|
||
|
status.error = ERROR_INVALID_SLOT;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PORTC &= ~(1 << PC1); /* set LED */
|
||
|
return USB_NO_MSG; /* use usbFunctionWrite() */
|
||
|
}
|
||
|
else {
|
||
|
status.error = ERROR_LOCKED;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
case USBRQ_VENDOR_GET_STATUS: {
|
||
|
status.writable = 0;
|
||
|
if (WRITE_PROTECTION) {
|
||
|
status.writable = (writable()) ? 1 : 2;
|
||
|
}
|
||
|
|
||
|
usbMsgPtr = (uint8_t *) &status;
|
||
|
return sizeof(status);
|
||
|
}
|
||
|
|
||
|
case USBRQ_VENDOR_RESET:
|
||
|
if (!writable() && WRITE_PROTECTION) {
|
||
|
status.error = ERROR_LOCKED;
|
||
|
}
|
||
|
|
||
|
eeprom_write_word(&counter_e, 0);
|
||
|
usbReset(); // TODO check
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
uint8_t usbFunctionWrite(uint8_t *data, uint8_t len) {
|
||
|
if(len > bytesRemaining) { /* if this is the last incomplete chunk */
|
||
|
len = bytesRemaining; /* limit to the amount we can store */
|
||
|
}
|
||
|
bytesRemaining -= len;
|
||
|
|
||
|
for(uint8_t i = 0; i < len; i++) {
|
||
|
switch (status.mode) {
|
||
|
case EXPECT_SLOT:
|
||
|
((uint8_t *) &updateSlot)[bytesOffset++] = data[i];
|
||
|
break;
|
||
|
|
||
|
case EXPECT_SERIAL:
|
||
|
descriptorStringSerial[bytesOffset++] = data[i];
|
||
|
break;
|
||
|
|
||
|
case EXPECT_REPORT: // TODO
|
||
|
default: break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (bytesRemaining == 0) { /* store slot into eeprom when completed */
|
||
|
switch (status.mode) {
|
||
|
case EXPECT_SLOT:
|
||
|
setSlot(&updateSlot, updateSlotIndex);
|
||
|
break;
|
||
|
|
||
|
case EXPECT_SERIAL:
|
||
|
descriptorStringSerial[0] = USB_STRING_DESCRIPTOR_HEADER(bytesOffset-1);
|
||
|
eeprom_write_block(descriptorStringSerial, descriptorStringSerial_e, sizeof(descriptorStringSerial));
|
||
|
break;
|
||
|
|
||
|
case EXPECT_REPORT: // TODO
|
||
|
default: break;
|
||
|
}
|
||
|
|
||
|
currentSlotIndex = 0; /* reset slot */
|
||
|
status.mode = IDLE;
|
||
|
status.error = ERROR_SUCCESS;
|
||
|
PORTC |= (1 << PC1); /* clear LED */
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int main(void) {
|
||
|
uint8_t updateNeeded = 0;
|
||
|
uint8_t idleCounter = 0;
|
||
|
|
||
|
uint8_t len = 0;
|
||
|
uint8_t debounce = 0;
|
||
|
uint16_t pressed = 0;
|
||
|
|
||
|
status.counter = eeprom_read_word(&counter_e);
|
||
|
|
||
|
status.maxSlots = MAX_SLOTS;
|
||
|
status.maxUserLen = MAX_USER_LEN;
|
||
|
status.maxPassLen = MAX_PASS_LEN;
|
||
|
status.maxSerialLen = MAX_SERIAL_LEN;
|
||
|
|
||
|
status.mode = IDLE;
|
||
|
status.error = ERROR_SUCCESS;
|
||
|
|
||
|
/* Initialize EEPROM */
|
||
|
if (status.counter == 0) {
|
||
|
struct slot empty = { SLOT_EMPTY };
|
||
|
struct slot slots[] = {
|
||
|
{ SLOT_STRING, 0, '\t', "HIDeKey v1.0", { .string = "" } },
|
||
|
{ SLOT_RANDOM, 0, '\t', "demo1_random" },
|
||
|
{ SLOT_GENERATE,0, '\t', "demo2_random_gen" },
|
||
|
{ SLOT_STRING, 0, '\t', "demo3_string", { .string = "constant" } },
|
||
|
{ SLOT_OTP, 0, '\t', "demo4_otp", { .otp = { .seed = {1, 2, 3, 4, 5, 6, 7, 8}, .sequence = 0 } } }
|
||
|
};
|
||
|
|
||
|
uint16_t i;
|
||
|
for (i = 0; i < (sizeof(slots) / sizeof(struct slot)); i++) {
|
||
|
setSlot(&slots[i], i);
|
||
|
}
|
||
|
|
||
|
for (; i < MAX_SLOTS; i++) {
|
||
|
setSlot(&empty, i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
wdt_enable(WDTO_2S); /* enable watchdog timer 2s */
|
||
|
srand((status.counter * 256) % RAND_MAX); /* crypto initialization */
|
||
|
|
||
|
/* increment and store startup counter */
|
||
|
status.counter++;
|
||
|
eeprom_write_word(&counter_e, status.counter);
|
||
|
|
||
|
usbInit(); /* initialize USB stack processing */
|
||
|
hardwareInit(); /* setup io & starts timer */
|
||
|
sei(); /* enable global interrupts */
|
||
|
|
||
|
PORTC |= (1 << PC1); /* disable startup LED */
|
||
|
|
||
|
/* main loop */
|
||
|
for (;;) {
|
||
|
wdt_reset(); /* reset the watchdog */
|
||
|
usbPoll(); /* poll the USB stack */
|
||
|
|
||
|
if (TIFR & (1 << TOV0)) { /* timer0 overflow? */
|
||
|
TIFR = 1 << TOV0; /* reset timer overflow flag */
|
||
|
|
||
|
if (buttonPressed()) pressed++;
|
||
|
else if (debounce > 0) debounce--;
|
||
|
else if (pressed > 0) {
|
||
|
if (pressed < BTN_LONG_PRESS) {
|
||
|
do { /* find next non-empty slot */
|
||
|
currentSlotIndex %= MAX_SLOTS; /* avoid overflow */
|
||
|
getSlot(¤tSlot, currentSlotIndex);
|
||
|
currentSlotIndex++; /* increment slot */
|
||
|
} while (currentSlot.type == SLOT_EMPTY); /* skip empty slots */
|
||
|
}
|
||
|
|
||
|
if (currentSlot.options & SKIP_USER || pressed > BTN_LONG_PRESS) {
|
||
|
char pass[MAX_PASS_LEN];
|
||
|
getPassword(¤tSlot, pass, MAX_PASS_LEN);
|
||
|
|
||
|
if (~currentSlot.options & SKIP_DELIMITER) {
|
||
|
if (currentSlot.delimiter) {
|
||
|
hidSendChar(currentSlot.delimiter);
|
||
|
hidSendChar(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hidSendString(pass);
|
||
|
|
||
|
if (~currentSlot.options & SKIP_RETURN) {
|
||
|
hidSendChar('\n');
|
||
|
hidSendChar(0);
|
||
|
}
|
||
|
|
||
|
if (currentSlot.type == SLOT_OTP) {
|
||
|
currentSlot.pass.otp.sequence++;
|
||
|
setSlot(¤tSlot, currentSlotIndex - 1);
|
||
|
}
|
||
|
|
||
|
if (currentSlot.options & SKIP_RESET) {
|
||
|
currentSlotIndex = 0;
|
||
|
}
|
||
|
|
||
|
len = 0;
|
||
|
}
|
||
|
else {
|
||
|
/* delete old username */
|
||
|
for (uint8_t i = 0; i < len; i++) {
|
||
|
hidSendChar('\b');
|
||
|
hidSendChar(0);
|
||
|
}
|
||
|
|
||
|
/* write new username */
|
||
|
hidSendString(currentSlot.user);
|
||
|
len = strlen(currentSlot.user);
|
||
|
}
|
||
|
|
||
|
pressed = 0;
|
||
|
debounce = 10;
|
||
|
}
|
||
|
|
||
|
if (idleRate != 0) { /* do we need periodic reports? */
|
||
|
if (idleCounter > 3) { /* yes, but not yet */
|
||
|
idleCounter -= 3;
|
||
|
} else { /* yes, it is time now */
|
||
|
updateNeeded = 1;
|
||
|
idleCounter = idleRate;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* if an update is needed, send the report */
|
||
|
if(updateNeeded && usbInterruptIsReady()) {
|
||
|
updateNeeded = 0;
|
||
|
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|