Cryptographically_Enforced_Access_Control
Desing and implement a Cryptographically Enforced Access Control using CP-ABE
Definition of Data Model
The data model comprises entities: patients, doctors, hospitals, insurance agencies, employers, and health clubs. Additionally, a trusted authority exists, representing an entity trusted by everyone but not an actual entity. For instance, a reputable hospital or a government agency can become a trusted authority.
Entities and Data Involved
- Authority’s public key $PK$: Accessible to all.
- Authority’s master key $MK$: Known only to the authority.
- List of all parties and their attributes: Managed by the authority.
- Each party’s secret key $SK$: Distributed by the authority and known only to the party.
- Encrypted health records: Stored in the trusted authority’s server, available for download by all, but decrypting them enforces specific policies.
Requirements
- Encrypt patients' records.
- Allow patients access to their data.
- Enable patients to selectively share records with doctors, insurance agencies, and employers.
- Permit hospitals to insert new records during patient visits.
- Allow health clubs to insert records for their members.
Access Control Protocol Description
CP-ABE (Ciphertext-Policy Attribute-Based Encryption)
Our implementation is based on the CP-ABE protocol defined in BSW07 \cite{BSW}. CP-ABE associates each encrypted file with a policy tree dictating access. Entities have attribute lists.
CP-ABE Protocol Procedure
- The trusted authority runs the Setup algorithm, publishing $PK$, and retains $MK$.
from charm.toolbox.pairinggroup import PairingGroup
from charm.schemes.abenc.abenc_bsw07 import CPabe_BSW07
class KeyDistributor:
global master_public_key, master_key
# init method or constructor
def __init__(self, cpabe):
self.cpabe = cpabe
self.master_public_key, self.master_key = cpabe.setup()
def create_secret_key(self, attributes: list):
return self.cpabe.keygen(self.master_public_key, self.master_key, attributes)
- The authority maintains a list of involved parties and their attributes, running KeyGen for all parties and distributing secret keys accordingly.
- Any entity with $PK$ and a specified access tree can encrypt a document.
def insert(self, data:HealthData, access_policy, password_manager, entities: list[Entity]):
max_attempts = 3 # Adjust the number of maximum attempts as needed
attempts = 0
while attempts < max_attempts:
patient_password = input("Patient_{} password: ".format(self.entity_id))
check = password_manager.check_password(self, patient_password)
access_policy = f"({self.entity_type}{self.entity_id})"
if check:
for entity in entities:
if entity.entity_type == "Hospital":
self.addRights(entity)
print(f"Hospital {entity.name} {entity.location} have write rights on {self.entity_type}{self.entity_id} records")
access_policy = f'({access_policy} OR ({entity.entity_type}{entity.entity_id}))'
#print(access_policy)
cipher_text = self.cpabe.encrypt(self.master_public_key, data.msg, access_policy)
self.records.append(cipher_text)
break
else:
attempts += 1
if attempts < max_attempts:
print("Incorrect password. Please try again.")
if attempts == max_attempts:
print("Maximum password attempts reached. Access denied.")
- Entities whose attributes match the access tree can run Decrypt to access the plaintext document.
def read(self, record):
msg = self.cpabe.decrypt(self.master_public_key, self.secret_key, record)
print(f"Patient {self.name} {self.surname} read {msg}")
Design Choice
In our Personal Health Record (PHR) system design, we favor attribute-based encryption (ABE) for granular access control. For example, Patient A’s doctor shouldn’t access Patient B’s data if they aren’t treated by the same doctor. This calls for avoiding role-based access control or the access matrix model. Within ABE, we select ciphertext-policy (CP) over key-policy due to the latter’s impractical public key enumeration. However, CP-ABE introduces a single point of failure due to the trusted authority.
We maintain a list of parties: patients, doctors, hospitals, insurance agencies, employers, and health clubs. Each entity has specific attributes for precise access control, including UIDs and doctors' specialties (e.g., cardiology
, nephrology
). Including all UIDs is crucial for precise access rights control.
Authentication and Insertion
To facilitate insertion, two solutions using Access Control Lists (ACLs) are proposed.
First Solution: Static Password
- Entities provide a static “uploading password” upon creation.
- Entities verify passwords with the authority for insertion rights.
- However, this method poses security risks and heavily relies on the central authority.
Second Solution: ABE Access Policy as ACL
- The authority generates an ACL file encrypted with a policy tree allowing only the patient to read.
- Patients re-encrypt the file with additional attributes for hospitals/health clubs.
def addRights(self, entity):
psw = self.group.random(GT)
old_policy = self.guestWriteAccess["policy"]
# print(f"{old_policy = }")
policy = f'({old_policy} OR ({entity.entity_type}{entity.entity_id}))'
# print(policy)
cipher_psw = self.cpabe.encrypt(self.master_public_key, psw, policy)
# print(f"{cipher_psw = }")
self.guestWriteAccess['psw'] = cipher_psw
self.guestWriteAccess['policy'] = policy
return
- Entities retrieve passwords from the ACL file for file insertion, and the authority modifies passwords when necessary.
def writePatient(self, patient, data:HealthData, password_manager):
max_attempts = 3 # Adjust the number of maximum attempts as needed
attempts = 0
if data.type != "Health":
print("You are not allowed to insert this type of data")
#raise Exception("You are not allowed to insert this type of data")
while attempts < max_attempts:
health_password = input("Hospital_{} password: ".format(self.entity_id))
check = password_manager.check_password(self, health_password)
if check:
toDec = patient.get_crypted_psw()
decrypted = self.cpabe.decrypt(self.master_public_key, self.secret_key, toDec)
right_check = patient.right_check(decrypted)
if right_check:
access_policy = f'(({patient.entity_type}{patient.entity_id}))'
# msg = self.group.random(GT)
cipher_text = self.cpabe.encrypt(self.master_public_key, data.msg, access_policy)
patient.records.append(cipher_text)
break
else:
print("You are not allowed to write for this user")
break
else:
attempts += 1
if attempts < max_attempts:
print("Incorrect password. Please try again (Max 3 attempts)")
if attempts == max_attempts:
print("Maximum password attempts reached. Access denied.")
return
The second solution, built atop the reading access control system, offers more security but assumes parties' non-collusion and introduces occasional password entries for hospitals.
Implementation Details
- Operating System: Linux
- Language: Python v3.10.12
Our implementation utilizes the charm.schemes.abenc.abenc_bsw07
module in the Charm-Crypto v0.50 Python package. We chose a supersingular elliptic curve with a $512$-bit base field as the bilinear group. Each entity, when creating a patient’s health record, determines a policy tree for encryption, enabling selective access. For insertion authentication, passwords are generated via bcrypt
hashing.
Serialization and deserialization complexities within the Charm-Crypto package hinder the implementation’s security. A custom serializer/deserializer is necessary for secure information storage.
Access Policy Definition
The mathematical definition of the access policy (policy tree $\mathcal T$) is detailed in Section 2.1, representing various scenarios for reading and inserting files.
Access Policy Scenarios for Reading Files
- Patient A’s record after seeing Doctor B: A.patient_id or B.doctor_id
- Patient A’s record after seeing Doctor B and agreeing to share it with all neurologists: A.patient_id or B.doctor_id or specialization=neurology
- Patient A’s record created by Hospital B after visiting the hospital: A.patient_id or B.hospital_id
- Patient A’s record from Hospital B shared with Employer C and Insurance Agency D for insurance claim: A.patient_id or B.hospital_id or C.employer_id or D.insurance_id
Access Policy Scenarios for Inserting Files
- When Patient A is born: A.patient_id
- When Patient A visits Doctor B and B wants to add new files to A’s record: A.patient_id or B.doctor_id
- When Patient A visits Hospital B: A.patient_id or B.hospital_id
- When Patient A joins Health Club B: A.patient_id or B.club_id
- When Patient A is sent to hospital B while exercising as a member of Health Club C: A.patient_id or B.hospital_id or C.club_id
Conclusion
Acknowledging flaws within our code, the demonstration serves its purpose: showcasing a practical implementation fulfilling requirements and exemplifying CP-ABE’s usage in our problem domain.