7 ms·
Tiny Toy TOTP Generator in 18 Lines of Python
- xendo 7y ago5 most important lines: import base64 import hmac import struct import sys import time
- pushpop 7y agoI get your point but equally the point of programming languages is to abstract away the harder stuff. The question is just how much abstraction developers want between the code and the execution. I mean, you could make the same claim about one written in C because it doesn’t include stdio.h. So where do you draw the line? Assembly?
- xendo 7y agoMy point is that saying that something is written in 18 lines of code when actually all the heavy lifting is done by the libraries is misleading. That doesn’t mean I don’t appreciate Python’s expressiveness and rich standard library.
- icebraining 7y agoYeah, but that comment can be made about literally every software in existence. Even core language keywords are doing a lot of heavy lifting in the interpreter. In Python, the stdlib is effectively part of the language, so as long as they're not installing third-party libs, I don't see how it can be misleading.
- anamexis 7y agoI think you both raise valid points. This was an interesting thing to look at to see get a quick idea of how TOTP works. On the flip side, though, if this we had this hypothetical implementation: import totp if __name__ == '__main__': totp.generate() Well, we probably wouldn't be here discussing it.
- PeterisP 7y agoWell, the key part essentially is just like that, it's the single line mac = hmac.new(secret_bytes, counter_bytes, digest).digest() and everything else is just converting data to/from the proper format for this function.
- anamexis 7y agoWell sure, but given that TOTP is itself just formatted HMAC, that "everything else" of formatting is the essence of TOTP. Otherwise you probably wouldn't say you're implementing TOTP, you'd say you're implementing HMAC.
- userbinator 7y agoI'd say these are the 4 most important, because they show the actual core of the algorithm; everything else is just input/output: mac = hmac.new(secret_bytes, counter_bytes, digest).digest() offset = mac[-1] & 0x0f truncated = struct.unpack('>L', mac[offset:offset+4])[0] & 0x7fffffff return str(truncated)[-digits:].rjust(digits, '0') In other words, HMAC your secret key with the time and pick digits using the output of the HMAC.
- mhb 7y agoSingle most important line: TOTP stands for Time-based One-Time Password
- shakna 7y agoAlong with micropython-hmac (MicroPython doesn't include hmac), and the touch sensor on an ESP32 I threw together an authenticator with the same inspiration as this project. It seems to work quite well, overall.
- saghul 7y agoI haven't used MicroPython in a long time, but it seems to include hmac: https://github.com/micropython/micropython-lib/tree/master/hmac https://github.com/micropython/micropython-lib/tree/master/h... right?
- porterde 7y agoBeing of a certain age and in the UK, I was disappointed to find this is not an 18 line Top Of The Pops generator... :)
- wilsonrocks 7y agoSame here!
- ggm 7y agoComes with mandatory "whole lotta love" algorithm and bad lip sync
- iamnotacrook 7y agoNo nonces, either.
- gingerlime 7y agoPlugging my hotp/totp python library hotpie[0]. Written originally in 2010. Around 100 lines including comments and tests against the RFC. Available on Pypi for python 2.x and 3.x. The beauty of HOTP/TOTP for me is its simplicity. And being able to write a simple implementation makes it easy to test, debug and be sure that there are little or no holes. [0] https://github.com/gingerlime/hotpie https://github.com/gingerlime/hotpie
- fr33104d 7y agoI remember having fun implementing that rfc and having a sort of Google authenticator on my Linux box besides Android. https://github.com/bjornua/totp.py/blob/master/totp.py https://github.com/bjornua/totp.py/blob/master/totp.py
- tedk-42 7y agoMFA - what you have. I personally prefer this golang library to generate my OTP codes https://github.com/pquerna/otp https://github.com/pquerna/otp as it's much faster than running a python script. My personal computer is the 'what I have' to do the second factor of authentication for most sites via a shell script, followed by xclip (linux) or pbcopy (mac). I prefer this over browser extensions using javascript to paste in your OTP code for you.
- icebraining 7y agoIf you want raw speed, oathtool is hard to beat. Only 132KB to load to memory, compared to the megabytes of the typical Go binary. But unless you're playing an FPS where you have to input TOTP codes to shoot, this script is probably fast enough (80ms on my old laptop).
- Thorrez 7y agoThe python binary itself will take some memory. Although maybe it can be shared with other running python processes.
- userbinator 7y agoOnly 132KB to load to memory It's amusing to see people think 100KB+ is small, when the whole TOTP algorithm, including SHA1 (probably the biggest part), and the input/output conversion, likely needs only a few KB of code. With the exception of SHA1, everything else is doable in dozens of bytes.
- icebraining 7y agoTrue, but I'm just talking about the sizes of the binaries generated by the default settings of common compilers (gcc, in the case of oathtool), for comparing orders of magnitude. I'm sure there's plenty of fat you could trim by simply tuning the compilation a bit. (Oathtool also supports SHA2, since it may be used by other implementations, per the RFC. )
- ddevault 7y agoIn practice, clocks are often out of sync enough that you want to give some leeway and accept some codes on either side of the current code. The implementation I use for sourcehut is similarly tiny: https://git.sr.ht/~sircmpwn/meta.sr.ht/tree/master/metasrht/totp.py https://git.sr.ht/~sircmpwn/meta.sr.ht/tree/master/metasrht/...
- susam 7y agoYes, in fact the RFCs for both HOTP and TOTP have a section each dedicated to resynchronization of counter/clock to account for client and server being out of sync. Here are the relevant sections: - RFC 4226 (HOTP): Section 7.4 (Resynchronization of the Counter): https://tools.ietf.org/html/rfc4226#section-7.4 https://tools.ietf.org/html/rfc4226#section-7.4 - RFC 6238 (TOTP): Section 6 (Resynchronization): https://tools.ietf.org/html/rfc6238#section-6 https://tools.ietf.org/html/rfc6238#section-6 In case of HOTP, the client's counter could be ahead of the server's counter if a user requests multiple HOTPs from the client before the user presents the HOTP to the server. Therefore the server should look ahead according to a permissible look-ahead window to see if any succeeding HOTP value matches the HOTP presented by the user or client. In case of TOTP, there is of course the problem of clock drifts. Therefore the server should look backward as well as forward by a few time steps to see if any TOTP backward or forward matches the TOTP presented by the user or client.
- dunham 7y agoIn the past, when I've implemented TOTP on the server, I've allowed for a couple of time periods of drift. But I recorded the time period that last matched, and only allowed subsequent authentication attempts to be strictly greater than the last successful time period, to prevent replay attacks.
- susam 7y agoYes, RFC 6238 requires this too. Quoting from https://tools.ietf.org/html/rfc6238#section-5.2 https://tools.ietf.org/html/rfc6238#section-5.2: > Note that a prover may send the same OTP inside a given time-step window multiple times to a verifier. The verifier MUST NOT accept the second attempt of the OTP after the successful validation has been issued for the first OTP, which ensures one-time only use of an OTP.
- yuri91 7y agoThe RFCs for HOTP[0] and TOTP[1] are very readable. I built a small cli utility to manage my TOTP logins easily using them as reference. [0] https://tools.ietf.org/html/rfc4226 https://tools.ietf.org/html/rfc4226 [1] https://tools.ietf.org/html/rfc6238 https://tools.ietf.org/html/rfc6238
- Thorrez 7y ago>However, doing so defeats the purpose of two-factor authentication (2FA). There are still some 2FA benefits from this. The biggest one is for people who reuse passwords. Some websites might put you into a higher security tier if you have 2FA. Also if you have to choose between SMS vs this, this has some benefits, for example it can't be hijacked by social engineering your phone provider. Also it says regular TOTP protects you from keyloggers. That's not fully true, because the keylogger could steal your TOTP code as you enter it into the website. If the keylogger is realtime, it could log into your account before you're able to. Or if you assume there's malware on your computer, it could steal your cookies, or perform whatever account actions it wants directly on your computer.
- susam 7y agoThe README does not say that TOTP protects us from keyloggers. I was either not clear in writing that paragraph or you may have misundertood that paragraph. Here's what the README says, > If your desktop/laptop device is compromised, then both authentication factors would be compromised. The attacker can steal the first authentication factor that only you should know (e.g., password) by running a key logger on the compromised device. The attacker can also steal the second authentication factor that only you should have ... What I mean here is that generating the TOTP on the same system that we would use to log into a website with 2FA defeats the purpose of 2FA because the attacker can steal the TOTP secret key in addition to stealing the password (keylogger being one way to steal the password).
- eikenberry 7y agoI think the grandparent is just trying to say that while it defeats one of the purposes behind 2fa, it doesn't defeat all of them. Security is all about trade-offs and defense in depth and 2fa is still valuable in this sense even with the 2fa secret stored on your laptop. That is, it trades off some security for convenience but is still more secure than not having 2fa.
- susam 7y agoI agree. I think it is acceptable to trade some security for convenience and in this case the convenient solution is still more secure than not having 2FA at all. However, the fact that some security is being traded for convenience should be documented in the README, otherwise one can criticize that the README is promoting a less secure usage of TOTP.
- ianai 7y agoAm I the only one who found the use of acronyms here a little annoying? Like, use the whole word expansion at least once before introducing the acronym. That should be standard practice regardless of discipline and audience.
- tptacek 7y agoWhich acronym? Expanding "TOTP" isn't going to help anyone; what you really want is the short sentence that simply explains what TOTP is.
- fwip 7y agoI didn't know what it meant, and looked it up. "Time-based One Time Password" explains a hell of a lot more that "TOTP." From just those 4 words I figured out we were talking about the kind of thing that powers 2-factor auth implementations where get a time-based one-time code. Before I looked it up, I thought it was somehow related to NTP.
- tptacek 7y agoMy point is that "time based one-time password" doesn't really tell you anything about what TOTP is; what you want is the phrase "the protocol code-based 2FA applications like Google Authenticator use", after which you don't care anymore about the stupid name the protocol has. It's a little bit like expanding "transport control protocol". I mean, sure, I guess it's marginally better than the acronym TCP? But really, that's not the clarification you want to provide to someone who doesn't know what TCP is. Also, obviously, if you don't know what TOTP is, you might just not be the audience for the article. Remember that most people don't write their personal blogs (or, in this case, their Github personal projects) specifically for an audience of Hacker News people, even though HN sometimes makes it seem that way.
- susam 7y agoAlthough not at the very first line, I do expand the acronyms in the first section: > Introduction: TOTP stands for Time-based One-Time Password. At the heart of the TOTP algorithm lies the HOTP algorithm. HOTP stands for HMAC-based One-Time Password.
- varshithr 7y agoIf we don't have to follow PEP8, how many lines can we condense it to? I am going to try.
- daneel_w 7y agoHere is one in 4 lines: https://github.com/stolendata/totp/blob/master/totp.php#L42-L45 https://github.com/stolendata/totp/blob/master/totp.php#L42-...
- deleted 7y ago[deleted]
- _def 7y agoReadability is more important than your ego.