diff --git a/IS/Lab/Eval-Endsem/ans.py b/IS/Lab/Eval-Endsem/ans.py index 4b7a362..2522289 100644 --- a/IS/Lab/Eval-Endsem/ans.py +++ b/IS/Lab/Eval-Endsem/ans.py @@ -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() diff --git a/IS/Lab/Eval-Endsem/server_state.json b/IS/Lab/Eval-Endsem/server_state.json new file mode 100644 index 0000000..02256f3 --- /dev/null +++ b/IS/Lab/Eval-Endsem/server_state.json @@ -0,0 +1,39 @@ +{ + "server": { + "rsa_oaep": { + "pub_pem": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4tLsDIfOKBqe3vblt5LXG5a8R\n10L/x8JEF9i+A9egGTcehkf/bGm4C5L3L29KajadW4ZosCLRXp7UL6DS8pAPIjym\n00ydwG8gaBIi8Oq1cqmLB+umJWfj0FPSCQQ/EWOkfy4adhlpVsEpYX0F3HagJMWX\n8k+7Y5T2VinlLvzFeQIDAQAB\n-----END PUBLIC KEY-----", + "priv_pem": "-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQC4tLsDIfOKBqe3vblt5LXG5a8R10L/x8JEF9i+A9egGTcehkf/\nbGm4C5L3L29KajadW4ZosCLRXp7UL6DS8pAPIjym00ydwG8gaBIi8Oq1cqmLB+um\nJWfj0FPSCQQ/EWOkfy4adhlpVsEpYX0F3HagJMWX8k+7Y5T2VinlLvzFeQIDAQAB\nAoGADkh0hzYchvWDifD/CjVTzLMFdhnZLZ4ZAsq8yRnTNmdIxMChx+nOZYvolBqM\nDrs2qLWzh7wqHxpj6hjaRQG6m71KmI/2wf2zuVbe6JXjl1/JnhAxkX+/21VLPHeN\n3asoW4OoHmEzODNn/ToR/C5febKbrytLzg+pSDLVYLv4lwECQQDMjq2K/t+o8Mau\nys1hxFyWU9gAGI9eaenLOEDj1qWR+rzDjQHm3jRYmcrNEW1ANv786PwfnnADAG4Y\nd0KONJZ5AkEA5ygHqdFkLavMcXQq94jwCxrm5jnWgDQhTMCaVJm7q15Wy00J0YhV\nrOxueEXsz+qvqwPwYOqy0DFuJp8dSMnnAQJBAJrt8YkV84Z8Hq9ikN3coJeHF1Ez\nSNskctvlVlh6SVrgQroFgYw/ffwhN1XMPiflv4kEWXkFQicz2y8SnMkiEVkCQAYb\n5Lf0NLWQSMLm0wvfrphciaWj+atBtW+V135M4czRnXGaA5xqAfmj9fdvwaZtCV93\npy6ohTlDVSnoIpn93AECQAC3baByatcNs7d4gf6YAHeJR7lcunp8mkXSSFSfvpvd\nro4ZeK1+43zku924Bbt20TiK8ILv6A+UXjn90i+2cuQ=\n-----END RSA PRIVATE KEY-----" + }, + "homo_rsa": { + "n": 164389842359232134264031846579315180404350193796978989046715441129384207187207002909588561534322686552937177365781418709303198559133835621379932523919086988320481496243214495525660229165581656339725039217620772984301683801526094566411085598132762353978145016002239646463912985089234411247383307346440089991203, + "e": 65537, + "d": 74077895226727238127355852558152273758204862876074309077652681159551689866124339127934208058232521180777533157681000778682220904948654965720171159232806441014558674483465137260985628222001380523192555165268091766813928524584493224915369065364617135803593916189915134737442232565522805233342167437550352366973, + "base": 143134059844924073577556129506412771459533056544528952115538234599990715607403235525630972585813359898598154341805874144221347210705662153088065085346583035732786469642031050624550551183067263503472324662861545150647071141086235327408373720591263386297504020866978683057570292963982843365020773290075986031937, + "max_exp": 10000 + }, + "paillier": { + "n": 138696499454888532528019348635312686392652339484022359867838370358252283221017693932734415338314111706304992381888388639484446266676687521331519609781974069972632618731437711667619339769179344407970583846846400410753304647753457676686479878169700556577085241706114110986595235446256203147240824093802166646183, + "p": 10626744063889666417391725031851847935638448851114859021300775977048391276492463154539902017942602395853524748513714697872632096475343518303983602864352771, + "q": 13051645793012726815897903117649031194828553011444925802312634020180928927348477129194587702272809291014028618782499026062864654839862549368989270633400973 + } + }, + "doctors": { + "doc_9e8bce2e": { + "name": "abhidutta", + "department": "chicken", + "department_md5": 154404180747625484564548290272714958592, + "department_paillier": { + "ciphertext": 5954550937813511557859396889491781578709149502022563187410379755537616862897682932027670570080166490007624311496797425606037210969616523632743568146564706516123565096363182631247894562191903755229081265292639080416331985747706853936700040142690722097853440768248086783986102022577722182573598634908256159074146958177291983425015023982109147584394696547337979862679652378801373316077574835707358786633346144358165457207360747901317023041645356432012921511341040354760279029798165432791303357070157909841686393104943299102037425405822413475232035027558818428124945664827511093659376082039508075831813408324507966930678, + "exponent": 0 + }, + "elgamal": { + "p": 117671301588964778053148720916997075761927003975524216044616908236045921053574958317042244681269658414402504393690212321719012709956243450147980024291251092114624636060665796496601602367080539912662648234095999038729129339274018999953003845114669344109857674886565004915628218831791723597711620511913820782567, + "g": 72436130290717364351348320669407622905296512670695435848332558258663958465154643086454315130372998880754004712107837519812162982253829892054885443221177801973320604098444851054567695114438506003471175046261392724126010578316836991748449980413640661626029998490929865444723456863315045656678727292916127448216, + "y": 43081148778631766544144967924221222977793800329294410348533627475044938507346990910066908133927324128214670343922258294642495949419869309980036383810858510106523456095132420570080505759761011318006124676929624483242885094096066046546227089308573542760931013388194193464527067404173235419484999791822406266959, + "x": 97919070841102403192874501824599544347127590955132792502332924861485116119333701112188334895949397314654164844968249170623250917675155939400150469922323947025996879988535798869042950318158037215627255190775431433527010508780894311887563428631410286424905211260618588035998441181044434125534215976487788400690 + } + } + }, + "reports": [], + "expenses": {} +} \ No newline at end of file