From f1c12c8fb936740eef33837c5ad51bad0ca34a65 Mon Sep 17 00:00:00 2001 From: Yohanes Nugroho Date: Wed, 2 Mar 2011 11:26:28 +0700 Subject: [PATCH 01/14] TOTP implementation --- logic/menu.c | 22 +++ logic/menu.h | 5 + logic/otp.c | 422 ++++++++++++++++++++++++++++++++++++++++++++++++ logic/otp.h | 11 ++ makefile | 2 +- tools/config.py | 63 +++++++- 6 files changed, 520 insertions(+), 5 deletions(-) create mode 100644 logic/otp.c create mode 100644 logic/otp.h diff --git a/logic/menu.c b/logic/menu.c index 0dcf5c0..96774d6 100644 --- a/logic/menu.c +++ b/logic/menu.c @@ -96,6 +96,11 @@ #include "gps.h" #endif +#ifdef CONFIG_OTP +#include "otp.h" +#endif + + // ************************************************************************************************* // Defines section @@ -424,6 +429,19 @@ const struct menu menu_L2_Gps = }; #endif +#ifdef CONFIG_OTP +// OTP +const struct menu menu_L2_Otp = +{ + FUNCTION(otp_sx), // direct function + FUNCTION(otp_switch), // sub menu function + FUNCTION(menu_skip_next), // next item function + FUNCTION(display_otp), // display function + FUNCTION(update_otp), // new display data +}; +#endif + + // ************************************************************************************************* // menu array @@ -491,6 +509,10 @@ const struct menu *menu_L2[]={ #ifdef CONFIG_USE_GPS &menu_L2_Gps, #endif + #ifdef CONFIG_OTP + &menu_L2_Otp, + #endif + }; const int menu_L2_size=sizeof(menu_L2)/sizeof(struct menu*); diff --git a/logic/menu.h b/logic/menu.h index d507ac0..ebbc246 100644 --- a/logic/menu.h +++ b/logic/menu.h @@ -131,6 +131,11 @@ extern const struct menu menu_L2_Vario; extern const struct menu menu_L2_Gps; #endif +#ifdef CONFIG_USE_OTP +extern const struct menu menu_L2_Otp; +#endif + + // Pointers to current menu item extern const struct menu * ptrMenu_L1; extern const struct menu * ptrMenu_L2; diff --git a/logic/otp.c b/logic/otp.c new file mode 100644 index 0000000..adf2783 --- /dev/null +++ b/logic/otp.c @@ -0,0 +1,422 @@ +/** + Copyright (c) 2011 Yohanes Nugroho (yohanes@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + The SHA1 code is based on public domain code by + Uwe Hollerbach + from Peter C. Gutmann's implementation as found in + Applied Cryptography by Bruce Schneier +*/ +#include "project.h" + +#ifdef CONFIG_OTP + +#include + +#include "ports.h" +#include "display.h" +#include "timer.h" +#include "buzzer.h" +#include "user.h" +#include "clock.h" +#include "date.h" + +// logic +#include "menu.h" + +#include "otp.h" + +#undef C + +extern struct date sDate; + +#define SHA1_BLOCKSIZE 64 +#define SHA1_DIGEST_LENGTH 20 + +/*in this implementation: MAX = 63*/ +#define HMAC_KEY_LENGTH 10 +#define HMAC_DATA_LENGTH 8 + +static uint8_t hmac_key[HMAC_KEY_LENGTH]; +static uint32_t sha1_digest[8]; +static uint32_t sha1_count, sha1_count_hi; +static uint8_t sha1_data[SHA1_BLOCKSIZE]; +static uint32_t sha1_W[80]; +static uint8_t hmac_tmp_key[64 + HMAC_DATA_LENGTH]; +static uint8_t hmac_sha[SHA1_DIGEST_LENGTH]; + +// The key for the inner digest is derived from our key, by padding the key +// the full length of 64 bytes, and then XOR'ing each byte with 0x36. +static uint8_t tmp_key[64]; + + +/* SHA f()-functions */ +#define f1(x,y,z) ((x & y) | (~x & z)) +#define f2(x,y,z) (x ^ y ^ z) +#define f3(x,y,z) ((x & y) | (x & z) | (y & z)) +#define f4(x,y,z) (x ^ y ^ z) + +/* SHA constants */ +#define CONST1 0x5a827999L +#define CONST2 0x6ed9eba1L +#define CONST3 0x8f1bbcdcL +#define CONST4 0xca62c1d6L + +/* truncate to 32 bits -- should be a null op on 32-bit machines */ +#define T32(x) ((x) & 0xffffffffL) + +#define R32(x,n) T32(((x << n) | (x >> (32 - n)))) + +/* the generic case, for when the overall rotation is not unraveled */ +#define FG(n) \ + T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); \ + E = D; D = C; C = R32(B,30); B = A; A = T + + +void sha1_transform() +{ + int i; + uint8_t *dp; + uint32_t T, A, B, C, D, E, *WP; + + dp = sha1_data; + +#define SWAP_DONE + for (i = 0; i < 16; ++i) { + T = *((uint32_t *) dp); + dp += 4; + sha1_W[i] = + ((T << 24) & 0xff000000) | + ((T << 8) & 0x00ff0000) | + ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); + } + + for (i = 16; i < 80; ++i) { + sha1_W[i] = sha1_W[i-3] ^ sha1_W[i-8] ^ sha1_W[i-14] ^ sha1_W[i-16]; + sha1_W[i] = R32(sha1_W[i], 1); + } + + + A = sha1_digest[0]; + B = sha1_digest[1]; + C = sha1_digest[2]; + D = sha1_digest[3]; + E = sha1_digest[4]; + WP = sha1_W; + for (i = 0; i < 20; ++i) { FG(1); } + for (i = 20; i < 40; ++i) { FG(2); } + for (i = 40; i < 60; ++i) { FG(3); } + for (i = 60; i < 80; ++i) { FG(4); } + + sha1_digest[0] = T32(sha1_digest[0] + A); + sha1_digest[1] = T32(sha1_digest[1] + B); + sha1_digest[2] = T32(sha1_digest[2] + C); + sha1_digest[3] = T32(sha1_digest[3] + D); + sha1_digest[4] = T32(sha1_digest[4] + E); + +} + +void sha1(const uint8_t* data, uint32_t len, uint8_t digest[20]) +{ + + int i; + + int count; + uint32_t lo_bit_count; + + + sha1_digest[0] = 0x67452301L; + sha1_digest[1] = 0xefcdab89L; + sha1_digest[2] = 0x98badcfeL; + sha1_digest[3] = 0x10325476L; + sha1_digest[4] = 0xc3d2e1f0L; + sha1_count = 0L; + + sha1_count = T32(((uint32_t) len << 3)); + + while (len >= SHA1_BLOCKSIZE) { + memcpy(sha1_data, data, SHA1_BLOCKSIZE); + data += SHA1_BLOCKSIZE; + len -= SHA1_BLOCKSIZE; + sha1_transform(); + } + memcpy(sha1_data, data, len); + + lo_bit_count = sha1_count; + + count = (int) ((lo_bit_count >> 3) & 0x3f); + ((uint8_t *) sha1_data)[count++] = 0x80; + if (count > SHA1_BLOCKSIZE - 8) { + memset(((uint8_t *) sha1_data) + count, 0, SHA1_BLOCKSIZE - count); + sha1_transform(); + memset((uint8_t *) sha1_data, 0, SHA1_BLOCKSIZE - 8); + } else { + memset(((uint8_t *) sha1_data) + count, 0, + SHA1_BLOCKSIZE - 8 - count); + } + + sha1_data[56] = 0; + sha1_data[57] = 0; + sha1_data[58] = 0; + sha1_data[59] = 0; + sha1_data[60] = (uint8_t)((lo_bit_count >> 24) & 0xff); + sha1_data[61] = (uint8_t)((lo_bit_count >> 16) & 0xff); + sha1_data[62] = (uint8_t)((lo_bit_count >> 8) & 0xff); + sha1_data[63] = (uint8_t)((lo_bit_count >> 0) & 0xff); + + sha1_transform(); + + //memcpy(digest, sha1_digest, 20); + + count = 0; + for(i = 0; i<5; i++) { + digest[count++] = (unsigned char) ((sha1_digest[i] >> 24) & 0xff); + digest[count++] = (unsigned char) ((sha1_digest[i] >> 16) & 0xff); + digest[count++] = (unsigned char) ((sha1_digest[i] >> 8) & 0xff); + digest[count++] = (unsigned char) ((sha1_digest[i]) & 0xff); + } + +} + + +//data is in tmp_key + 64 +//result is in hmac_sha +uint8_t* hmac_sha1(uint8_t *data) { + + int i; + + + // The key for the inner digest is derived from our key, by padding the key + // the full length of 64 bytes, and then XOR'ing each byte with 0x36. + + for (i = 0; i < HMAC_KEY_LENGTH; ++i) { + hmac_tmp_key[i] = hmac_key[i] ^ 0x36; + } + memset(hmac_tmp_key + HMAC_KEY_LENGTH, 0x36, 64 - HMAC_KEY_LENGTH); + + memcpy(hmac_tmp_key + 64, data, HMAC_DATA_LENGTH); + + sha1(hmac_tmp_key, 64 + HMAC_DATA_LENGTH, hmac_sha); + + + // The key for the outer digest is derived from our key, by padding the key + // the full length of 64 bytes, and then XOR'ing each byte with 0x5C. + for (i = 0; i < HMAC_KEY_LENGTH; ++i) { + hmac_tmp_key[i] = hmac_key[i] ^ 0x5C; + } + memset(hmac_tmp_key + HMAC_KEY_LENGTH, 0x5C, 64 - HMAC_KEY_LENGTH); + + memcpy(hmac_tmp_key + 64, hmac_sha, SHA1_DIGEST_LENGTH); + + sha1(hmac_tmp_key, 64 + SHA1_DIGEST_LENGTH, hmac_sha); + + + return hmac_sha; +} + +static int days[12] ={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + +uint32_t simple_mktime(int year, int month, int day, int hour, int minute, int second) +{ + uint32_t result; + + year += month / 12; + month %= 12; + result = (year - 1970) * 365 + days[month]; + if (month <= 1) + year -= 1; + + //only works for year 2000 - 2032 + + result += (year - 1968) / 4; + + result += day -1; + + result = ((result*24+hour)*60+minute)*60 + second; + + return (result); +} + +static char otp_result[5]; +static uint8_t data[] = {0,0,0,0,0,0,0,0}; + +const char *key = CONFIG_OTP_KEY; + +extern struct date sDate; +extern struct time sTime; + +static uint32_t last_time = 0; +static uint32_t last_val = 0; + +uint32_t otp() +{ + uint32_t val =0; + int i; + + uint32_t time = simple_mktime(sDate.year, sDate.month - 1, sDate.day, + sTime.hour, sTime.minute, sTime.second); + + time -= CONFIG_OTP_UTC_OFFSET*3600; + + time /= 30; + + if (time==last_time) { + return last_val; + } + + memcpy(hmac_key, key, HMAC_KEY_LENGTH); + + last_time = time; + + data[4] = (time >> 24) & 0xff; + data[5] = (time >> 16) & 0xff; + data[6] = (time >> 8) & 0xff; + data[7] = (time) & 0xff; + + hmac_sha1(data); + + int off = hmac_sha[SHA1_DIGEST_LENGTH-1] & 0x0f; + + char *cc = (char *)&val; + for (i =0; i < 4; i++) { + cc[3-i] = hmac_sha[off+i]; + } + val &= 0x7fffffff; + val %= 1000000; + + last_val = val; + + return val; +} + +static int display_mode = 0; //show first 2 digits + +void otp_sx(u8 line) +{ + otp(); + display_otp(line, DISPLAY_LINE_UPDATE_PARTIAL); +} + +void otp_switch(u8 line) +{ + display_mode = !display_mode; + display_otp(line, DISPLAY_LINE_UPDATE_PARTIAL); +} + +void update_otp(u8 line, u8 update) +{ + otp(); +} + +#ifdef TEST_SHA1 + +static char *test_data[] = { + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "A million repetitions of 'a'"}; +static char *test_results[] = { + "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D", + "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1", + "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F"}; + +static void hex_p(char *s, int c) +{ + const char *hextab = "0123456789ABCDEF"; + s[0] = hextab[(c >> 4) & 0xf]; + s[1] = hextab[c & 0xf]; +} + + +void digest_to_hex(const uint8_t digest[SHA1_DIGEST_LENGTH], char *output) +{ + int i,j; + char *c = output; + + for (i = 0; i < SHA1_DIGEST_LENGTH/4; i++) { + for (j = 0; j < 4; j++) { + hex_p(c, digest[i*4+j]); + c += 2; + } + *c = ' '; + c += 1; + } + *(c - 1) = '\0'; +} + +int test_result = 0; + +void test_sha1() +{ + int k; + uint8_t digest[20]; + uint8_t output[80]; + + for (k = 0; k < 2; k++){ + + sha1(test_data[k], strlen(test_data[k]), digest); + digest_to_hex(digest, output); + if (strcmp(output, test_results[k])) { + test_result = 1; + break; + } + } + +} + +#endif + +void display_otp(u8 line, u8 update) +{ + +#ifdef TEST_SHA1 + test_sha1(); +#endif + + if (update == DISPLAY_LINE_UPDATE_FULL || update==DISPLAY_LINE_UPDATE_PARTIAL) + { + u8 *str; + + display_symbol(LCD_ICON_HEART, SEG_ON); + + otp(); + + if (!display_mode) { + display_symbol(LCD_SYMB_MAX, SEG_OFF); + int v = (last_val/10000) % 100; + str = itoa(v, 2, 0); + display_chars(LCD_SEG_L2_1_0, str, SEG_ON); + } else { + display_symbol(LCD_SYMB_MAX, SEG_ON); + int v = (last_val%10000); + str = itoa(v, 4, 0); + display_chars(LCD_SEG_L2_3_0, str, SEG_ON); + } + +#ifdef TEST_SHA1 + if (test_result) + str = "9999"; + display_chars(LCD_SEG_L2_3_0, str, SEG_ON); +#endif + + + } + if (update == DISPLAY_LINE_CLEAR) { + display_symbol(LCD_ICON_HEART, SEG_OFF); + display_symbol(LCD_SYMB_MAX, SEG_OFF); + display_mode = 0; + } +} + +#endif diff --git a/logic/otp.h b/logic/otp.h new file mode 100644 index 0000000..f8539b6 --- /dev/null +++ b/logic/otp.h @@ -0,0 +1,11 @@ +#ifndef OTP_H +#define OTP_H + + +extern void otp_sx(u8 line); +extern void otp_switch(u8 line); +extern void display_otp(u8 line, u8 update); +extern void update_otp(u8 line, u8 update); + + +#endif diff --git a/makefile b/makefile index cdd8b46..5968839 100644 --- a/makefile +++ b/makefile @@ -21,7 +21,7 @@ CC_INCLUDE = -I$(PROJ_DIR)/ -I$(PROJ_DIR)/include/ -I$(PROJ_DIR)/gcc/ -I$(PROJ_D CC_COPT = $(CC_CMACH) $(CC_DMACH) $(CC_DOPT) $(CC_INCLUDE) LOGIC_SOURCE = logic/acceleration.c logic/alarm.c logic/altitude.c logic/battery.c logic/clock.c logic/date.c logic/menu.c logic/rfbsl.c logic/rfsimpliciti.c logic/stopwatch.c logic/temperature.c logic/test.c logic/user.c logic/phase_clock.c logic/eggtimer.c logic/prout.c logic/vario.c logic/sidereal.c logic/strength.c \ - logic/sequence.c logic/gps.c + logic/sequence.c logic/gps.c logic/otp.c LOGIC_O = $(addsuffix .o,$(basename $(LOGIC_SOURCE))) diff --git a/tools/config.py b/tools/config.py index e1447bd..16dff57 100755 --- a/tools/config.py +++ b/tools/config.py @@ -4,7 +4,7 @@ import urwid import urwid.raw_display import sys - +import base64 import re, sys, random from sorteddict import SortedDict @@ -18,6 +18,16 @@ def rand_hw(): res.sort(reverse=True) return "{" + ",".join([hex(x) for x in res]) + "}" +#cstring is in the form of "\xaa\xbb" +def b32encoded_string_to_c_string(b32key): + key = base64.b32decode(b32key.upper().replace(" ","")) + return '"' + "".join(map(lambda x:"\\x%02x" % ord(x), list(key))) + '"' + +def c_string_to_b32encoded_string(cstring): + cstring = cstring.replace('"', '') + s = "".join(map (lambda x: chr(int("0x" + x, 16)), cstring.split("\\x")[1:])) + return base64.b32encode(s) + DATA = SortedDict() DATA["CONFIG_FREQUENCY"] = { @@ -230,6 +240,32 @@ def rand_hw(): "depends": [], "default": False} +###Implemented by Yohanes Nugroho (yohanes@gmail.com) + +DATA["CONFIG_OTP"] = { + "name": "OTP Function", + "depends": [], + "default": False, + "help": "Enable Time based OTP (one use of it is for google-authentication)" + } + + +DATA["CONFIG_OTP_KEY"] = { + "name": "OTP Key (in base32 encoded format)", + "depends": ["CONFIG_OTP"], + "default": "", + "type": "text", + "help": "OTP Key in base32 encoded format (spaces will be ignored)" } + +DATA["CONFIG_OTP_UTC_OFFSET"] = { + "name": "Offset from UTC for OTP Key generation", + "depends": ["CONFIG_OTP"], + "default": 0, + "type": "text", + "help": "Offset from UTC in hours (can be negative)" } + + + HEADER = """ #ifndef _CONFIG_H_ @@ -318,7 +354,7 @@ def main(self): list_content.append(hgf) elif field["type"] == "text": - f = urwid.AttrWrap(urwid.Edit("%s: "%field["name"], field["value"]), + f = urwid.AttrWrap(urwid.Edit("%s: "%field["name"], str(field["value"])), 'editbx', 'editfc') f._datafield = field self.fields[key] = f @@ -385,7 +421,7 @@ def save_config(self): if item.get_state(): # found the set radio button DATA[key]["value"] = item.value - # look up the + # look up the elif isinstance(field, urwid.Text): pass elif isinstance(field, urwid.AttrMap): @@ -397,6 +433,20 @@ def save_config(self): else: raise ValueError, "Unhandled type" + #special handling for OTP encoding + otp = DATA["CONFIG_OTP"] + otp_key = DATA["CONFIG_OTP_KEY"] + + if (len(otp_key["value"])>0): + try: + otp_key["value"] = b32encoded_string_to_c_string(otp_key["value"]) + except (TypeError) as a: + print "ERROR: invalid OTP Key (" + str(a) + ")" + if (otp["value"]): + print "OTP will be disabled" + otp["value"] = False + otp_key['value'] = '""' + fp = open("config.h", "w") fp.write("// !!!! DO NOT EDIT !!!, use: make config\n") fp.write(HEADER) @@ -453,7 +503,12 @@ def set_default(): m = m.groups() DATA[m[0]]["value"] = False - set_default() + otp_key = DATA["CONFIG_OTP_KEY"] + + if (len(otp_key["value"])>0): + otp_key["value"] = c_string_to_b32encoded_string(otp_key["value"]).lower() + + set_default() if __name__ == "__main__": App = OpenChronosApp() From e6d646fc9bab4ac5068f070ef017500c9472109e Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Thu, 15 Sep 2011 19:32:05 +0100 Subject: [PATCH 02/14] itoa was renamed to _itoa in the branch we just merged, so make the same change in the otp module. --- logic/otp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logic/otp.c b/logic/otp.c index adf2783..3173d95 100644 --- a/logic/otp.c +++ b/logic/otp.c @@ -395,12 +395,12 @@ void display_otp(u8 line, u8 update) if (!display_mode) { display_symbol(LCD_SYMB_MAX, SEG_OFF); int v = (last_val/10000) % 100; - str = itoa(v, 2, 0); + str = _itoa(v, 2, 0); display_chars(LCD_SEG_L2_1_0, str, SEG_ON); } else { display_symbol(LCD_SYMB_MAX, SEG_ON); int v = (last_val%10000); - str = itoa(v, 4, 0); + str = _itoa(v, 4, 0); display_chars(LCD_SEG_L2_3_0, str, SEG_ON); } From e6fab29e1a87feab0a59029795133f54fdc33bd0 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Tue, 13 Sep 2011 11:47:24 +0100 Subject: [PATCH 03/14] Fix config script for OTP --- tools/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/config.py b/tools/config.py index e95feb4..69147b4 100755 --- a/tools/config.py +++ b/tools/config.py @@ -561,7 +561,7 @@ def set_default(): otp_key = DATA["CONFIG_OTP_KEY"] - if (len(otp_key["value"])>0): + if ("value" in otp_key and len(otp_key["value"])>0): otp_key["value"] = c_string_to_b32encoded_string(otp_key["value"]).lower() set_default() From e49beb48d585c3d079c4ea95fe97f1a0a60df14e Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Tue, 13 Sep 2011 16:39:54 +0100 Subject: [PATCH 04/14] Fixes to config script so that 'make config' will actually run without crashing. --- tools/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/config.py b/tools/config.py index 69147b4..7253bd1 100755 --- a/tools/config.py +++ b/tools/config.py @@ -561,7 +561,7 @@ def set_default(): otp_key = DATA["CONFIG_OTP_KEY"] - if ("value" in otp_key and len(otp_key["value"])>0): + if ("value" in otp_key and isinstance(otp_key["value"], str) and len(otp_key["value"])>0): otp_key["value"] = c_string_to_b32encoded_string(otp_key["value"]).lower() set_default() From c8680c7b17c8782ef391cb9f37c2759eeb7d8c24 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Tue, 13 Sep 2011 18:11:28 +0100 Subject: [PATCH 05/14] update_otp should return a value. --- logic/otp.c | 3 ++- logic/otp.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/logic/otp.c b/logic/otp.c index 3173d95..733419f 100644 --- a/logic/otp.c +++ b/logic/otp.c @@ -315,9 +315,10 @@ void otp_switch(u8 line) display_otp(line, DISPLAY_LINE_UPDATE_PARTIAL); } -void update_otp(u8 line, u8 update) +u8 update_otp(u8 line, u8 update) { otp(); + return 0; } #ifdef TEST_SHA1 diff --git a/logic/otp.h b/logic/otp.h index f8539b6..650257c 100644 --- a/logic/otp.h +++ b/logic/otp.h @@ -5,7 +5,7 @@ extern void otp_sx(u8 line); extern void otp_switch(u8 line); extern void display_otp(u8 line, u8 update); -extern void update_otp(u8 line, u8 update); +extern u8 update_otp(u8 line, u8 update); #endif From a8b2fdebdae82751428a513434e9b545d246fc7b Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Tue, 13 Sep 2011 18:12:10 +0100 Subject: [PATCH 06/14] Removing unused variables. --- logic/otp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/logic/otp.c b/logic/otp.c index 733419f..0405878 100644 --- a/logic/otp.c +++ b/logic/otp.c @@ -51,7 +51,7 @@ extern struct date sDate; static uint8_t hmac_key[HMAC_KEY_LENGTH]; static uint32_t sha1_digest[8]; -static uint32_t sha1_count, sha1_count_hi; +static uint32_t sha1_count; static uint8_t sha1_data[SHA1_BLOCKSIZE]; static uint32_t sha1_W[80]; static uint8_t hmac_tmp_key[64 + HMAC_DATA_LENGTH]; @@ -59,7 +59,6 @@ static uint8_t hmac_sha[SHA1_DIGEST_LENGTH]; // The key for the inner digest is derived from our key, by padding the key // the full length of 64 bytes, and then XOR'ing each byte with 0x36. -static uint8_t tmp_key[64]; /* SHA f()-functions */ @@ -249,7 +248,6 @@ uint32_t simple_mktime(int year, int month, int day, int hour, int minute, int s return (result); } -static char otp_result[5]; static uint8_t data[] = {0,0,0,0,0,0,0,0}; const char *key = CONFIG_OTP_KEY; From e3d9f4d3fee332c868dd0ec626d32fd4eceefb04 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Tue, 13 Sep 2011 18:13:01 +0100 Subject: [PATCH 07/14] Fixing formatting. --- logic/otp.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/logic/otp.c b/logic/otp.c index 0405878..997ea7f 100644 --- a/logic/otp.c +++ b/logic/otp.c @@ -250,7 +250,7 @@ uint32_t simple_mktime(int year, int month, int day, int hour, int minute, int s static uint8_t data[] = {0,0,0,0,0,0,0,0}; -const char *key = CONFIG_OTP_KEY; +const char *key = CONFIG_OTP_KEY; extern struct date sDate; extern struct time sTime; @@ -260,7 +260,7 @@ static uint32_t last_val = 0; uint32_t otp() { - uint32_t val =0; + uint32_t val = 0; int i; uint32_t time = simple_mktime(sDate.year, sDate.month - 1, sDate.day, @@ -288,7 +288,7 @@ uint32_t otp() int off = hmac_sha[SHA1_DIGEST_LENGTH-1] & 0x0f; char *cc = (char *)&val; - for (i =0; i < 4; i++) { + for (i = 0; i < 4; i++) { cc[3-i] = hmac_sha[off+i]; } val &= 0x7fffffff; @@ -383,7 +383,7 @@ void display_otp(u8 line, u8 update) test_sha1(); #endif - if (update == DISPLAY_LINE_UPDATE_FULL || update==DISPLAY_LINE_UPDATE_PARTIAL) + if (update == DISPLAY_LINE_UPDATE_FULL || update == DISPLAY_LINE_UPDATE_PARTIAL) { u8 *str; @@ -393,12 +393,12 @@ void display_otp(u8 line, u8 update) if (!display_mode) { display_symbol(LCD_SYMB_MAX, SEG_OFF); - int v = (last_val/10000) % 100; + int v = (last_val / 10000) % 100; str = _itoa(v, 2, 0); display_chars(LCD_SEG_L2_1_0, str, SEG_ON); } else { display_symbol(LCD_SYMB_MAX, SEG_ON); - int v = (last_val%10000); + int v = (last_val % 10000); str = _itoa(v, 4, 0); display_chars(LCD_SEG_L2_3_0, str, SEG_ON); } @@ -408,8 +408,6 @@ void display_otp(u8 line, u8 update) str = "9999"; display_chars(LCD_SEG_L2_3_0, str, SEG_ON); #endif - - } if (update == DISPLAY_LINE_CLEAR) { display_symbol(LCD_ICON_HEART, SEG_OFF); From 8983565b2398ec49a76bd127f284961f4b98236f Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Tue, 13 Sep 2011 18:14:05 +0100 Subject: [PATCH 08/14] Adding support for HOTP, with a config option to choose between HOTP and TOTP. --- logic/otp.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++- tools/config.py | 5 +++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/logic/otp.c b/logic/otp.c index 997ea7f..b70e506 100644 --- a/logic/otp.c +++ b/logic/otp.c @@ -49,6 +49,12 @@ extern struct date sDate; #define HMAC_KEY_LENGTH 10 #define HMAC_DATA_LENGTH 8 +#ifdef CONFIG_HOTP +#define HOTP +#else +#define TOTP +#endif + static uint8_t hmac_key[HMAC_KEY_LENGTH]; static uint32_t sha1_digest[8]; static uint32_t sha1_count; @@ -225,6 +231,7 @@ uint8_t* hmac_sha1(uint8_t *data) { return hmac_sha; } +#ifdef TOTP static int days[12] ={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; uint32_t simple_mktime(int year, int month, int day, int hour, int minute, int second) @@ -247,17 +254,25 @@ uint32_t simple_mktime(int year, int month, int day, int hour, int minute, int s return (result); } +#endif static uint8_t data[] = {0,0,0,0,0,0,0,0}; +static uint32_t last_val = 0; const char *key = CONFIG_OTP_KEY; +#ifdef TOTP extern struct date sDate; extern struct time sTime; static uint32_t last_time = 0; -static uint32_t last_val = 0; +#endif + +#ifdef HOTP +static uint64_t counter = 0; +#endif +#ifdef TOTP uint32_t otp() { uint32_t val = 0; @@ -298,12 +313,45 @@ uint32_t otp() return val; } +#endif + +#ifdef HOTP +uint32_t otp() +{ + int i; + uint64_t temp = counter; + for (i = 0; i < 8; ++i) { + data[7 - i] = temp & 0xff; + temp >>= 8; + } + + memcpy(hmac_key, key, HMAC_KEY_LENGTH); + hmac_sha1(data); + + int off = hmac_sha[SHA1_DIGEST_LENGTH - 1] & 0x0f; + + last_val = 0; + char *cc = (char *) &last_val; + for (i = 0; i < 4; i++) { + cc[3 - i] = hmac_sha[off + i]; + } + last_val &= 0x7fffffff; + last_val %= 1000000; + + ++counter; + + return last_val; +} +#endif static int display_mode = 0; //show first 2 digits void otp_sx(u8 line) { otp(); +#ifdef HOTP + display_mode = 0; +#endif display_otp(line, DISPLAY_LINE_UPDATE_PARTIAL); } @@ -315,7 +363,9 @@ void otp_switch(u8 line) u8 update_otp(u8 line, u8 update) { +#ifdef TOTP otp(); +#endif return 0; } @@ -389,7 +439,9 @@ void display_otp(u8 line, u8 update) display_symbol(LCD_ICON_HEART, SEG_ON); +#if TOTP otp(); +#endif if (!display_mode) { display_symbol(LCD_SYMB_MAX, SEG_OFF); diff --git a/tools/config.py b/tools/config.py index 7253bd1..9bc6931 100755 --- a/tools/config.py +++ b/tools/config.py @@ -307,6 +307,11 @@ def c_string_to_b32encoded_string(cstring): "help": "Enable Time based OTP (one use of it is for google-authentication)" } +DATA["CONFIG_HOTP"] = { + "name": "HOTP algorithm", + "depends": ["CONFIG_OTP"], + "default": False, + "help": "Use event-based OTP rather than time-based"} DATA["CONFIG_OTP_KEY"] = { "name": "OTP Key (in base32 encoded format)", From 3ddc8545b68c7355244e4acdb1e5945dd2dbc49f Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Tue, 13 Sep 2011 18:14:27 +0100 Subject: [PATCH 09/14] Moving OTP nearer to the start of the menu, as it makes more sense there. --- logic/menu.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/logic/menu.c b/logic/menu.c index 99caf1e..d3b53f3 100644 --- a/logic/menu.c +++ b/logic/menu.c @@ -506,6 +506,9 @@ const struct menu *menu_L2[]={ #ifdef CONFIG_BATTERY &menu_L2_Battery, #endif + #ifdef CONFIG_OTP + &menu_L2_Otp, + #endif #ifdef CONFIG_PHASE_CLOCK &menu_L2_Phase, #endif @@ -530,10 +533,6 @@ const struct menu *menu_L2[]={ #ifdef CONFIG_USE_GPS &menu_L2_Gps, #endif - #ifdef CONFIG_OTP - &menu_L2_Otp, - #endif - }; const int menu_L2_size=sizeof(menu_L2)/sizeof(struct menu*); From da011faba6aa22efd0817e867ed5dba2c7ad1c5b Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Tue, 13 Sep 2011 18:16:28 +0100 Subject: [PATCH 10/14] Switching button functions around for OTP. Right button now switches between first 2 and last 4 digits, while long press of left button generates a new code. --- logic/otp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/logic/otp.c b/logic/otp.c index b70e506..7ff98bf 100644 --- a/logic/otp.c +++ b/logic/otp.c @@ -348,16 +348,16 @@ static int display_mode = 0; //show first 2 digits void otp_sx(u8 line) { - otp(); -#ifdef HOTP - display_mode = 0; -#endif + display_mode = !display_mode; display_otp(line, DISPLAY_LINE_UPDATE_PARTIAL); } void otp_switch(u8 line) { - display_mode = !display_mode; + otp(); +#ifdef HOTP + display_mode = 0; +#endif display_otp(line, DISPLAY_LINE_UPDATE_PARTIAL); } From 3d1702158853b4eeff84fbb34f78a839662849f1 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Fri, 23 Sep 2011 16:20:28 +0100 Subject: [PATCH 11/14] Fixing size of buffer that was too small and being overflowed. --- logic/otp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/otp.c b/logic/otp.c index 7ff98bf..1e0ed32 100644 --- a/logic/otp.c +++ b/logic/otp.c @@ -60,7 +60,7 @@ static uint32_t sha1_digest[8]; static uint32_t sha1_count; static uint8_t sha1_data[SHA1_BLOCKSIZE]; static uint32_t sha1_W[80]; -static uint8_t hmac_tmp_key[64 + HMAC_DATA_LENGTH]; +static uint8_t hmac_tmp_key[64 + SHA1_DIGEST_LENGTH]; // 64 + max(HMAC_DATA_LENGTH, SHA1_DIGEST_LENGTH) static uint8_t hmac_sha[SHA1_DIGEST_LENGTH]; // The key for the inner digest is derived from our key, by padding the key From 6b82a8d2a6ca28ead290a7aacfc8930efe258b97 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Fri, 23 Sep 2011 17:19:40 +0100 Subject: [PATCH 12/14] Supporting HMAC key lengths other than 10 for OTP. --- logic/otp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/otp.c b/logic/otp.c index 1e0ed32..09c108e 100644 --- a/logic/otp.c +++ b/logic/otp.c @@ -46,7 +46,7 @@ extern struct date sDate; #define SHA1_DIGEST_LENGTH 20 /*in this implementation: MAX = 63*/ -#define HMAC_KEY_LENGTH 10 +#define HMAC_KEY_LENGTH (sizeof(CONFIG_OTP_KEY) - 1) #define HMAC_DATA_LENGTH 8 #ifdef CONFIG_HOTP From ae4847430a535cf18c219830542ca7a52fb089a9 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Mon, 26 Sep 2011 17:49:00 +0100 Subject: [PATCH 13/14] Adding Google copyright notice. --- logic/otp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/logic/otp.c b/logic/otp.c index 09c108e..29e026b 100644 --- a/logic/otp.c +++ b/logic/otp.c @@ -1,5 +1,6 @@ /** Copyright (c) 2011 Yohanes Nugroho (yohanes@gmail.com) + Copyright (c) 2011 Google Inc. (qwandor@google.com) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by From 34ef6204f3cac61085f0f32db5573bd0e66d1fe8 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Fri, 31 Aug 2012 10:01:02 +0100 Subject: [PATCH 14/14] Fix to TOTP config from github comment. --- logic/otp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/otp.c b/logic/otp.c index 29e026b..6e6737a 100644 --- a/logic/otp.c +++ b/logic/otp.c @@ -440,7 +440,7 @@ void display_otp(u8 line, u8 update) display_symbol(LCD_ICON_HEART, SEG_ON); -#if TOTP +#ifdef TOTP otp(); #endif