from flask import Flask, request, jsonify, render_template, abort from passlib.hash import sha512_crypt, sha256_crypt, md5_crypt import secrets, os app = Flask(__name__, static_folder='static', template_folder='templates') SALT_CHARS = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" MIN_LEN = 16 MAX_SALT_LEN = 16 ALG_MAP = { 'sha512': sha512_crypt, 'sha256': sha256_crypt } @app.route('/') def index(): return render_template('index.html') @app.route('/gensalt') def gensalt(): salt = ''.join(secrets.choice(SALT_CHARS) for _ in range(MAX_SALT_LEN)) return jsonify({'salt': salt}) @app.route('/hash', methods=['POST']) def do_hash(): data = request.get_json() or {} password = data.get('password', '') salt = data.get('salt', '') algorithm = data.get('algorithm', 'sha512') if not isinstance(password, str) or not isinstance(salt, str): abort(400, 'Invalid input') if len(password) < MIN_LEN: abort(400, f'Password must be at least {MIN_LEN} characters') if len(salt) < MIN_LEN or len(salt) > MAX_SALT_LEN: abort(400, f'Salt must be between {MIN_LEN} and {MAX_SALT_LEN} characters') hash_class = ALG_MAP.get(algorithm) if hash_class is None: abort(400, 'Unsupported algorithm') # truncate salt to MAX_SALT_LEN just in case salt_to_use = salt[:MAX_SALT_LEN] hashed = hash_class.using(salt=salt_to_use).hash(password) return jsonify({'hash': hashed}) if __name__ == '__main__': host = os.environ.get('HOST', '127.0.0.1') port = int(os.environ.get('PORT', 4444)) debug = os.environ.get('DEBUG', '1') == '1' app.run(host=host, port=port, debug=debug)