/
voter.py
142 lines (108 loc) · 3.59 KB
/
voter.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/usr/bin/python3
from Crypto.Util.number import long_to_bytes, bytes_to_long, inverse
from Crypto.PublicKey import RSA
import string
import os
import requests
import random
import math
import base64
import json
vote_subj = "If you could vote the next president of your country, who would that be?"
options = [
(1, "Yakuhito"),
(2, "Also Yakuhito"),
(3, "Definetly Yakuhito"),
(4, "Yakuhito, of course!")
]
pubkey_pem = b'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv1dYYw3e/nRRmomgTaeF\n1+ocseg2RMlhDGP16daOmcd//oBudGWqphDs+0a1d75I1wmj/YlviiRhiwRgPo4j\nmXXb4akPyxnO44plK0IpO761gyod2WrxQXnCNmUYMVOSiZdE168WinrKcIijc8XY\nbWLexx4RwKS0j+cinSTbJiIVvhefSWYXxOpz18gEIu3xgkOx9aD853n8BXA4Bv5t\ncuwxZdF+ibIrE5TmNJe8kxJbfxsucDkamGvIWsummEMpuH4jGWEuTantYnNKG615\nWhsA7eI/9xCR036O7nNTIjk5KRR/rZ1ytgBMceerK5g/bk8hYII/surpqxjZ+N/0\nkwIDAQAB\n-----END PUBLIC KEY-----'
VALIDATOR_ADDR = "http://127.0.0.1:1111/validate"
COUNTER_ADDR = "http://127.0.0.1:2222/submit"
STATS_ADDR = "http://127.0.0.1:2222/stats"
def getSignedVote(username, vote):
global pubkey_pem
global VALIDATOR_ADDR
pubkey = RSA.importKey(pubkey_pem)
# Choose r
r = random.randint(2, pubkey.n)
while math.gcd(r, pubkey.n) != 1:
r += 1
# Calculate blinding factor
blinding_factor = pow(r, pubkey.e, pubkey.n)
# Calculate blinding vote
blinded_vote = (int(vote) * blinding_factor) % pubkey.n
# Get blinded signature
enc_vote = base64.b64encode(long_to_bytes(blinded_vote)).decode()
req = requests.post(VALIDATOR_ADDR, json={'username': username, 'vote': enc_vote})
resp = json.loads(req.text)
blinded_signature = bytes_to_long(base64.b64decode(resp["signature"]))
# Calculate signature
r_inv = inverse(r, pubkey.n)
signature = blinded_signature * r_inv % pubkey.n
return signature
def submitSignedVote(vote, r):
global COUNTER_ADDR
vote = base64.b64encode(long_to_bytes(vote)).decode()
req = requests.post(COUNTER_ADDR, json={"signed_vote": vote, "r": str(r)})
print(req.text)
def printStats():
global STATS_ADDR
req = requests.get(STATS_ADDR)
stats = json.loads(req.text)
print()
print("Thank you for taking the time to vote! Here are the vote stats:")
for key, value in stats.items():
print("Option {} has {} votes.".format(key, value))
print()
def encodeVote(vote):
alphabet = string.ascii_letters + "0123456789"
r = ''.join([random.choice(alphabet) for i in range(64)])
enc = "{}-{}".format(vote, r)
return bytes_to_long(enc.encode()), r
def main():
global vote_subj
global options
# Intro
print("Welcome to y@kuhi.to's voting system demo!")
print("PLEASE NOTE THAT YOUR VOTE IS FINAL")
print("No pressure!")
print()
print("Today's voting topic:")
print(vote_subj)
print()
print("Yout voting options:")
for opt in options:
print("OPTION {}: {}".format(opt[0], opt[1]))
print()
# Get user's username
print("Username:", end=" ")
username = input()
# Get the user's vote
print("Your vote:", end=" ")
try:
vote = int(input()) # This is python3, please note that running this line on python2 will result in a code execution vuln
except:
print("Nope.")
return ""
# See if the vote is valid
valid = False
for opt in options:
if opt[0] == vote:
valid = True
if valid == False:
print("You were the chosen one! I trusted you!")
return ""
# Encode Vote
vote, r = encodeVote(vote)
# Get signed vote
try:
signed_vote = getSignedVote(username, vote)
except:
print("Something went wrong with vote signing :(")
return ""
# Send vote to counter
submitSignedVote(signed_vote, r)
# After the vote has bin submitted, print the stats
printStats()
if __name__ == "__main__":
main()