3 ms·
It is even shorter without boilerplates: def hotp(key, counter, digits=6, digest='sha1'): key = base64.b32decode(key.upper() + '=' * ((8 - len(key)
by lifthrasiir 2y ago
It is even shorter without boilerplates:
def hotp(key, counter, digits=6, digest='sha1'):
key = base64.b32decode(key.upper() + '=' * ((8 - len(key)) % 8))
counter = struct.pack('>Q', counter)
mac = hmac.new(key, counter, digest).digest()
offset = mac[-1] & 0x0f
binary = struct.unpack('>L', mac[offset:offset+4])[0] & 0x7fffffff
return str(binary)[-digits:].zfill(digits)
def totp(key, time_step=30, digits=6, digest='sha1'):
return hotp(key, int(time.time() / time_step), digits, digest)
- notpushkin 2y agoEver so slightly easier to read (IMO) if you inline arguments: def hotp(key: bytes, counter: int, digits: int = 6, digest: Literal["sha1", "sha256", "sha512"] = "sha1"): mac = hmac.digest( key=base64.b32decode(key.upper() + "=" * ((8 - len(key)) % 8)), msg=struct.pack(">Q", counter), digest=digest, ) offset = mac[-1] & 0x0F binary: int = struct.unpack(">L", mac[offset : offset + 4])[0] & 0x7FFFFFFF return str(binary)[-digits:].zfill(digits) And Pyright doesn’t yell at this version because no type-changing variables here: https://basedpyright.com/?typeCheckingMode=all&code=JYWwDg9gTgLgBAIwIYGcCmA2ALAKFJWOACxCQGM9xp4UYoBXMmSg%2BGUNHHAEzQDNiEGGAAUAazQBPAFxxaUADRwyEegDsYaKLOAal3YAHNgMFDo1wAvHAz6jaWrPlW4AchREkARlcBKaThwQXASki7I6NgAdAgAzABMvCq84lJR9GBgWiK%2BcADUbpaucABUcCIiABxwALRwADZoaqmSvrkApHCVbYHBKuqaUC7yjDBRYORiIq4AfACKrkr9Glq%2BvUGkZC4k5FFqaADuLUuqK4pwBoYOML5Rl9c563AQfHzo8NabANo1XgC6cAAZHAAAwADxBfCeCF0SCgYWsIyY6TUEzIU1mABlFnBvi83mgYNJ8e88lg-r4viCAcDwQB2V6M15PKCE%2BhQNRyOgiGFqOGtH6XExmP5RABefGA9XqIiFpjWPH4cBgQlEoSU7BAaAA%2BrQ0GBLLEQXZjKZLLYLvZaEUPN4-AFgnBWTB2ZyiKrjnBdDARJq0FE-Tk4AB6ZUcXWaMC%2BE3Ck3XXxAA https://basedpyright.com/?typeCheckingMode=all&code=JYWwDg9g... --- This is actually really helpful. I’m using Pass [1], which requires oathtool for OTP support [2]. I’m currently on a Mac without admin rights (so no Homebrew for me), and compiling oathtool is a PITA. I’ve wanted to put together a pure Python replacement for a while now, but with this it can be a single-file script: https://gist.github.com/notpushkin/7ac32ddf35a0c73bc6f181a1b5dffa4f https://gist.github.com/notpushkin/7ac32ddf35a0c73bc6f181a1b... [1]: https://www.passwordstore.org/ https://www.passwordstore.org/ [2]: https://github.com/tadfisher/pass-otp#requirements https://github.com/tadfisher/pass-otp#requirements
- LtWorf 2y agoWhy not do an integer division?