You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

86 lines
2.6 KiB
Python

1 year ago
#!/usr/bin/env python3
6 months ago
import argparse
import datetime
import hashlib
import os
1 year ago
import random
import secrets
6 months ago
import string
6 months ago
import sys
1 year ago
6 months ago
DEFAULT_SECRET_PATH = 'secret'
1 year ago
def create_secret():
6 months ago
"""returns 128 bytes of randomness as hex bytes"""
1 year ago
return secrets.token_hex(128)
def generate_password():
6 months ago
"""returns a random 24 char password"""
alphabet = string.ascii_letters + string.digits + '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}'
1 year ago
return ''.join(random.choice(alphabet) for i in range(24))
def month_timestamp():
6 months ago
"""returns the unix timestamp of the first of the current month"""
1 year ago
today = datetime.datetime.now()
start_of_month = datetime.datetime(today.year, today.month, 1, 0, 0, 0, 0)
return int(start_of_month.timestamp())
def generate_seed(secret):
6 months ago
"""returns an rng seed based on the current date"""
hash_object = hashlib.sha256()
hash_object.update(bytes.fromhex(secret))
hash_object.update(str(month_timestamp()).encode())
return hash_object.digest()
1 year ago
6 months ago
def generate_secret(secret_path):
6 months ago
"""generates a secret and writes it as a file"""
6 months ago
print('Generating a new secret... ', end='')
secret = create_secret()
6 months ago
with open(secret_path, 'w') as file:
file.write(secret)
6 months ago
print('done. Send this to the other party:')
print(secret)
1 year ago
def main():
6 months ago
parser = argparse.ArgumentParser(
prog='Remote Admin Password Solution',
description='Generate rotating passwords based on a shared secret'
)
parser.add_argument('--secret', action='store', help='path to secret file')
1 year ago
parser.add_argument('--new-secret', action='store_true', help='generate a new secret')
args = parser.parse_args()
6 months ago
if args.secret:
secret_path = os.path.realpath(args.secret)
else:
secret_path = os.path.realpath(DEFAULT_SECRET_PATH)
1 year ago
secret = ''
6 months ago
if args.new_secret:
if os.path.isfile(secret_path):
choice = ''
while choice.lower() != 'y' and choice.lower() != 'n':
choice = input(f'Secret {secret_path} exists! Overwrite? [y/n]: ')
if choice.lower() == 'y':
generate_secret(secret_path)
else:
generate_secret(secret_path)
try:
secret = open(secret_path, 'r').read().strip()
except FileNotFoundError:
print(f'ERROR: Secret file {secret_path} could not be found.')
sys.exit(1)
6 months ago
6 months ago
print(f'Secret {secret_path} loaded.')
1 year ago
random.seed(generate_seed(secret))
1 year ago
print('The password of the month is:')
print(generate_password())
if __name__ == '__main__':
main()