VUSB-Firmware for Attiny85 implementing HMAC one time password authentication
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
hmac-otp/libcrypt/main.c

171 lines
4.7 KiB

/*
* This code is based on seveal VUSB-Examples the
* HID was taken from the CapsLocker code from macetech
* http://macetech.com/blog/?q=node/46
*
*/
#include "main.h"
#define MSG "what do ya want for nothing?"
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <stdlib.h>
uint8_t reportBuffer[2]; /* buffer for HID reports */
static uint8_t next_key=0, prev_key=0xFF;
static uint8_t sec[SECLEN]=SECRET;
uint32_t get_cnt(){
void* p=(void*)eeprom_read_word(CNTPOS_PTR);
return eeprom_read_dword(p);
}
uint8_t inc_cnt(){
uint32_t cnt;
void* p=(void*)eeprom_read_word(CNTPOS_PTR);
cnt=eeprom_read_dword(p);
if(cnt==UINT32_MAX){
eeprom_write_word(CNTPOS_PTR,ERROR);
return 0;
}
eeprom_write_dword(p,cnt+1);
retry:
if(eeprom_read_dword(p)!=cnt+1){
eeprom_write_dword(p,cnt+1);
if(eeprom_read_dword(p)!=cnt+1){
/*Probabbly the EEPROM position is bad, try an other*/
p+=4;
if(p+4>(void*)EEPROM_SIZE){
eeprom_write_word(CNTPOS_PTR,ERROR);
return 0;
}
eeprom_write_word(CNTPOS_PTR,(uint16_t)p);
/* I know some people don't like goto because of dijkstra's
legendary article "goto considered harmfull". The truth is he
didn't want us to stop using goto at all, but to think if it
is appropriate. The alternative here would be a loop around
this whole block and some well-placed "break" and "continue"
kbd_event_statements - I think that would be even worse than the goto*/
goto retry;
}
}
return 1;
}
void buildReport(uint8_t mod, uint8_t key){
reportBuffer[0] = mod;
reportBuffer[1] = key;
}
void main_fsm(){
static uint8_t device_state=0;
static uint8_t prev_btn=0;
switch(device_state){
case DEV_STATE_RESET:
{
uint32_t cnt;
if( eeprom_read_word(CNTPOS_PTR)==ERROR ){
writeToBuffer(USB_KEY_E);
writeToBuffer(USB_KEY_R);
writeToBuffer(USB_KEY_R);
writeToBuffer(USB_KEY_O);
writeToBuffer(USB_KEY_R);
}else{
cnt = get_cnt();
buffer_unum(get_otp_from_cnt(cnt,8,sec,SECLEN));
}
device_state=DEV_STATE_SENT;
break;
}
case DEV_STATE_SENT:
if( prev_btn!=0 && ((PIN_BTN)&(1<<PBTN))==0 ){
writeToBuffer(USB_KEY_ENTER);
inc_cnt();
device_state=DEV_STATE_CONFIRMED;
_delay_ms(100);
}
break;
case DEV_STATE_CONFIRMED:
default:
if( prev_btn!=0 && ((PIN_BTN)&(1<<PBTN))==0 ){
device_state=DEV_STATE_RESET;
_delay_ms(100);
}
break;
}
prev_btn=(PIN_BTN)&(1<<PBTN);
}
int main(void){
#ifdef CALIB
uint8_t calibrationValue;
#endif
#ifdef CALIB
/* oszillator calibration */
calibrationValue = eeprom_read_byte(0); /* calibration value from last time */
if(calibrationValue != 0xff){
OSCCAL = calibrationValue;
}
#endif //CALLIB
usbDeviceDisconnect();
/* just leave some time for a disconnect/connect sequence mustn't be that exact */
/* TODO only do this if watchdog was activated*/
_delay_ms(200);
usbDeviceConnect();
wdt_enable(WDTO_500MS);
writeToBuffer(USB_KEY_NOP);
/*Set button to input*/
DDR_BTN &= ~(1<<PBTN);
/*internal pull-up on*/
PORT_BTN |= 1<<PBTN;
usbInit();
sei();
for(;;){
wdt_reset();
usbPoll();
/* Main FSM*/
main_fsm();
/* Send Keystrokes, if asked to */
if(usbInterruptIsReady()){
if(!buff_empty || next_key!=0){
if(next_key==0){
next_key=readBuffer();
}
if(next_key==prev_key){
/*we must send a NOP in between otherwise it will be
interpreted as only one keystroke*/
buildReport(0x00, USB_KEY_NOP);
/*set the prev key to something different*/
prev_key=!next_key;
}else{
buildReport(0x00, next_key);
prev_key=next_key;
next_key=0;
}
}else{
buildReport(0x00, USB_KEY_NOP);
}
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
}
}
return 0;
}