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