/usr/lib/python2.7/dist-packages/pyotp/otp.py is in python-pyotp 2.2.1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | from __future__ import absolute_import, division, print_function, unicode_literals
import base64
import hashlib
import hmac
from .compat import str
class OTP(object):
def __init__(self, s, digits=6, digest=hashlib.sha1):
"""
@param [String] secret in the form of base32
@option options digits [Integer] (6)
Number of integers in the OTP
Google Authenticate only supports 6 currently
@option options digest [Callable] (hashlib.sha1)
Digest used in the HMAC
Google Authenticate only supports 'sha1' currently
@returns [OTP] OTP instantiation
"""
self.digits = digits
self.digest = digest
self.secret = s
def generate_otp(self, input):
"""
@param [Integer] input the number used seed the HMAC
Usually either the counter, or the computed integer
based on the Unix timestamp
"""
hasher = hmac.new(self.byte_secret(), self.int_to_bytestring(input), self.digest)
hmac_hash = bytearray(hasher.digest())
offset = hmac_hash[-1] & 0xf
code = ((hmac_hash[offset] & 0x7f) << 24 |
(hmac_hash[offset + 1] & 0xff) << 16 |
(hmac_hash[offset + 2] & 0xff) << 8 |
(hmac_hash[offset + 3] & 0xff))
str_code = str(code % 10 ** self.digits)
while len(str_code) < self.digits:
str_code = '0' + str_code
return str_code
def byte_secret(self):
missing_padding = len(self.secret) % 8
if missing_padding != 0:
self.secret += '=' * (8 - missing_padding)
return base64.b32decode(self.secret, casefold=True)
@staticmethod
def int_to_bytestring(i, padding=8):
"""
Turns an integer to the OATH specified
bytestring, which is fed to the HMAC
along with the secret
"""
result = bytearray()
while i != 0:
result.append(i & 0xFF)
i >>= 8
# It's necessary to convert the final result from bytearray to bytes
# because the hmac functions in python 2.6 and 3.3 don't work with
# bytearray
return bytes(bytearray(reversed(result)).rjust(padding, b'\0'))
|