From 428122f04ea80fb4acb307328577e0d91c12fef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Henrique?= Date: Tue, 12 Sep 2023 11:21:31 -0300 Subject: [PATCH] finalizando trab 2 --- .gitignore | 2 + trabalho2/gerador.py | 132 ++++++++++++++++++---------------------- trabalho2/localtoken.py | 30 +++++++-- trabalho2/server.py | 93 +++++++++++++++++++++------- 4 files changed, 160 insertions(+), 97 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0b54e83 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.dat +__pycache__ diff --git a/trabalho2/gerador.py b/trabalho2/gerador.py index 4853acf..fd6f07a 100644 --- a/trabalho2/gerador.py +++ b/trabalho2/gerador.py @@ -1,88 +1,76 @@ from hashlib import sha256 import localtoken - -''' -Gerador: - Primeira vez criar - um usuário - uma senha semente (Senha igual a registrada no servidor, senha principal) - Um salt (o mesmo do Aplicativo) - uma senha local (Senha para acesso ao gerador de senhas somente) - Próximas vezes - Digitar usuário e a senha local, se correto continua. - Quando requisitado gera uma senha(Token). - (algoritmo gerador de senhas) - A senha (Token) deve ser gerada a partir da hash da senha semente do usuário (diferente da senha do usuário). - O aluno deve propor uma variante do algoritmo OTP de Lamport, visto em aula. - Este algoritmo deve levar em consideração o tempo (data hora minuto). - As senhas devem ter validade de no máximo um minuto e só podem ser usadas uma única vez.(Fazer uma lista de senhas para ser usada no minuto. Ex.lista com 5 senhas para o minuto solicitado) - somente gerar lista de senhas para o minuto solicitado. - -Servidor: - Quando acessado usa o mesmo algoritmo gerador de senhas anterior. Mas em instância separada. - A lista de senha gerada será a mesma nas duas partes, apesar de estarem em aplicativos separados e sem comunicação. - Verifica o usuário e se senha digitada esta na lista gerada e não foi usada e nem invalidada. - nesta caso apresenta “Chave válida”. - Atenção: - As senhas devem ter validade de no máximo um minuto e só podem ser usadas uma única vez. - Senhas são geradas a partir de outras senhas, e se for usada uma chave todas as chaves geradas pela mesma devem ser invalidadas. - Se o cliente digitar uma senha válida o servidor aceita, caso contrario retorna mensagem de erro. - -''' - -USER = '' -LOCAL_PASSWORD = '' -SEED_PASSWORD = '' -SALT = '' - -def check_setup(): - try: - with open('gerador.dat', 'r', newline='') as setup: - lines = setup.readlines() - if len(lines) != 4: - return False - - USER = lines[0] - LOCAL_PASSWORD = lines[1] - SEED_PASSWORD = lines[2] - SALT = lines[3] - return True - except: - init_setup() - - return True +import os +import time def init_setup(): - with open('gerador.dat', 'w', newline='') as setup: + with open('gerador.dat', 'a', newline='') as setup: user = input('Digite o usuário: ') local_password = sha256(input('Digite a senha local: ').encode('utf-8')).hexdigest() seed_password = sha256(input('Digite a senha semente: ').encode('utf-8')).hexdigest() - salt = sha256(input('Digite o salt: ').encode('utf-8')).hexdigest() - setup.write(user + '\n') - setup.write(local_password + '\n') - setup.write(seed_password + '\n') - setup.write(salt) + salt = input('Digite o salt: ') + salted_password = localtoken.get_salted_password(seed_password, salt) -def check_password(): - local_password = sha256(input('Digite a senha local: ').encode('utf-8')).hexdigest() - if local_password == LOCAL_PASSWORD: - return True - else: - return False + line = f'{user},{local_password},{salted_password}\n' + setup.write(line) + + print(f'Usuário [{user}] registrado com sucesso!') def generate_token(): - token = localtoken.generate_token(SEED_PASSWORD, SALT) - print('Token gerado: ' + token[:8]) + user = input('Digite o usuário: ') + local_password = sha256(input('Digite a senha local: ').encode('utf-8')).hexdigest() + salted_password = '' + with open('gerador.dat', 'r', newline='') as setup: + for line in setup: + line = line.replace('\n', '') -def main(): - if check_setup(): - if check_password(): - input('Pressione alguma tecla para gerar uma senha...') - generate_token() + if line.split(',')[0] == user and line.split(',')[1] == local_password: + salted_password = line.split(',')[2] + break else: print('Usuário ou senha incorretos!') - else: - print('Erro ao verificar setup!') + return + + loop_token(user, salted_password) + +def loop_token(user, salted_password): + while True: + print(f'Gerando token para [{user}]...') + tokens = [localtoken.generate_token(salted_password)] + for i in range(4): + tokens.append(localtoken.generate_token(tokens[-1])) + + for token in tokens: + print(token[:8]) + + # sleep until next minute + time.sleep(60 - time.time() % 60 + 1) + + # clear console + os.system('cls' if os.name == 'nt' else 'clear') + +def main(): + while True: + print('Selecione uma opção:') + print('1 - Registrar usuário') + print('2 - Gerar token') + print('0 - Sair') + option = input('Opção: ') + + if option == '1': + init_setup() + elif option == '2': + generate_token() + elif option == '0': + exit() + +def exit(): + print('Saindo...') + quit() + if __name__ == '__main__': + if not os.path.exists('gerador.dat'): + open('gerador.dat', 'w').close() + main() \ No newline at end of file diff --git a/trabalho2/localtoken.py b/trabalho2/localtoken.py index f82861e..dfda382 100644 --- a/trabalho2/localtoken.py +++ b/trabalho2/localtoken.py @@ -1,7 +1,29 @@ from hashlib import sha256 import time -# password = hashed password -def generate_token(password, salt): - time = time.strftime('%d%m%Y%H%M') - token = sha256((password + salt + time).encode('utf-8')).hexdigest() \ No newline at end of file +# token = hashed password + hashed salt +def generate_token(token): + time = get_timestamp() + token = sha256((token + time).encode('utf-8')).hexdigest() + + return token + +# password = hashed seed password +# salt = hashed salt +def get_salted_password(password, salt): + return sha256((password + salt).encode('utf-8')).hexdigest() + +def validate_token(salted_password, token, n=5): + time = get_timestamp() + tokens = [] + for i in range(n): + last = tokens[-1] if len(tokens) > 0 else salted_password + tokens.append(generate_token(last)) + + if token[:8] == tokens[-1][:8]: + return True, i + + return False, -1 + +def get_timestamp(): + return time.strftime('%d%m%Y%H%M') \ No newline at end of file diff --git a/trabalho2/server.py b/trabalho2/server.py index f398fd6..586f72f 100644 --- a/trabalho2/server.py +++ b/trabalho2/server.py @@ -1,34 +1,85 @@ from hashlib import sha256 +import string import localtoken +import random +import os -''' -Quando acessado usa o mesmo algoritmo gerador de senhas anterior. Mas em instância separada. - A lista de senha gerada será a mesma nas duas partes, apesar de estarem em aplicativos separados e sem comunicação. - Verifica o usuário e se senha digitada esta na lista gerada e não foi usada e nem invalidada. - nesta caso apresenta “Chave válida”. - Atenção: - As senhas devem ter validade de no máximo um minuto e só podem ser usadas uma única vez. - Senhas são geradas a partir de outras senhas, e se for usada uma chave todas as chaves geradas pela mesma devem ser invalidadas. -Se o cliente digitar uma senha válida o servidor aceita, caso contrario retorna mensagem de erro. +def register_user(): + user = input('Digite o usuário: ') + seed_password = sha256(input('Digite a senha: ').encode('utf-8')).hexdigest() + salt = ''.join(random.choice(string.ascii_letters) for i in range(16)) + salt = sha256(salt.encode('utf-8')).hexdigest() -''' + line = f'{user},{seed_password},{salt}\n' + with open('server.dat', 'a', newline='') as setup: + setup.write(line) -SALT = '' -PASSWORD = '' + print(f'Usuário registrado com sucesso! Salt: [{salt}]') + +def validate_token(): + user = input('Digite o usuário: ') + token = input('Digite o token: ') + password = '' + salt = '' + with open('server.dat', 'r', newline='') as setup: + for line in setup: + if len(line) == 0: + continue + line = line.replace('\n', '') + + if line.split(',')[0] == user: + password = line.split(',')[1] + salt = line.split(',')[2] + break + else: + print('Usuário incorreto!') + return + + used_index = -1 + used_timestamp = '' + with open('used_tokens.dat', 'r', newline='') as used_tokens: + for used_token in reversed(list(used_tokens)): + used_token = used_token.replace('\n', '') + if used_token.split(',')[0] == user: + used_index = int(used_token.split(',')[1]) + used_timestamp = used_token.split(',')[2] + break + + password = localtoken.get_salted_password(password, salt) + + valid, index = localtoken.validate_token(password, token) + if valid: + if used_index <= index and used_timestamp == localtoken.get_timestamp(): + print('Chave inválida (invalidada)!') + else: + print('Chave válida!') + with open('used_tokens.dat', 'a', newline='') as used_tokens: + line = f'{user},{index},{localtoken.get_timestamp()}' + used_tokens.write(line + '\n') + else: + print('Chave inválida!') def main(): - print('Servidor!') - SALT = sha256(input('Digite o salt: ').encode('utf-8')).hexdigest() - PASSWORD = sha256(input('Digite a senha: ').encode('utf-8')).hexdigest() - while True: - token = input('Digite o token: ') - if localtoken.generate_token(PASSWORD, SALT)[:8] == token[:8]: - print('Chave válida!') - else: - print('Chave inválida!') + print('Selecione uma opção:') + print('1 - Registrar usuário') + print('2 - Validar token') + print('0 - Sair') + option = input('Digite a opção: ') + if option == '1': + register_user() + elif option == '2': + validate_token() + elif option == '0': + exit() if __name__ == '__main__': + if not os.path.exists('server.dat'): + open('server.dat', 'w').close() + + if not os.path.exists('used_tokens.dat'): + open('used_tokens.dat', 'w').close() + main() \ No newline at end of file