Benutzer:Mihi/TinyTOTP

aus Metalab Wiki, dem offenen Zentrum für meta-disziplinäre Magier und technisch-kreative Enthusiasten.
Zur Navigation springenZur Suche springen

TinyTOTP

Goal: Time based One Time Passwords in a small embedded device. Basically cloning the functionality of my RSA SecurID

Design Thoughts

Want to have small USB HID device that outputs the current code on keypress or buttonpress.

Based on Attiny45 and v-usb[1]

Based on TOTP [2] and HOTP [3]. Simply because PAM modules exist on the other end. -> easy addition to OpenVPN, SSH etc.

Docu

Needs HMAC-SHA1 (available in the AVR crypto lib from das-labor [4])

Time chip: maxim - samples ordered DS1372 und DS1374 beide zaehlen 32bit binary (e.q. seconds since unix epoch, which is needed in TOTP). DS1374 comes with internal oscillator and battery backup loop.

HOTP

HOTP is defined by RFC 4226,

basically it works like this:

HOTP=Truncate(HMAC-SHA1(K,C))

Where K is Key, C is count and Truncate is an algorithm to produce n (usually n=6) decimal digits from the returned HMAC hash.

Truncate works as follows:

hs=HMAC-SHA1(K,C)

offset=hs & 0xf

hs[offset..offset+3] & 0x7fffffff 0x7f to discard the most significant bits here, some processors calculate sha1 slightly different (according to the RFC).

return hs % 10^n (n is our digits)

Sample implementation in python:

#!/usr/bin/python

import hmac
import hashlib
class hotp:
        def __init__(self,key,digits=6):
                self.key=key
                self.digits=digits

        def dynamictruncate(self,s):
                """dynamically truncate the string"""
                offset=int(s,16)&0xf
                return "%016x" % (int(s[offset*2:offset*2+8],16) 
                &0x7fffffff)

        def intto16string(self,c):
                """convert an int to a 16 byte string"""
                c="%016x" %count
                return "".join([chr(int(c[i*2:i*2+2],16)) for i in range 
                (0,8)])

        def get(self,count):
                """ calculates the HOTP for key and count """
                count=self.intto16string(count)
                hc=hmac.new(self.key,count,hashlib.sha1)
                s=hc.hexdigest()
                ts=self.dynamictruncate(s)
                snum=int(ts,16)
                return snum % (10 ** self.digits)

                return hotp.get(self,count)

if __name__=="__main__":
        h=hotp("12345678901234567890")
        for count in range (0,6):
                print h.get(count)