def test_verify(self, backend, params): secret = params["secret"] counter = int(params["counter"]) hotp_value = params["hotp"] hotp = HOTP(secret, 6, SHA1(), backend) hotp.verify(hotp_value, counter)
def check_hotp_value(hotp_token): """ Verify the HOTP token from the AS """ logger.info("Loading 2FA secret from %s", auth_secretfile) # Load the shared secret and counter from file with open(auth_secretfile, 'r') as f: content = json.loads(f.read()) secret = content['2FAKey'] counter = content['Counter'] logger.info("Loaded 2FA secret") hotp = HOTP(bytes(secret, 'utf-8'), 6, hashes.SHA1(), backend=default_backend()) logger.info("Trying to verify HOTP token") try: # Try to verify the token hotp.verify(hotp=bytes(hotp_token, 'utf-8'), counter=counter) # Verification failure would have raised an InvalidToken exception here logger.info("HOTP token successfully authenticated") # Save the updated secret to file counter += 1 # Increment the counter content['Counter'] = counter logger.info("HOTP counter updated to: %s", counter) with open(auth_secretfile, 'w') as f: # Write to file f.write(json.dumps(content)) return True except InvalidToken: logger.warning("HOTP token was not authenticated") return False
def verify_hotp_code(secret, code, counter): """ Validate a Google authenticator compatible HOTP code Args: secret: 16 character base32 secret code: 6 digit code that expires in 30 seconds counter: matching integer value Return: Counter value if validation successful or None """ if isinstance(secret, unicode): secret = secret.encode('utf-8') if isinstance(code, unicode): code = code.encode('utf-8') try: key = base64.b32decode(secret) hotp = HOTP(key, 6, SHA1(), backend=default_backend(), enforce_key_length=False) for count in range(counter, counter + 3): try: hotp.verify(code, count) return count except InvalidToken: pass except (ValueError, TypeError): pass return None
def generate_htop(length=6, salt=0): hotp = HOTP(key, length, SHA1(), backend=default_backend()) hotp_value = hotp.generate(salt) # hotp.verify(hotp_value, 0) return hotp_value.decode()
def test_invalid_verify(self, backend): secret = b"12345678901234567890" counter = 0 hotp = HOTP(secret, 6, SHA1(), backend) with pytest.raises(InvalidToken): hotp.verify(b"123456", counter)
def test_generate(self, backend, params): secret = params["secret"] counter = int(params["counter"]) hotp_value = params["hotp"] hotp = HOTP(secret, 6, SHA1(), backend) assert hotp.generate(counter) == hotp_value
def test_verify(self, backend, params): secret = params["secret"] counter = int(params["counter"]) hotp_value = params["hotp"] hotp = HOTP(secret, 6, SHA1(), backend) assert hotp.verify(hotp_value, counter) is None
def test_truncate(self, backend, params): secret = params["secret"] counter = int(params["counter"]) truncated = params["truncated"] hotp = HOTP(secret, 6, SHA1(), backend) assert hotp._dynamic_truncate(counter) == int(truncated.decode(), 16)
def __init__(self, key, length, algorithm, time_step, backend): if not isinstance(backend, HMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement HMACBackend.", _Reasons.BACKEND_MISSING_INTERFACE) self._time_step = time_step self._hotp = HOTP(key, length, algorithm, backend)
def test_get_provisioning_uri(self, backend): secret = b"12345678901234567890" hotp = HOTP(secret, 6, SHA1(), backend) assert hotp.get_provisioning_uri("Alice Smith", 1, None) == ( "otpauth://hotp/Alice%20Smith?digits=6&secret=GEZDGNBV" "GY3TQOJQGEZDGNBVGY3TQOJQ&algorithm=SHA1&counter=1") assert hotp.get_provisioning_uri("Alice Smith", 1, 'Foo') == ( "otpauth://hotp/Foo:Alice%20Smith?digits=6&secret=GEZD" "GNBVGY3TQOJQGEZDGNBVGY3TQOJQ&algorithm=SHA1&issuer=Foo" "&counter=1")
def test_get_provisioning_uri(self, backend): secret = b"12345678901234567890" hotp = HOTP(secret, 6, SHA1(), backend) assert hotp.get_provisioning_uri( "Alice Smith", 1, None) == ("otpauth://hotp/Alice%20Smith?digits=6&secret=GEZDGNBV" "GY3TQOJQGEZDGNBVGY3TQOJQ&algorithm=SHA1&counter=1") assert hotp.get_provisioning_uri( "Alice Smith", 1, "Foo") == ("otpauth://hotp/Foo:Alice%20Smith?digits=6&secret=GEZD" "GNBVGY3TQOJQGEZDGNBVGY3TQOJQ&algorithm=SHA1&issuer=Foo" "&counter=1")
def __init__( self, key: bytes, length: int, algorithm: _ALLOWED_HASH_TYPES, time_step: int, backend: typing.Any = None, enforce_key_length: bool = True, ): self._time_step = time_step self._hotp = HOTP(key, length, algorithm, enforce_key_length=enforce_key_length)
def retrieve_keys(db, attribute): """ Retrieve keys from the KS; This involves querying the KS with an authentication token Then decrypting and returning the encrypted payload db -- Databse whose keys to retrieve attribute -- The attribute whose encryption key to retrieve """ # Load the HOTP secret and counter from the secret file of the Key Server with open(ks_secretfile, 'r') as f: ksdict = json.loads(f.read()) counter = ksdict['Counter'] tfapass = ksdict['2FAKey'] # Calculate the HOTP token value hotp = HOTP(bytes(tfapass, 'utf-8'), 6, hashes.SHA1(), backend=default_backend()) tfaval = hotp.generate(counter).decode('utf-8') # Do the request to the key server #XXX: Chnage to https for deployment url = "http://{}:{}/key/{}/{}?token={}".format(ks_address, ks_port, db, attribute, tfaval) logger.info("Trying to access key from KS: %s", url) # Do the request try: resp = requests.get(url) except requests.exceptions.Timeout: logger.warning("KS request timeout") return None except requests.exceptions.ConnectionError: logger.warning("KS connection refused") return None logger.info("KS response code: %s", resp.status_code) if resp.status_code == 200: # Got 200 means KS incremented the counter counter += 1 # Increment our own counter # Save the updated secret ksdict['Counter'] = counter with open(ks_secretfile, 'w') as f: f.write(json.dumps(ksdict)) logger.info("KS HOTP counter was incremented to %s", counter) # Get the transport secure message secured_message = resp.json() key = transport_security.deconstruct_message(secured_message, destprivkey=app_privatekey, srcpubkey=ks_publickey) # Check if decryption was successful if not key: logger.warning("Secured message from KS was not decrypted properly") return None return key else: # KS did not return the key logger.warning("KS replied negatively. Something is wrong.") return None
def send_aic(sessionid, role, bindkey, pubkey): """ Send an AIC to the ags, returns success value sessionid -- Anonymized Session ID for user role -- Role as retrieved from database bindkey -- As generated during login pubkey -- Users stored public key context -- Users login context """ # AIC construct aic = {"sessionid":sessionid, "role":role, "bindkey":bindkey, "pubkey":pubkey} message = json.dumps(aic) logger.info("Genrated AIC: %s", message) # Secure the payload payload = transport_security.construct_message(message, srcprivkey=app_privatekey, destpubkey=ags_publickey) # Calculate the current HOTP token from file with open(ags_secretfile, 'r') as f: agsdict = json.loads(f.read()) counter = agsdict['Counter'] tfapass = agsdict['2FAKey'] hotp = HOTP(bytes(tfapass, 'utf-8'), 6, hashes.SHA1(), backend=default_backend()) tfaval = hotp.generate(counter).decode('utf-8') # Do the reques to the AGS #XXX: Change to https for deployment url = "http://{}:{}/ags/authorized?token={}".format(ags_address, ags_port, tfaval) logger.info("Adding AIC to AGS: %s", url) try: resp = requests.put(url, json=payload) except requests.Timeout: logger.warning("AGS connection timeout") return None except requests.ConnectionError: logger.warning("AGS connection error") return None logger.info("AGS AIC PUT status code: %s", resp.status_code) # A 200 OK response means the request was successful if resp.status_code == 200: # Update the HOTP counter value counter += 1 agsdict['Counter'] = counter with open(ags_secretfile, 'w') as f: f.write(json.dumps(agsdict)) logger.info("AGS HOTP counter was incremented to %s", counter) # Return the validity as returned by the AGS return resp.json()['validity'] else: logger.warning("AGS rejected AIC") return None
def test_invalid_backend(): secret = b"12345678901234567890" pretend_backend = object() with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): HOTP(secret, 8, hashes.SHA1(), pretend_backend)
def add_otptoken(host, owner, *, otptype="hotp", digits=6, algo="sha1"): args = [ "ipa", "otptoken-add", "--owner", owner, "--type", otptype, "--digits", str(digits), "--algo", algo, "--no-qrcode", ] result = host.run_command(args) otpuid = re.search(r"Unique ID:\s*([a-z0-9-]*)\s+", result.stdout_text).group(1) otpuristr = re.search(r"URI:\s*(.*)\s+", result.stdout_text).group(1) otpuri = urlparse(otpuristr) assert otpuri.netloc == otptype query = parse_qs(otpuri.query) assert query["algorithm"][0] == algo.upper() assert query["digits"][0] == str(digits) key = base64.b32decode(query["secret"][0]) assert len(key) == 35 hashcls = getattr(hashes, algo.upper()) if otptype == "hotp": return otpuid, HOTP(key, digits, hashcls(), default_backend()) else: period = int(query["period"][0]) return otpuid, TOTP(key, digits, hashcls(), period, default_backend())
class TOTP(object): def __init__( self, key: bytes, length: int, algorithm: _ALLOWED_HASH_TYPES, time_step: int, backend=None, enforce_key_length: bool = True, ): backend = _get_backend(backend) if not isinstance(backend, HMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement HMACBackend.", _Reasons.BACKEND_MISSING_INTERFACE, ) self._time_step = time_step self._hotp = HOTP(key, length, algorithm, backend, enforce_key_length) def generate(self, time: typing.Union[int, float]) -> bytes: counter = int(time / self._time_step) return self._hotp.generate(counter) def verify(self, totp: bytes, time: int) -> None: if not constant_time.bytes_eq(self.generate(time), totp): raise InvalidToken("Supplied TOTP value does not match.") def get_provisioning_uri(self, account_name: str, issuer: typing.Optional[str]) -> str: return _generate_uri(self._hotp, "totp", account_name, issuer, [("period", int(self._time_step))])
class TOTP(object): def __init__( self, key: bytes, length: int, algorithm: _ALLOWED_HASH_TYPES, time_step: int, backend: typing.Any = None, enforce_key_length: bool = True, ): self._time_step = time_step self._hotp = HOTP(key, length, algorithm, enforce_key_length=enforce_key_length) def generate(self, time: typing.Union[int, float]) -> bytes: counter = int(time / self._time_step) return self._hotp.generate(counter) def verify(self, totp: bytes, time: int) -> None: if not constant_time.bytes_eq(self.generate(time), totp): raise InvalidToken("Supplied TOTP value does not match.") def get_provisioning_uri(self, account_name: str, issuer: typing.Optional[str]) -> str: return _generate_uri( self._hotp, "totp", account_name, issuer, [("period", int(self._time_step))], )
class TOTP(object): def __init__(self, key, length, algorithm, time_step, backend, enforce_key_length=True): if not isinstance(backend, HMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement HMACBackend.", _Reasons.BACKEND_MISSING_INTERFACE) self._time_step = time_step self._hotp = HOTP(key, length, algorithm, backend, enforce_key_length) def generate(self, time): counter = int(time / self._time_step) return self._hotp.generate(counter) def verify(self, totp, time): if not constant_time.bytes_eq(self.generate(time), totp): raise InvalidToken("Supplied TOTP value does not match.") def get_provisioning_uri(self, account_name, issuer): return _generate_uri(self._hotp, "totp", account_name, issuer, [ ("period", int(self._time_step)), ])
def __init__(self, key, length, algorithm, time_step, backend, enforce_key_length=True): if not isinstance(backend, HMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement HMACBackend.", _Reasons.BACKEND_MISSING_INTERFACE ) self._time_step = time_step self._hotp = HOTP(key, length, algorithm, backend, enforce_key_length)
def __init__( self, key: bytes, length: int, algorithm: _ALLOWED_HASH_TYPES, time_step: int, backend=None, enforce_key_length: bool = True, ): backend = _get_backend(backend) if not isinstance(backend, HMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement HMACBackend.", _Reasons.BACKEND_MISSING_INTERFACE, ) self._time_step = time_step self._hotp = HOTP(key, length, algorithm, backend, enforce_key_length)
def generate_hotp_uri(secret, counter, email): """ Generate a Google authenticator compatible QR code provisioning URI Args: secret: 16 character base32 secret counter: unique integer value email: Authenticator email address Return: URI: otpauth://hotp/[email protected]?secret=JBSWY3DPEHPK3PXP&counter=0&issuer=FrostyWeb """ if isinstance(secret, unicode): secret = secret.encode('utf-8') try: key = base64.b32decode(secret) hotp = HOTP(key, 6, SHA1(), backend=default_backend(), enforce_key_length=False) return hotp.get_provisioning_uri(email, counter, 'FrostyWeb') except (ValueError, TypeError): pass return None
def generate_hotp_code(secret, counter): """ Generate a Google authenticator compatible HOTP code Args: secret: 16 character base32 secret (80 bit key) counter: unique integer value Return: code: 6 digit one time use code """ if isinstance(secret, unicode): secret = secret.encode('utf-8') try: key = base64.b32decode(secret) hotp = HOTP(key, 6, SHA1(), backend=default_backend(), enforce_key_length=False) hotp_value = hotp.generate(counter) return hotp_value except (ValueError, TypeError): pass return None
class TOTP(object): def __init__(self, key, length, algorithm, time_step, backend): self._time_step = time_step self._hotp = HOTP(key, length, algorithm, backend) def generate(self, time): counter = int(time / self._time_step) return self._hotp.generate(counter) def verify(self, totp, time): if not constant_time.bytes_eq(self.generate(time), totp): raise InvalidToken("Supplied TOTP value does not match")
class TOTP(object): def __init__(self, key, length, algorithm, time_step, backend): if not isinstance(backend, HMACBackend): raise UnsupportedInterface("Backend object does not implement HMACBackend") self._time_step = time_step self._hotp = HOTP(key, length, algorithm, backend) def generate(self, time): counter = int(time / self._time_step) return self._hotp.generate(counter) def verify(self, totp, time): if not constant_time.bytes_eq(self.generate(time), totp): raise InvalidToken("Supplied TOTP value does not match")
class TOTP(object): def __init__(self, key, length, algorithm, time_step, backend): if not isinstance(backend, HMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement HMACBackend.", _Reasons.BACKEND_MISSING_INTERFACE) self._time_step = time_step self._hotp = HOTP(key, length, algorithm, backend) def generate(self, time): counter = int(time / self._time_step) return self._hotp.generate(counter) def verify(self, totp, time): if not constant_time.bytes_eq(self.generate(time), totp): raise InvalidToken("Supplied TOTP value does not match.")
class TOTP(object): def __init__(self, key, length, algorithm, time_step, backend, enforce_key_length=True): if not isinstance(backend, HMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement HMACBackend.", _Reasons.BACKEND_MISSING_INTERFACE ) self._time_step = time_step self._hotp = HOTP(key, length, algorithm, backend, enforce_key_length) def generate(self, time): counter = int(time / self._time_step) return self._hotp.generate(counter) def verify(self, totp, time): if not constant_time.bytes_eq(self.generate(time), totp): raise InvalidToken("Supplied TOTP value does not match.") def get_provisioning_uri(self, account_name, issuer): return _generate_uri(self._hotp, "totp", account_name, issuer, [("period", int(self._time_step))])
def primitive(): # Initialize the errors variable to empty string. We will have the error messages # in that variable, if any. errors = '' if request.method == "GET": # If the request is GET, render the form template. return render_template("index.html", errors=errors) if 'aesForm' in request.form: # The request is POST with some data, get POST data and validate it. # The form data is available in request.form dictionary. Stripping it to remove # leading and trailing whitespaces aesPlainText = request.form['aesPlainText'].strip() # Check if all the fields are non-empty and raise an error otherwise if not aesPlainText: errors = "Please enter all the fields." if not errors: # If there are no errors, create a dictionary containing all the entered # data and pass it to the template to be displayed a1 = "Symmetric Encryption\n" a2 = "This application will use DES Symmetric Encryption to encrypt and decrypt text\n" plainText = "Text to encrypt: " getInput = aesPlainText backend = default_backend() cfb_Key = os.urandom(16) aes_Key = os.urandom(32) #secretMessage = str.encode(input(plainText)) secretMessage = str.encode(getInput) cipher = Cipher(algorithms.AES(aes_Key), modes.CFB(cfb_Key), backend=backend) encryptor = cipher.encryptor() encryptedText = encryptor.update( secretMessage) + encryptor.finalize() decryptor = cipher.decryptor() decryptedText = decryptor.update( encryptedText) + decryptor.finalize() dataAes = { 'aes_Key': aes_Key, 'cfb_Key': cfb_Key, 'encryptedText': encryptedText, 'decryptedText': decryptedText } # Since the form data is valid, render the success template return render_template("prim/aes.html", dataAes=dataAes) # Render the form template with the error messages return render_template("index.html", errors=errors) if 'desForm' in request.form: # The request is POST with some data, get POST data and validate it. # The form data is available in request.form dictionary. Stripping it to remove desPlainText = request.form['desPlainText'].strip() #desBitKey = request.form['desBitKey'].strip() #desMode = request.form['desMode'].strip() # Check if all the fields are non-empty and raise an error otherwise if not desPlainText: errors = "Please enter all the fields." if not errors: # If there are no errors, create a dictionary containing all the entered # data and pass it to the template to be displayed plaintext = desPlainText mode = "CBC" key = "12345678" #key and plain text desKey = des(key, mode, "\0\0\0\0\0\0\0\0") #print ("Key : %r" % k.getKey()) #print ("Plaintext : %r" % plaintext) #desKey = k # Encrypted message desEnc = desKey.encrypt(plaintext, [], PAD_PKCS5) #print ("Encrypted: %r" % d) desEncMessage = desEnc # Decrypted message desDec = desKey.decrypt(desEncMessage, [], PAD_PKCS5) #print ("Decrypted Plaintext: %r" % d) desDecMessage = desDec dataDes = { 'desPlainText': desPlainText, 'desKey': desKey, 'desEncMessage': desEncMessage, 'desDecMessage': desDecMessage } # Since the form data is valid, render the success template return render_template("prim/des.html", dataDes=dataDes) # Render the form template with the error messages return render_template("index.html", errors=errors) if 'hmacForm' in request.form: # The request is POST with some data, get POST data and validate it. # The form data is available in request.form dictionary. Stripping it to remove hmacPlainText = request.form['hmacPlainText'].strip() # Check if all the fields are non-empty and raise an error otherwise if not hmacPlainText: errors = "Please enter all the fields." if not errors: # If there are no errors, create a dictionary containing all the entered # data and pass it to the template to be displayed shared_key = os.urandom(16) # Create a HMAC object digest = hmac.HMAC(shared_key, hashes.SHA256(), backend=default_backend()) # enter the message has input to be hased in bytes plaintext = str.encode(hmacPlainText) digest.update(plaintext) # Finalized and produce the HMAC that will be attached to the message hash_code = digest.finalize() print("message", hmacPlainText) print("hash_code", hash_code) print("random Key:", shared_key) dataHmac = { 'hmacPlainText': hmacPlainText, 'hash_code': hash_code, 'shared_key': shared_key } # Since the form data is valid, render the success template return render_template("prim/hmac.html", dataHmac=dataHmac) # Render the form template with the error messages return render_template("index.html", errors=errors) if 'diffForm' in request.form: # The request is POST with some data, get POST data and validate it. # The form data is available in request.form dictionary. Stripping it to remove diifPlainText = request.form['diifPlainText'].strip() diffPub1 = request.form['diffPub1'].strip() diffPub2 = request.form['diffPub2'].strip() # Check if all the fields are non-empty and raise an error otherwise if not diifPlainText or not diffPub1 or not diffPub2: errors = "Please enter all the fields." if not errors: # If there are no errors, create a dictionary containing all the entered # data and pass it to the template to be displayed Xa = int(diffPub1) Xb = int(diffPub2) diifPlainText = int(diifPlainText) check_num = 0 prK = 2 a = prK #Compute Public Key for first user Ya = (a**Xa) % diifPlainText #Compute Public Key for second user Yb = (a**Xb) % diifPlainText #Compute shared key Ka = (Yb**Xa) % diifPlainText Kb = (Ya**Xb) % diifPlainText #Shared key should be same value for both users print("primitive_root: prK and prQ") print("1 shared key is", Ka) print("2 shared key is", Kb, "\n") print("1 and 2 secret shared key is", Ka, "\n") print("primitive_root", prK) print("a_pupKey", Ya) print("a_sharedKey", Ka) print("b_pupKey", Yb) print("b_sharedKey:", Kb) dataDiff = { 'prime': diifPlainText, 'primitive_root': prK, 'a_pupKey': Ya, 'a_sharedKey': Ka, 'b_pupKey': Yb, 'b_sharedKey': Kb } # Since the form data is valid, render the success template return render_template("prim/diff.html", dataDiff=dataDiff) # Render the form template with the error messages return render_template("index.html", errors=errors) if '2faForm' in request.form: # The request is POST with some data, get POST data and validate it. # The form data is available in request.form dictionary. Stripping it to remove #diifPlainText = request.form['diifPlainText'].strip() # Check if all the fields are non-empty and raise an error otherwise #if not diifPlainText or not diffPub1 or not diffPub2: #errors = "Please enter all the fields." if not errors: # If there are no errors, create a dictionary containing all the entered # data and pass it to the template to be displayed #Key is a secret key which is being randomly generated bytes key2Fa = os.urandom(20) #HOTP is an HMAC one-time password algorithm. #Length parameter is controls the length of the generated password which must be >=6 and <=8; Is using SHA1() hash function to encrypt hotp = HOTP(key2Fa, 6, SHA1(), backend=default_backend()) #Hotp.generate, generates the random 6 digit token hotp_value = hotp.generate(0) hotp.verify(hotp_value, 0) print("hashed_value: ", hotp_value) print("generated key: ", key2Fa) data2Fa = {'hotp_value': hotp_value, 'key2Fa': key2Fa} # Since the form data is valid, render the success template return render_template("prim/2fa.html", data2Fa=data2Fa) # Render the form template with the error messages return render_template("index.html", errors=errors)
def test_buffer_protocol(self, backend): key = bytearray(b"a long key with lots of entropy goes here") hotp = HOTP(key, 6, SHA1(), backend) assert hotp.generate(10) == b"559978"
""" Implementación de un validador de Tokens HOTP RFC-4226 HMAC-Based One-time Password (HOTP) """ import os import base64 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.twofactor.hotp import HOTP, InvalidToken from cryptography.hazmat.primitives.hashes import SHA1 key = b'abcdefghij' hotp = HOTP(key, 6, SHA1(), backend=default_backend()) token = input("Introduce Token: ").encode('utf-8') valido = False for counter in range(0, 100): try: hotp.verify(token, counter) valido = True except InvalidToken: pass if valido: print("Token Válido") else: print("Token Inválido")
import matplotlib.pyplot as plt import numpy as np import seaborn as sns import collections def count_frequency(arr): return collections.Counter(arr) if __name__ == '__main__': hotp_holder = [] key = os.urandom(20) hotp = HOTP(key, 8, SHA1(), backend=default_backend()) for x in range(100000): hotp_value = hotp.generate(x) hotp_str = hotp_value.decode("utf-8") n = 2 for i in range(0, len(hotp_str), n): hotp_holder.append(hotp_str[i:i + n]) # matplotlib histogram plt.hist(hotp_holder, color='blue', edgecolor='black', bins=100) # seaborn histogram sns.distplot(hotp_holder, hist=True, kde=False,
def test_invalid_hotp_length(self, backend): secret = os.urandom(16) with pytest.raises(ValueError): HOTP(secret, 4, SHA1(), backend)
def test_invalid_algorithm(self, backend): secret = os.urandom(16) with pytest.raises(UnsupportedAlgorithm): HOTP(secret, 6, MD5(), backend)
import webbrowser from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.twofactor.hotp import HOTP from cryptography.hazmat.primitives.hashes import SHA1 from cryptography.hazmat.primitives.twofactor import InvalidToken import pyqrcode key = os.urandom(16) counter = 1 issuer = 'GruPyPR' account_name = input('Your name: ') hotp = HOTP(key, 6, SHA1(), backend=default_backend()) uri = hotp.get_provisioning_uri(account_name, counter, issuer) url = pyqrcode.create(uri) print('Scan this!\n') url.svg('hotp.svg', scale=8) webbrowser.open('hotp.svg') while True: try: hotp_value = bytes(input('Two factor password: '******'utf-8') hotp.verify(hotp_value, counter) print('You are authenticated!\n') except InvalidToken: print('You shall not pass!\n') continue
def __init__(self, key, length, algorithm, time_step, backend): self._time_step = time_step self._hotp = HOTP(key, length, algorithm, backend)
def __init__(self, key, length, algorithm, time_step, backend): if not isinstance(backend, HMACBackend): raise UnsupportedInterface("Backend object does not implement HMACBackend") self._time_step = time_step self._hotp = HOTP(key, length, algorithm, backend)
def test_length_not_int(self, backend): secret = b"12345678901234567890" with pytest.raises(TypeError): HOTP(secret, b"foo", SHA1(), backend)
def test_invalid_algorithm(self, backend): secret = os.urandom(16) with pytest.raises(TypeError): HOTP(secret, 6, MD5(), backend)
def test_unenforced_invalid_kwy_length(self, backend): secret = os.urandom(10) HOTP(secret, 6, SHA1(), backend, enforce_key_length=False)