proj
This commit is contained in:
		
							parent
							
								
									b34530706e
								
							
						
					
					
						commit
						a6e0798ef4
					
				
					 2 changed files with 105 additions and 26 deletions
				
			
		|  | @ -1,4 +1,3 @@ | |||
| 
 | ||||
| import os | ||||
| import json | ||||
| import base64 | ||||
|  | @ -20,34 +19,33 @@ except ImportError: | |||
| STATE_FILE = "server_state.json" | ||||
| INPUT_DIR = "inputdata" | ||||
| 
 | ||||
| 
 | ||||
| def ensure_dirs(): | ||||
|     if not os.path.exists(INPUT_DIR): | ||||
|         os.makedirs(INPUT_DIR) | ||||
| 
 | ||||
| 
 | ||||
| def load_state(): | ||||
|     if not os.path.exists(STATE_FILE): | ||||
|         return { | ||||
|             "server": {}, | ||||
|             "doctors": {}, | ||||
|             "reports": [], | ||||
|             "expenses": {} | ||||
|         } | ||||
|         return {"server": {}, "doctors": {}, "reports": [], "expenses": {}} | ||||
|     with open(STATE_FILE, "r") as f: | ||||
|         return json.load(f) | ||||
| 
 | ||||
| 
 | ||||
| def save_state(state): | ||||
|     with open(STATE_FILE, "w") as f: | ||||
|         json.dump(state, f, indent=2) | ||||
| 
 | ||||
| 
 | ||||
| def gen_server_keys(state): | ||||
|     if "rsa_oaep" in state["server"]: | ||||
|         print("Server keys already exist.") | ||||
|         return | ||||
|     rsa_oaep_key = RSA.generate(512) | ||||
|     rsa_oaep_key = RSA.generate(1024) | ||||
|     pub_pem = rsa_oaep_key.publickey().export_key().decode() | ||||
|     priv_pem = rsa_oaep_key.export_key().decode() | ||||
| 
 | ||||
|     homo_rsa = RSA.generate(512) | ||||
|     homo_rsa = RSA.generate(1024) | ||||
|     n = int(homo_rsa.n) | ||||
|     e = int(homo_rsa.e) | ||||
|     d = int(homo_rsa.d) | ||||
|  | @ -61,11 +59,18 @@ def gen_server_keys(state): | |||
|     pub, priv = paillier.generate_paillier_keypair(n_length=1024) | ||||
| 
 | ||||
|     state["server"]["rsa_oaep"] = {"pub_pem": pub_pem, "priv_pem": priv_pem} | ||||
|     state["server"]["homo_rsa"] = {"n": n, "e": e, "d": d, "base": base, "max_exp": max_exp} | ||||
|     state["server"]["homo_rsa"] = { | ||||
|         "n": n, | ||||
|         "e": e, | ||||
|         "d": d, | ||||
|         "base": base, | ||||
|         "max_exp": max_exp, | ||||
|     } | ||||
|     state["server"]["paillier"] = {"n": pub.n, "p": priv.p, "q": priv.q} | ||||
|     save_state(state) | ||||
|     print("Server RSA-OAEP, Homo-RSA, and Paillier keys generated.") | ||||
| 
 | ||||
| 
 | ||||
| def get_paillier_keys(state): | ||||
|     n = state["server"]["paillier"]["n"] | ||||
|     p = state["server"]["paillier"]["p"] | ||||
|  | @ -74,12 +79,13 @@ def get_paillier_keys(state): | |||
|     priv = paillier.PaillierPrivateKey(pub, p, q) | ||||
|     return pub, priv | ||||
| 
 | ||||
| 
 | ||||
| def register_doctor(state): | ||||
|     name = input("Doctor name: ").strip() | ||||
|     dept = input("Department: ").strip() | ||||
|     doc_id = "doc_" + uuid.uuid4().hex[:8] | ||||
| 
 | ||||
|     eg_key = ElGamal.generate(512, get_random_bytes) | ||||
|     eg_key = ElGamal.generate(1024, get_random_bytes) | ||||
|     # ElGamal object has p,g,y,x attributes | ||||
|     p = int(eg_key.p) | ||||
|     g = int(eg_key.g) | ||||
|  | @ -97,13 +103,16 @@ def register_doctor(state): | |||
|         "department_md5": dept_md5_int, | ||||
|         "department_paillier": { | ||||
|             "ciphertext": int(dept_enc.ciphertext()), | ||||
|             "exponent": dept_enc.exponent | ||||
|             "exponent": dept_enc.exponent, | ||||
|         }, | ||||
|         "elgamal": {"p": p, "g": g, "y": y, "x": x} | ||||
|         "elgamal": {"p": p, "g": g, "y": y, "x": x}, | ||||
|     } | ||||
|     save_state(state) | ||||
|     print(f"Registered doctor {name} with id {doc_id} in dept {dept}.") | ||||
|     print(f"ElGamal pub (p,g,y) set. Department stored both plaintext and Paillier-encrypted.") | ||||
|     print( | ||||
|         f"ElGamal pub (p,g,y) set. Department stored both plaintext and Paillier-encrypted." | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def list_markdown_files(): | ||||
|     ensure_dirs() | ||||
|  | @ -112,18 +121,20 @@ def list_markdown_files(): | |||
|         print(f"{i}. {f}") | ||||
|     return files | ||||
| 
 | ||||
| 
 | ||||
| def rsa_oaep_encrypt_large(data_bytes, pub_pem): | ||||
|     pub = RSA.import_key(pub_pem) | ||||
|     cipher = PKCS1_OAEP.new(pub)  # SHA1 by default | ||||
|     k = pub.size_in_bytes() | ||||
|     hlen = 20 | ||||
|     max_pt = k - 2*hlen - 2 | ||||
|     max_pt = k - 2 * hlen - 2 | ||||
|     out = b"" | ||||
|     for i in range(0, len(data_bytes), max_pt): | ||||
|         block = data_bytes[i:i+max_pt] | ||||
|         block = data_bytes[i : i + max_pt] | ||||
|         out += cipher.encrypt(block) | ||||
|     return base64.b64encode(out).decode() | ||||
| 
 | ||||
| 
 | ||||
| def rsa_oaep_decrypt_large(b64, priv_pem): | ||||
|     data = base64.b64decode(b64.encode()) | ||||
|     priv = RSA.import_key(priv_pem) | ||||
|  | @ -131,10 +142,11 @@ def rsa_oaep_decrypt_large(b64, priv_pem): | |||
|     k = priv.size_in_bytes() | ||||
|     out = b"" | ||||
|     for i in range(0, len(data), k): | ||||
|         block = data[i:i+k] | ||||
|         block = data[i : i + k] | ||||
|         out += cipher.decrypt(block) | ||||
|     return out | ||||
| 
 | ||||
| 
 | ||||
| def elgamal_sign(doc_eg, msg_bytes): | ||||
|     p = int(doc_eg["p"]) | ||||
|     g = int(doc_eg["g"]) | ||||
|  | @ -149,6 +161,7 @@ def elgamal_sign(doc_eg, msg_bytes): | |||
|     s = (kinv * (H - x * r)) % (p - 1) | ||||
|     return int(r), int(s) | ||||
| 
 | ||||
| 
 | ||||
| def elgamal_verify(pub_eg, msg_bytes, sig): | ||||
|     p = int(pub_eg["p"]) | ||||
|     g = int(pub_eg["g"]) | ||||
|  | @ -161,6 +174,7 @@ def elgamal_verify(pub_eg, msg_bytes, sig): | |||
|     v2 = pow(g, H, p) | ||||
|     return v1 == v2 | ||||
| 
 | ||||
| 
 | ||||
| def doctor_submit_report(state): | ||||
|     if not state["doctors"]: | ||||
|         print("No doctors. Register first.") | ||||
|  | @ -196,7 +210,7 @@ def doctor_submit_report(state): | |||
|         "timestamp_utc": ts, | ||||
|         "md5_hex": md5_hex, | ||||
|         "elgamal_sig": {"r": r, "s": s}, | ||||
|         "rsa_oaep_b64": ct_b64 | ||||
|         "rsa_oaep_b64": ct_b64, | ||||
|     } | ||||
|     state["reports"].append(rec) | ||||
|     save_state(state) | ||||
|  | @ -206,6 +220,7 @@ def doctor_submit_report(state): | |||
|     print(f"sig: r={r} s={s}") | ||||
|     print(f"enc blocks (base64 len): {len(ct_b64)}") | ||||
| 
 | ||||
| 
 | ||||
| def homo_rsa_encrypt_amount(state, amount): | ||||
|     n = int(state["server"]["homo_rsa"]["n"]) | ||||
|     e = int(state["server"]["homo_rsa"]["e"]) | ||||
|  | @ -217,6 +232,7 @@ def homo_rsa_encrypt_amount(state, amount): | |||
|     c = pow(m, e, n) | ||||
|     return int(c) | ||||
| 
 | ||||
| 
 | ||||
| def homo_rsa_discrete_log(m, base, mod, max_k): | ||||
|     val = 1 % mod | ||||
|     if m == 1 % mod: | ||||
|  | @ -227,6 +243,7 @@ def homo_rsa_discrete_log(m, base, mod, max_k): | |||
|             return k | ||||
|     return None | ||||
| 
 | ||||
| 
 | ||||
| def doctor_submit_expense(state): | ||||
|     if not state["doctors"]: | ||||
|         print("No doctors. Register first.") | ||||
|  | @ -242,12 +259,16 @@ def doctor_submit_expense(state): | |||
|     print(f"Encrypted expense stored for {doc_id}.") | ||||
|     print(f"ciphertext: {c}") | ||||
| 
 | ||||
| 
 | ||||
| def auditor_list_reports(state): | ||||
|     if not state["reports"]: | ||||
|         print("No reports.") | ||||
|         return | ||||
|     for r in state["reports"]: | ||||
|         print(f"{r['report_id']} by {r['doctor_id']} at {r['timestamp_utc']} file={r['filename']} md5={r['md5_hex']}") | ||||
|         print( | ||||
|             f"{r['report_id']} by {r['doctor_id']} at {r['timestamp_utc']} file={r['filename']} md5={r['md5_hex']}" | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| def auditor_verify_report(state): | ||||
|     if not state["reports"]: | ||||
|  | @ -261,12 +282,18 @@ def auditor_verify_report(state): | |||
|     priv_pem = state["server"]["rsa_oaep"]["priv_pem"] | ||||
|     pt = rsa_oaep_decrypt_large(rec["rsa_oaep_b64"], priv_pem) | ||||
|     md5_calc = MD5.new(pt).hexdigest() | ||||
|     ok_md5 = (md5_calc == rec["md5_hex"]) | ||||
|     ok_md5 = md5_calc == rec["md5_hex"] | ||||
| 
 | ||||
|     doc = state["doctors"][rec["doctor_id"]] | ||||
|     pub_eg = {"p": doc["elgamal"]["p"], "g": doc["elgamal"]["g"], "y": doc["elgamal"]["y"]} | ||||
|     pub_eg = { | ||||
|         "p": doc["elgamal"]["p"], | ||||
|         "g": doc["elgamal"]["g"], | ||||
|         "y": doc["elgamal"]["y"], | ||||
|     } | ||||
|     msg = pt + rec["timestamp_utc"].encode() | ||||
|     ok_sig = elgamal_verify(pub_eg, msg, (rec["elgamal_sig"]["r"], rec["elgamal_sig"]["s"])) | ||||
|     ok_sig = elgamal_verify( | ||||
|         pub_eg, msg, (rec["elgamal_sig"]["r"], rec["elgamal_sig"]["s"]) | ||||
|     ) | ||||
| 
 | ||||
|     ts = datetime.fromisoformat(rec["timestamp_utc"]) | ||||
|     now = datetime.now(timezone.utc) | ||||
|  | @ -279,6 +306,7 @@ def auditor_verify_report(state): | |||
|     print(f"server now: {now.isoformat()}") | ||||
|     print(f"age seconds: {int(skew_sec)} (future? {skew_sec < 0})") | ||||
| 
 | ||||
| 
 | ||||
| def auditor_keyword_search(state): | ||||
|     if not state["doctors"]: | ||||
|         print("No doctors.") | ||||
|  | @ -292,18 +320,26 @@ def auditor_keyword_search(state): | |||
|     found = [] | ||||
|     for doc_id, doc in state["doctors"].items(): | ||||
|         enc_info = doc["department_paillier"] | ||||
|         enc_doc = paillier.EncryptedNumber(pub, int(enc_info["ciphertext"]), int(enc_info["exponent"])) | ||||
|         enc_doc = paillier.EncryptedNumber( | ||||
|             pub, int(enc_info["ciphertext"]), int(enc_info["exponent"]) | ||||
|         ) | ||||
|         diff = enc_doc - q_enc | ||||
|         val = priv.decrypt(diff) | ||||
|         is_match = (val == 0) | ||||
|         is_match = val == 0 | ||||
|         if is_match: | ||||
|             found.append(doc_id) | ||||
|         print(f"{doc_id}: dept='{doc['department']}' enc_ct={enc_info['ciphertext']} match={is_match}") | ||||
|         print( | ||||
|             f"{doc_id}: dept='{doc['department']}' enc_ct={enc_info['ciphertext']} match={is_match}" | ||||
|         ) | ||||
|     print(f"Matches: {found}") | ||||
| 
 | ||||
| 
 | ||||
| def auditor_sum_expenses(state): | ||||
|     homo = state["server"]["homo_rsa"] | ||||
|     n = int(homo["n"]); d = int(homo["d"]); base = int(homo["base"]); max_exp = int(homo["max_exp"]) | ||||
|     n = int(homo["n"]) | ||||
|     d = int(homo["d"]) | ||||
|     base = int(homo["base"]) | ||||
|     max_exp = int(homo["max_exp"]) | ||||
|     if not state["expenses"]: | ||||
|         print("No expenses.") | ||||
|         return | ||||
|  | @ -332,6 +368,7 @@ def auditor_sum_expenses(state): | |||
|     else: | ||||
|         print(f"decrypted sum: {s}") | ||||
| 
 | ||||
| 
 | ||||
| def list_doctors(state): | ||||
|     if not state["doctors"]: | ||||
|         print("No doctors.") | ||||
|  | @ -339,6 +376,7 @@ def list_doctors(state): | |||
|     for doc_id, d in state["doctors"].items(): | ||||
|         print(f"{doc_id}: {d['name']} dept='{d['department']}'") | ||||
| 
 | ||||
| 
 | ||||
| def doctor_list_my_data(state): | ||||
|     doc_id = input("Enter your doctor id: ").strip() | ||||
|     if doc_id not in state["doctors"]: | ||||
|  | @ -352,6 +390,7 @@ def doctor_list_my_data(state): | |||
|     for c in state["expenses"].get(doc_id, []): | ||||
|         print(c) | ||||
| 
 | ||||
| 
 | ||||
| def main(): | ||||
|     ensure_dirs() | ||||
|     state = load_state() | ||||
|  | @ -430,5 +469,6 @@ def main(): | |||
|         else: | ||||
|             print("Invalid.") | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue