#!/usr/bin/env python3 from flask import Flask, Response, request, send_from_directory from ecdsa import SigningKey, VerifyingKey, BadSignatureError from base64 import b64decode, b64encode from hashlib import sha256 from random import randrange import os import time ... if not FLAG: import sys sys.exit(1) app_dir = os.path.abspath(os.path.dirname(__file__)) admin_priv = SigningKey.from_pem(open('{}/keys/admin_priv.pem'.format(app_dir)).read(), hashfunc=sha256) admin_pub = admin_priv.verifying_key user_keys = dict() for u in ['john', 'kate', 'silberman']: user_keys[u] = VerifyingKey.from_pem(open('{}/keys/{}_pub.pem'.format(app_dir, u)).read(), hashfunc=sha256) K_COEFF = [randrange(0, admin_pub.curve.order) for _ in range(5)] chal_ts = None chal_sig = None chal_k = randrange(0, admin_pub.curve.order) app = Flask(__name__, static_folder='{}/static'.format(app_dir)) ... def timestamp(): t = int(time.time()) return t - t % 30 def sigdecode(sig, order): bl = (order.bit_length() + 7) // 8 sig = b64decode(sig.encode('utf-8')) assert len(sig) == 2 * bl r = int.from_bytes(sig[:bl], 'big') s = int.from_bytes(sig[bl:], 'big') return r % order, s % order def sigencode(r, s, order): bl = (order.bit_length() + 7) // 8 r = (r % order).to_bytes(bl, 'big') s = (s % order).to_bytes(bl, 'big') return b64encode(r + s).decode('utf-8') def sigcheck(pubkey, sig): try: if pubkey.verify(sig, str(chal_ts).encode('utf-8') + b'login', hashfunc=sha256, sigdecode=sigdecode): return True except BadSignatureError: pass return False @app.route('/static/', methods=['GET']) def serve_static(path): return send_from_directory('static', path) @app.route('/', methods=['GET']) def index(): return app.send_static_file('index.html') @app.route('/login', methods=['POST']) def login(): data = request.get_json() if 'user' not in data or 'sig' not in data: return Response("Invalid request format", status=400) user = data['user'] if user not in user_keys: return { 'invalid': 'Invalid username' } sig = data['sig'] if sigcheck(user_keys[user], sig) or sigcheck(admin_pub, sig): return { 'valid': '{}'.format(FLAG) } return { 'invalid': 'Invalid private key' } @app.route('/challenge', methods=['GET']) def challenge(): global chal_ts, chal_sig, chal_k ts = timestamp() if ts != chal_ts: chal_ts = ts chal_k = sum(a * chal_k ** i for i, a in enumerate(K_COEFF)) % admin_pub.curve.order chal_sig = admin_priv.sign(str(chal_ts).encode('utf-8') + b'challenge', hashfunc=sha256, sigencode=sigencode, k=chal_k) return { 'challenge': str(chal_ts), 'sig': chal_sig } if __name__ == '__main__': ...