Benutzer:Mihi/TinyTOTP: Unterschied zwischen den Versionen
Mihi (Diskussion | Beiträge) (Die Seite wurde neu angelegt: „==TinyTOTP== Goal: Time based One Time Passwords in a small embedded device. Basically cloning the functionality of my RSA SecurID ==Design Thoughts== Want to …“) |
Mihi (Diskussion | Beiträge) (→HOTP) |
||
Zeile 18: | Zeile 18: | ||
===HOTP=== | ===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: | ||
+ | <pre> | ||
+ | #!/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) | ||
+ | </pre> |
Aktuelle Version vom 14. Januar 2011, 14:36 Uhr
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)