def createDatabase(self, count = 100, startFrom=1000): """ Description: creates the database """ # only allow 4 digit PINs if startFrom + count > 9999: startFrom = 1000 if count > 1000: count = 100 # 'privatekeys : where private keys are stored' if not os.path.exists('privatekeys'): os.makedirs('privatekeys') # database is again Database.pkl serverDB = open('Database.pkl','ab') for counter in range(startFrom, startFrom + count): # generates RSAkey pair, length = 1024 bits rsakey = RSAKeyHandling.generateRSAkeypair() # now we can write the public and private keys to different files # for the efficiency in verification and debugging, the values # have been chosen as such. # One must NOT confuse them as real values as they will be entirely different and generated # using a different set of algorithms voterID = 'voteid' + str(counter) PIN = counter # generate privatekey file name for voter keyfilename = 'privatekeys/' + voterID +'.pem' rsakey.save_pem(keyfilename, None, empty_callback) # public key part of RSA in base64 publickey_inbase64 = RSAKeyHandling.save_public_rsakey_to_b64string(rsakey) # sha256 of VoterID || PIN in base64 hash_of_voterID_PIN = RSAKeyHandling.sha256hash_base64( voterID + str(PIN) ) # create dictionary for a particular userID userDict = { hash_of_voterID_PIN : { 'pkey' : publickey_inbase64 , 'voted' : 0 } } # save dictionary; save userID info in the database pickle.dump(userDict, serverDB) serverDB.flush() serverDB.close()
def main(): # seeding the PRNG with 1024 random bytes from OS # from M2Crypto Rand.rand_seed (os.urandom (1024)) while 1: #====================================================== # draw MAIN SCREEN mainScreen = MainScreen() centerWindow(mainScreen, WINDOW_WIDTH_MS, WINDOW_HEIGHT_MS) mainScreen.mainloop() #====================================================== ### begin connecting to the srver # buffer length buffer_length = 5000 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # require a certificate from the server myhost = 'localhost' myport = 4321 try: # ssl.CERT_NONE : cause we are using a self signed certificate ssl_sock = ssl.wrap_socket(s,cert_reqs=ssl.CERT_NONE,ssl_version=ssl.PROTOCOL_TLSv1) ssl_sock.connect((myhost, myport)) #print repr(ssl_sock.getpeername()) #print ssl_sock.cipher() #begin to receive DH key exchange data from server #in order of p,g,g^a serverDH_p = base64.b64decode(ssl_sock.read(buffer_length)) serverDH_g = base64.b64decode(ssl_sock.read(buffer_length)) serverDH_pub = base64.b64decode(ssl_sock.read(buffer_length)) myDHobject = DH.set_params(serverDH_p, serverDH_g) # pick random p and generate g^b in myDhobject.pub myDHobject.gen_key() ssl_sock.sendall(base64.b64encode(myDHobject.pub)) # generate shared AES Key sharedAESkey = myDHobject.compute_key(serverDH_pub) # print 'shared AES Key ', hexlify(sharedAESkey) # now we have a secure shared 256-bit AES key to send data around # it was Diffie Hellman, so even if TLS was borked, hopefully noone knows it except: #ZZZ change to msgbox tkMessageBox.showwarning(title = "Connection Error", message = "Cannot connect to server.") ssl_sock.close() # mainScreen.destroy() # print 'Cannot connect to server', myhost , ':' , myport continue #====================================================== # draw AUTHENTICATION SCREEN authScreen = AuthScreen() centerWindow(authScreen, WINDOW_WIDTH_AUTH, WINDOW_HEIGHT_AUTH) authScreen.mainloop() # voterID, privateRSAKey and PIN are valid #====================================================== # start validating login # get the chosen IV in base64 chosen_IV_inbase64 = ssl_sock.read(buffer_length) # decode it from base64 chosen_IV = b64decode(chosen_IV_inbase64) # print 'got chosen_IV ', hexlify(chosen_IV) # voterID || PIN voterID_PIN = voterID + voterPIN # print 'voterID_PIN ', str(voterID_PIN) # calculate sha256 hash of voterID || PIN in base64 hash_of_voterID_PIN_inbase64 = RSAKeyHandling.sha256hash_base64(voterID_PIN) # print 'hash of voterID_PIN in base 64 ', hash_of_voterID_PIN_inbase64 # encrypt it using AES 256 # key = sharedAESKey # IV = chosen_IV encrypted_AES_hash = RSAKeyHandling.AES_encryptor(sharedAESkey, hash_of_voterID_PIN_inbase64, chosen_IV) # convert it into base64 encrypted_AES_hash_inbase64 = base64.b64encode(encrypted_AES_hash) # send it to the server ssl_sock.sendall(encrypted_AES_hash_inbase64) # print 'sent to server encrypted_AES_hash_inbase64 ', encrypted_AES_hash_inbase64 # wait for server to return user_exists or user_has_voted user_exists_base64 = ssl_sock.read(buffer_length) # decode it from base64 user_exists = base64.b64decode(user_exists_base64) # print hexlify(user_exists) # decrypt it from AES using sharedAESkey and chosenIV user_exists = RSAKeyHandling.AES_decryptor(sharedAESkey, user_exists, chosen_IV) # print user_exists if user_exists == 'LOL_NO_WAY': # ZZZ change to msgbox tkMessageBox.showerror(title = "Not Eligible User", message = "Sorry, User Not Eligible to Vote") #print 'Sorry, user not eligible to vote' ssl_sock.close() continue ## ZZZ restart GUI , how ? # if user is eligible to vote # load privatekey rsakey = RSA.load_key(privateRSAKey, RSAKeyHandling.empty_callback) try: # user_exists must contain the hash_normal encrypted with public key # decrypt it decrypted_hash = rsakey.private_decrypt(user_exists, RSA.pkcs1_padding) except: # decryption didn't work # ZZZ change to msgbox tkMessageBox.showerror(title = "Decyption Error", message = "Sorry, Wrong User Credentials") ssl_sock.close() continue ## ZZZ restart GUI , how ? if decrypted_hash != hash_of_voterID_PIN_inbase64: # ZZZ change to msgbox tkMessageBox.showerror(title = "Decryption Error", message = "Sorry, Wrong User Credentials") # print 'Sorry, wrong user credentials' ssl_sock.close() continue # sys.exit() # now the user is authenticated and we can go on # start voting #====================================================== #draw choice screen for president/congress/counsel/ polls = { "president" : (1, 3), "congress" : (1, 5), "counsel" : (2, 4) } votes = { "president" : None, "congress" : None, "counsel" : None } for poll in polls: window = Group(poll, polls[poll][0], polls[poll][1]) # def __init__(self, _vf, _ms, _mo, master=None): centerWindow(window, WINDOW_WIDTH_MAIN, WINDOW_HEIGHT_MAIN) window.mainloop() votes[poll] = tuple(userVote) # store user vote del userVote[:] # clear user vote # send the votes to server # print votes votes_string = json.dumps(votes) # convert votes to base64 votes_string_inbase64 = base64.b64encode(votes_string) # to load it later # votes_n = json.loads(vote_str) # begin to encrypt votes encrypted_votes_string = RSAKeyHandling.AES_encryptor(sharedAESkey, votes_string_inbase64, chosen_IV) # convert it to base64 encrypted_votes_string_inbase64 = base64.b64encode(encrypted_votes_string) # send it to the server ssl_sock.sendall(encrypted_votes_string_inbase64) # wait for the thank you note encrypted_thankyou_inbase64 = ssl_sock.read(buffer_length) # decode it from base64 encrypted_thankyou = base64.b64decode(encrypted_thankyou_inbase64) # decrypt it using AES decrypted_thankyou = RSAKeyHandling.AES_decryptor(sharedAESkey, encrypted_thankyou, chosen_IV) print decrypted_thankyou # draw END SCREEN endScreen = EndScreen() centerWindow(endScreen, WINDOW_WIDTH_ES, WINDOW_HEIGHT_MS) endScreen.mainloop() # note that closing the SSLSocket will also close the underlying socket ssl_sock.close()
def generate_voters(count=100,startfrom=1000): # only allow 4 digit PINs if startfrom+count > 9999: startfrom = 1000 if count > 100: count = 100 'privatekeys : where private keys are stores' if not os.path.exists('privatekeys'): os.makedirs('privatekeys') # 'publickeys : where the server DB will be saved' # if not os.path.exists('publickeys'): # os.makedirs('publickeys') serverDB = open('Database.pkl','ab') # start generating count RSA keypairs for counter in range(startfrom,startfrom+count): # generates RSAkey pair, length = 1024 bits rsakey = RSAKeyHandling.generateRSAkeypair() # now we can write the public and private keys to different files voterID = 'voters' + str(counter) PIN = counter # generate privatekey file name for voter keyfilename = 'privatekeys/' + voterID +'.pem' rsakey.save_pem(keyfilename, None, empty_callback) # public key part of RSA in base64 publickey_inbase64 = RSAKeyHandling.save_public_rsakey_to_b64string(rsakey) # sha256 of VoterID || PIN in base64 hash_of_voterID_PIN = RSAKeyHandling.sha256hash_base64( voterID + str(PIN) ) # final string to write to DB in a line # public key in base 64 SPACE hash of voterID||PIN SPACE 0 (0 because he has not voted yet) # final_db_record = publickey_inbase64 + ' ' + hash_of_voterID_PIN + ' '+'0\n' # print final_db_record # serverDB.write(final_db_record) userdict = { hash_of_voterID_PIN : { 'pkey' : publickey_inbase64 , 'voted' : 0 } } pickle.dump(userdict, serverDB) serverDB.flush() serverDB.close() return 1
def run(self): server_start = Server.Server() server_start.touchResultsFile() auditlogname = './AuditLog.pkl' if (os.path.exists(auditlogname)): os.remove(auditlogname) counterplname = './CounterPL.txt' if (os.path.exists(counterplname)): os.remove(counterplname) # try: # os.remove(auditlogname) # except OSError: # pass # try: # os.remove(counterplname) # except OSError: # pass # read it from config file later number_of_users = 100 print 'server thread started' # change buffer length here in bits buffer_length = 5000 # seeding the PRNG with 1024 random bytes from OS M2Crypto.Rand.rand_seed (os.urandom (1024)) # host address # myhost = 'localhost' myhost = '' # all interfaces # port , which is hopefully not used myport = 4321 # number of concurrent connections to the server, will drop after that number_of_concurrent_connections = 3 # binding a socket bindsocket = socket.socket() bindsocket.bind((myhost, myport)) # start listening bindsocket.listen(number_of_concurrent_connections) print 'listening' # read the pickle database databaseobject = Database.Database() serverDB = databaseobject.readAllDataFromDatabase(number_of_users) # now we have the database loaded in voting_database while True: #ZZZ remover it later print 'inside while' # connection part mysocket, fromaddr = bindsocket.accept() # wrap SSL around the socket connstream = ssl.wrap_socket(mysocket, server_side=True, certfile="servercert", # server certification file keyfile="serverkey", # server private key file ssl_version=ssl.PROTOCOL_TLSv1) # using TLS # deal_with_client(connstream) print 'Client connected from address ' + str(fromaddr) # beginning DH key exchange # print 'beginning DH Key exchange' # 256 = length # 2 = generator, which is usally 2 or 5 # empty_callback : to avoid writing garbage to screen serverDH = DH.gen_params(256, 2, RSAKeyHandling.empty_callback) # generate the random number a, now g^a will be in serverDH.pub serverDH.gen_key() # now we need to send serverDH.p , serverDH.g and serverDH.pub # first they need to be converted to base64 and then sent connstream.sendall(base64.b64encode(serverDH.p)) # p connstream.sendall(base64.b64encode(serverDH.g)) # g connstream.sendall(base64.b64encode(serverDH.pub)) # g^a # now wait for the g^b from client to computer sharedAESkey clientDH_pub = base64.b64decode(connstream.read(buffer_length)) # compute sharedAESkey sharedAESkey = serverDH.compute_key(clientDH_pub) # print 'shared AES Key ', hexlify(sharedAESkey) # now we have a 256 bit shared AES key to encrypt data with # now we can send voterID and check for correction in order to authenticate the voter # or send votes # generate 16 byte chosen_IV chosen_IV = Rand.rand_bytes(16) # encode it to base64 (to avoid 00 bytes) chosen_IV_inbase64 = base64.b64encode(chosen_IV) # send it to client connstream.sendall(chosen_IV_inbase64) # print 'Sent chosen IV ' , hexlify(chosen_IV) # wait for the AES_encrypted sha hash of voterID || PIN in base64 hash_inbase64 = connstream.read(buffer_length) # print 'received encrypted_hash_inbase64 ', hash_inbase64 # decode it from base64 encrypted_hash = base64.b64decode(hash_inbase64) # decrypt it from AES # key = sharedAESkey # iv = chosen_IV hash_normal = RSAKeyHandling.AES_decryptor(sharedAESkey, encrypted_hash, chosen_IV) # print 'hash_normal ', hash_normal # now we have the normal hash and can look up user data ####ZZZ do a print (which user connected) print hash_normal if hash_normal in serverDB: print 'user in DB' # look it up from DB user_public_key_inbase64 = serverDB[hash_normal]['pkey'] # we dont need to convert it from base64. our code does that # load the public rsa key into an rsakey for encryption rsakey = RSAKeyHandling.load_public_rsakey_from_b64string(user_public_key_inbase64) # check if he has voted has_voted = serverDB[hash_normal]['voted'] # we dont want to immediately reject after we see that he has voted, to avoid timing attacks # so we add the public key too anyway # if he has voted # send VOTED if (has_voted == 1): # print 'user has voted' # send LOL_NO_WAY # encrypt it using AES, sharedAESkey and chosen_IV encrypted_msg = RSAKeyHandling.AES_encryptor(sharedAESkey, 'LOL_NO_WAY', chosen_IV) # convert it to base64 encrypted_msg_inbase64 = base64.b64encode(encrypted_msg) # send it to the server connstream.sendall(encrypted_msg_inbase64) # break the connection # BYE BYE connstream.shutdown(socket.SHUT_RDWR) connstream.close() continue else: # user has not voted and can vote # otherwise (if the user has not voted) # encrypt the hash_normal with public key using RSA # padding = PKCS1 encrypted_hash_normal = rsakey.public_encrypt(hash_normal, RSA.pkcs1_padding) # encrypt it with AES encrypted_hash_normal = RSAKeyHandling.AES_encryptor(sharedAESkey, encrypted_hash_normal, chosen_IV) # encode it to base64 to send encrypted_hash_normal_inbase64 = base64.b64encode(encrypted_hash_normal) # send it connstream.sendall(encrypted_hash_normal_inbase64) # print 'sent public encrypted' else: # if he is not in DB # send LOL_NO_WAY # encrypt it using AES, sharedAESkey and chosen_IV encrypted_msg = RSAKeyHandling.AES_encryptor(sharedAESkey, 'LOL_NO_WAY', chosen_IV) # convert it to base64 encrypted_msg_inbase64 = base64.b64encode(encrypted_msg) # send it to the server connstream.sendall(encrypted_msg_inbase64) # break the connection # BYE BYE connstream.shutdown(socket.SHUT_RDWR) connstream.close() continue # now we need to wait for votes to be sent # read votes sent to server encrypted_votes_inbase64 = connstream.read(buffer_length) # decode it from base64 encrypted_votes = base64.b64decode(encrypted_votes_inbase64) # decrypt it using AES, we will get a base64 encoding of a json string of the dictionary try: decrypted_votes_inbase64_json = RSAKeyHandling.AES_decryptor(sharedAESkey, encrypted_votes, chosen_IV) except: # bad votes received connstream.shutdown(socket.SHUT_RDWR) connstream.close() continue # decode it from base64 decrypted_votes_json = base64.b64decode(decrypted_votes_inbase64_json) # de-json it decrypted_votes = json.loads(decrypted_votes_json) # note in the vote log, we don't want people to vote many times, THIS IS NOT IRAN or maybe it is ? :D serverDB[hash_normal]['voted'] = 1 # making server object to use the utility functions myserver = Server.Server() auditDict = { hash_normal:{ 'president': decrypted_votes['president'], 'congress' : decrypted_votes['congress'], 'counsel' : decrypted_votes['counsel'] } } # add votes to the DB myserver.addToAuditLogFile(auditDict) myserver.addToResultsFile(decrypted_votes) # Make vote confirmation message thankyou_msg = 'Votes OK' # Encrypt it encrypted_thanks = RSAKeyHandling.AES_encryptor(sharedAESkey, thankyou_msg, chosen_IV) # convert it to base64 encrypted_thanks_inbase64 = base64.b64encode(encrypted_thanks) # send it to the client connstream.sendall(encrypted_thanks_inbase64) #finally: connstream.shutdown(socket.SHUT_RDWR) connstream.close()