def setup_key_handler(y: str): session = Session.query.get(y) policy = PolicyModel.query.get(session.policy) if policy is None: raise Exception( "Couldn't find policy matching session information. Consider adding a policy" ) else: key_model = policy.get_key(session.timestamp) signer = key_model.signer # Retrieve pubkey and generate challenge to send in the response pubkey = SigConversion.convert_dict_strlist(signer.get_public_key()) challenge = SigConversion.convert_dict_strlist(signer.get_challenge()) # Update and Save session.u = signer.u session.d = signer.d session.s1 = signer.s1 session.s2 = signer.s2 session.save_to_db() data = {'public_key': pubkey, 'challenge': challenge} return data
def setup_key_handler(timestamp: int, number: int, policy: int): """ :param timestamp: (int) Timestamp of when the first knowledge proofs should be available on the ledger :param number: (int) Number of requested credentials :param policy: (int) The policy that a user is requesting credentials for. :return: (dict) """ resp = [] policy = PolicyModel.query.get(policy) sigvars = UserModel.query.get(current_user.id).get_sigvar( timestamp, policy) if not policy: raise Exception("Couldn't find policy") if sigvars: raise Exception("Key already exists") for i in range(0, number): # Retrieve key for particular timestamp and policy combination time = timestamp + (i * policy.publication_interval * 60 ) # publication_interval is in minutes # If no KeyModel exists for a given policy at a set time we create one key_model = policy.get_key(time) if key_model is None: signer = SignerBlindSignature(IntegerGroupQ()) new = KeyModel(time, policy, signer) policy.keys.append(new) new.save_to_db() policy.save_to_db() else: signer = key_model.signer # Retrieve pubkey and generate challenge to send in the response pubkey = SigConversion.convert_dict_strlist(signer.get_public_key()) challenge = SigConversion.convert_dict_strlist(signer.get_challenge()) # Save sigvars = SigVarsModel(timestamp=time, policy=policy.policy, u=signer.u, d=signer.d, s1=signer.s1, s2=signer.s2, user_id=current_user.id) sigvars.save_to_db() data = { 'timestamp': time, 'public_key': pubkey, 'challenge': challenge } resp.append(data) return resp
def verify_blind(self, cp, blind_signature): # Convert to modular integer dictionary sig = SigConversion.convert_dict_modint(json.loads(blind_signature)) cp_pubk = get_cp_pubkey(cp, self.timestamp, self.policy) verifier = BlindSignatureVerifier(cp_pubk) message = Conversion.OS2IP(self.pubk) return verifier.verify(sig, message)
def gen_proof_handler(e: dict): key = KeyModel.query.get((current_user.timestamp, current_user.policy)) signer = key.signer signer.d = current_user.d signer.u = current_user.u signer.s1 = current_user.s1 signer.s2 = current_user.s2 # Do the appropriate conversions so that we can serialize e = SigConversion.convert_dict_modint(e) proofs = SigConversion.convert_dict_strlist(signer.get_proofs(e)) hash_tmp = SHA256Hash().new(json.dumps(proofs).encode()) hash_proof = Conversion.OS2IP(hash_tmp.digest()) resp = {'proof': proofs, 'hash': hash_proof} return resp
def __init__(self, timestamp, policy, u, d, s1, s2, user_id): """ :param timestamp: POSIX timestamp :param policy: integer referencing the policy chosen :param u: Element.Integer mod q :param d: Element.Integer mod q :param s1: Element.Integer mod q :param s2: Element.Integer mod q :param user_id: integer representing the user in the CP's system database """ self.timestamp = timestamp self.policy = policy self.user_id = user_id self.u_ = SigConversion.modint2strlist(u) self.d_ = SigConversion.modint2strlist(d) self.s1_ = SigConversion.modint2strlist(s1) self.s2_ = SigConversion.modint2strlist(s2)
def __encode_dict__(self, dict_): tmp = {**dict_} for key in tmp: if tmp.get(key) is not None: tmp[key] = SigConversion.modint2strlist(tmp.get(key)) else: tmp[key] = 'null' return tmp
def user_response(): data = json.loads(request.json) params = {'policy': data.get('policy'), 'timestamp': data.get('timestamp')} # Find y in database user = User.query.get(data.get('y')) if user is None: return jsonify({'message': 'Could not find y'}), 500 # TODO: Ideally the keys should have been distributed by some other means res = requests.get('http://%s:5000/pubkey' % ap_host, params=params) if res.status_code == 200: key = res.json() key = SigConversion.convert_dict_modint(key) sig = json.loads(data.get('sig')) sig = SigConversion.convert_dict_modint(sig) if verify_sig(key, sig, data.get('y')): return jsonify({'message': 'Success'}), 200 else: return jsonify({'message': 'Could not verify signature'}), 500
def get_cp_pubkey(cp: int, timestamp: int, policy: int): """ Gets the public key from the ledger for a given timestamp and policy. :param cp: The ID of the CP on the ledger. :param timestamp: The timestamp at which the proofs are valid. :param policy: The CP policy the proofs are associated with. :return: """ block = get_block(cp, timestamp, policy) key_json = block.get('key') key_str = json.loads(key_json.get('key')) key = SigConversion.convert_dict_modint(key_str) return key
def gen_proofs_handler(policy, es): # Get policy from database and setup list policy = PolicyModel.query.get(policy) resp = list() # Iterate through the challenge responses received for x in es: # Retrieve KeyModel object timestamp = x.get('timestamp') key = policy.get_key(timestamp) # Retrieve SigVarsModel object so we can populate the signer with u and d sigvars = current_user.get_sigvar(timestamp, policy.policy) # Get policy pool pool = policy.get_pool(timestamp) if key and sigvars: signer = key.signer signer.d = sigvars.d signer.u = sigvars.u signer.s1 = sigvars.s1 signer.s2 = sigvars.s2 # Do the appropriate conversions so that we can serialize x['e'] = SigConversion.strlist2modint(x.get('e')) proofs = SigConversion.convert_dict_strlist(signer.get_proofs(x)) hash_tmp = SHA256Hash().new(json.dumps(proofs).encode()) hash_proof = Conversion.OS2IP(hash_tmp.digest()) # Add proofs to the pool pool.append_to_pool(proofs) resp.append({'timestamp': timestamp, 'hash_proof': hash_proof}) resp = {'policy': policy.policy, 'hash_proofs': resp} return resp
def handle_challenge_util(signer_type: str, signer_id: int, resp: dict, policy: int, message: int = None): """ Utility function that takes care of type conversions and ultimately calls the signing function :param signer_type: Whether a blind signature is being requested from a CP or an AP. :param signer_id: The CP\\AP's participant ID :param resp: The CP\\AP response to the challenge request. :param policy: The policy for which the signature needs to be generated. :param message: The message that the blind signature needs to be generated on. :return: e: The challenge response that is used by the CP/AP's to generate the proofs. """ pubk = SigConversion.convert_dict_modint(resp.get('public_key')) challenge = SigConversion.convert_dict_modint(resp.get('challenge')) timestamp = resp.get('timestamp') # Generate signer and keymodel signer = UserBlindSignature(pubk) key_model = KeyModel(provider_type=signer_type, p_id=signer_id, policy=policy, signer=signer, interval=timestamp) if message is None: message = Conversion.OS2IP(key_model.public_key) e = SigConversion.convert_dict_strlist( signer.challenge_response(challenge, message)) e['timestamp'] = timestamp key_model.signer = signer key_model.save_to_db() return e
def decode(self, jsn): obj = json.loads(jsn) db = obj.pop('db') if obj.get('db') is not None else None if isinstance(self, SignerBlindSignature): new = SignerBlindSignature(IntegerGroupQ()) elif isinstance(self, UserBlindSignature): new = UserBlindSignature() else: raise Exception("Unexpected argument") for key in obj: if obj[key] == 'null': attr_val = None else: attr_val = SigConversion.strlist2modint(obj[key]) setattr(new, key, attr_val) if db: for key in db: db[key] = SigConversion.strlist2modint(db[key]) setattr(new, 'db', db) new.group = IntegerGroupQ() new.group.setparam(p=new.p, q=new.q) return new
def get_key(): """ Allows services to retrieve the public key associated with a specific timestamp and policy. :return: """ timestamp = int(request.args.get('timestamp')) policy = int(request.args.get('policy')) key = KeyModel.query.get((timestamp, policy)) if key is None: return jsonify({'message': 'No key matching those parameters'}), 400 else: pubkey = key.get_public_key() pubkey = SigConversion.convert_dict_strlist(pubkey) resp = json.dumps(pubkey) return resp, 200
def publish_pool(policy: int, timestamp: int) -> bool: """ :param policy: :param timestamp: :return: """ pol = PolicyModel.query.get(policy) pool = pol.get_pool(timestamp) if pol is not None else None key = pol.get_key(timestamp) if pol is not None else None res = requests.get("http://cp_rest_api:3000/api/ProofBlock") cpid = 2000 if (res.status_code == 200) and (key is not None) and (pol is not None): data = { "$class": "digid.ProofBlock", "assetId": len(res.json()), "owner": "resource:digid.CertificationProvider#" + str(cpid), "timestamp": timestamp, "lifetime": pol.lifetime, "key": { "$class": "digid.PublicKey", "key": str(json.dumps(SigConversion.convert_dict_strlist(key.get_public_key()))), "policy": policy }, "proofHash": str(pool.get_pool_hash()), "proofs": str(json.dumps(pool.pool)) } res = requests.post("http://cp_rest_api:3000/api/ProofBlock", json=data) if res.status_code == 200: return True db.session.delete(pool) db.session.commit() else: return False else: return False
def publish_pool(policy: int, timestamp: int) -> bool: """ :param policy: :param timestamp: :return: """ cp_rest = current_app.config['CP_REST_URI'] cpid = current_app.config['CP_DLT_ID'] pol = PolicyModel.query.get(policy) pool = pol.get_pool(timestamp) if pol is not None else None key = pol.get_key(timestamp) if pol is not None else None res = requests.get(cp_rest + "/api/ProofBlock") if (res.status_code == 200) and (key is not None) and (pol is not None): data = { "$class": "digid.ProofBlock", "assetId": len(res.json()), "owner": "resource:digid.CertificationProvider#" + cpid, "timestamp": timestamp, "lifetime": pol.lifetime, "key": { "$class": "digid.PublicKey", "key": str(json.dumps(SigConversion.convert_dict_strlist(key.get_public_key()))), "policy": policy }, "proofHash": str(pool.get_pool_hash()), "proofs": str(json.dumps(pool.pool)) } res = requests.post(cp_rest + "/api/ProofBlock", json=data) if res.status_code == 200: return True else: return False else: return False
def access_service_post(): # Get nonce from service res = requests.get('http://{}/request'.format( current_app.config['service_host'])).json() service_y = res.get('y') # Setup parameters that are sent to the AP params = { 'cp': int(request.form.get('cp')), 'timestamp': int(dateutil.parser.parse(request.form.get('timestamp')).timestamp()), 'policy': int(request.form.get('policy')) } # Request-certs CP_i res = requests.get('http://{}/request_certs'.format( current_app.config['ap_host']), params=params) if res.status_code == 500: flash("Error when requesting certs: " + res.json().get('message'), "access_service_error") return render_template('service_authenticate.html') # Get data from response and find corresponding keymodel data = res.json() key_model = KeyModel.query.filter_by( provider_type_=1, p_id_=params.get('cp'), policy_=params.get('policy'), interval_timestamp_=params.get('timestamp')).first() # Validate that block has not been altered try: validate_block(data) except Exception as e: flash("Error when validating block: " + str(e), "access_service_error") return render_template('service_authenticate.html') pubk = {'pubk': Conversion.OS2IP(key_model.public_key)} # Get the challenge from the AP in order to prove that the user owns a specific keypair res = requests.get('http://{}/prove_owner'.format( current_app.config['ap_host']), params=pubk) y = res.json().get('y') # Prove the user owns the private key corresponding to a set of proofs in the block # Proof consists of the signature of the private key on the nonce y and the blind signature on the public key try: (proof, proof_owner) = prove_owner(y, data, key_model.proof_hash) blind_signature = key_model.generate_blind_signature( proof.get('proofs')) proof_resp = json.dumps({ 'y': y, 'signature': proof_owner[1], 'blind_signature': json.dumps(SigConversion.convert_dict_strlist(blind_signature)) }) # Post the proofs res = requests.post('http://{}/prove_owner'.format( current_app.config['ap_host']), json=proof_resp, params=params) # Receive access token for AP access_info = res.json() err = access_info headers = {'Authorization': "Bearer " + access_info.get('access')} # Request challenge from AP to issue blind signature challenge = requests.get('http://{}/init_sig'.format( current_app.config['ap_host']), headers=headers).json() # Handle challenge try: challenge['timestamp'] = params.get('timestamp') e = json.dumps( handle_challenge_ap(challenge, params.get('policy'), service_y)) # Send Response proof_response = requests.post('http://{}/generate_proof'.format( current_app.config['ap_host']), json=e, headers=headers) proofs = proof_response.json() # Validate Response try: validate_proof(proofs) except Exception as e: flash("Error when validating proofs: " + str(e), "access_service_error") return render_template('service_authenticate.html') # Get AP Keymodel ap_key_model = KeyModel.query.filter_by(p_id_=2000, provider_type_=2).first() # Build signature blind_signature = ap_key_model.generate_blind_signature( proofs.get('proof')) # Send signature on service_y to service resp_service = { 'y': service_y, 'sig': json.dumps( SigConversion.convert_dict_strlist(blind_signature)), 'policy': params.get('policy'), 'timestamp': params.get('timestamp') } # Get access to service res = requests.post('http://{}/response'.format( current_app.config['service_host']), json=json.dumps(resp_service)) if res.status_code == 200: return render_template('thanks.html') else: message = res.json().get('message') flash("Response code was not 200: " + message, "access_service_error") return render_template('service_authenticate.html') except Exception as e: flash("There was an error when handling the challenge: " + str(e), "access_service_error") return render_template('service_authenticate.html') except Exception as e: flash( "There was an error in the ownership proving stage. The blind signature likely failed to verify: " + str(e), "access_service_error") return render_template('service_authenticate.html')
def s1(self, s1): self.s1_ = SigConversion.modint2strlist(s1)
def s2(self, s2): self.s2_ = SigConversion.modint2strlist(s2)
def u(self): return SigConversion.strlist2modint(self.u_)
def d(self): return SigConversion.strlist2modint(self.d_)
def s1(self): return SigConversion.strlist2modint(self.s1_)
def d(self, d): self.d_ = SigConversion.modint2strlist(d)
def s2(self): return SigConversion.strlist2modint(self.s2_)
def generate_blind_signature(self, proof): signer = self.signer proof = SigConversion.convert_dict_modint(proof) return signer.gen_signature(proof)
def u(self, u): self.u_ = SigConversion.modint2strlist(u)