def challenge(): #create host object host = Host() #Create a hash of the node's public key to send to the auth node for identity verification keyhash = str( base64.b64encode( hashlib.sha256( rsa_encrypt.get_pub_key().exportKey("PEM")).digest()), 'ascii') #creates a payload of the message that identifies that this is a client node that needs to be updated payload = "imup" + ":" + str( comms_number) + ":" + keyhash + ":" + settings.ID #create a socket to communicate with the auth nodes with socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) as s: s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32) #Create an empty data and address variable and a socket to recieve the data data = "" addr = 0 with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as us: #set a timeout for if there is no auth node ready us.settimeout(1) us.bind(('0.0.0.0', 55551)) #send the challenge tag to the auth nodes along with a public key to encrypt their return message with s.sendto( aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), "who?:" + keyhash), ((host.host, host.port))) #Recv a number from the auth node to connect to try: data, addr = us.recvfrom(4096) #if it fails return an error except socket.timeout: us.close() return -1 #Decrypt the recieved message data = aes_crypt.aes_dec(rsa_encrypt.get_priv_key(), data) #if message is bad return error if data == -1 or data == -2: return -1 #convert data to a string to return to the auth nodes along with the instruction payload data = str(data, 'ascii') #send payload and return expected address s.sendto( aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), "you!:" + data + ":" + payload), ((host.host, host.port))) return addr
def register(user, name, keys): payload = "usrW" + ":" + rsa_encrypt.get_auth_hash() + ":" + user + ":" + name + ":" + ":".join(keys) with socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) as s: s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32) payload = aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), payload) s.sendto(payload, (settings.MULT_ADDR, settings.MULT_PORT))
def contest_auth(address): #open a socket to the reciever with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s: #send the number data = aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), str(my_number)) s.sendto(data, (address, 44443))
def challenge(my_number, kind): #Creates a host object for use in multicast socket host = Host() #Creates a multicast socket to communicate with all auth nodes at once with socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) as s: s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32) #Creates a socket to recieve a unique number from the first auth node to respond to the contest data = "" with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as us: #sets a small timeout in case this is the first auth node in the system or the response is delayed us.settimeout(1) us.bind(('0.0.0.0', 55551)) #Sends a messafe to the other auth nodes to start a contest s.sendto( aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), "regA:" + str(my_number)), ((host.host, host.port))) #Recieves encrypted number from auth node data, address = us.recvfrom(4096) #Decrypt the recieved number using auth private key data = aes_crypt.aes_dec(rsa_encrypt.get_priv_key_auth(), data) #Check to make sure the message wasnt tampered with, return error if it was if data == -1 or data == -2: return 1 #convert the number to a string data = str(data, 'ascii') #encrypt the number with the auth public key and send it back to the auth nodes, letting them know which one was chosen and what action to preform #in this case the asction is provising updates to the auth server s.sendto( aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), "you!:" + data + ":" + kind), ((host.host, host.port))) return address
def send_share(share, host): #Store the share as a string payload = "auth:" + share['id'] + ":" + share['x'] + ":" + share['y'] #open a socket to the multicast address with socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) as s: s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32) #encrypt the share with the auth public key and send it to the multicast address s.sendto(aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), payload), ((host.host, host.port)))
def db_send(db, num): ts = str(time.time()) comms.database_log([db, num, ts]) with socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) as s: s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32) s.sendto( aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), "DBUP:" + db + ":" + num + ":" + ts), (settings.MULT_ADDR, settings.MULT_PORT)) comms.send_clients()
def broadcast(uid): print("Sending New Share to other Auth Nodes") #instantiate a shares list shares = [] #For each database for i in settings.DBS: #Open a connection to the db conn = sqlite3.connect(settings.DBdir + i + ".db") conn.row_factory = sqlite3.Row c = conn.cursor() #Grab the provided user's share from this database c.execute("SELECT * FROM enc_shares WHERE id = ?", [uid]) #append the share to the list and close the connection shares.append(c.fetchone()) conn.close() #Connect to the secrets database conn = sqlite3.connect(settings.DBdir + "secrets.db") conn.row_factory = sqlite3.Row c = conn.cursor() #Grab the user's secret entry c.execute("SELECT * FROM secrets WHERE id = ?", [uid]) #append the secret to the list and close the connection shares.append(c.fetchone()) conn.close() #Create an empty string to hold the data data = "" #For each share for i in range(len(shares) - 1): #Add no data if this is a delete message if shares[i] == None: data += "NONE||" else: #Append the share as a string to the data using the seperator || data += ( str(shares[i]['id']) + "|" + str(shares[i]['share'] + "|" + str(shares[i]['timestamp'])) + "||") #Append the secrets entry to the data string data += (str(shares[-1]['id']) + "|" + str(shares[-1]['name']) + "|" + str(shares[-1]['secret']) + "|" + str(shares[-1]['timestamp'])) #Prepend a hash of the auth private key to the data data = (rsa_encrypt.get_auth_hash() + "||" + data) #Open a socket to the multicast address with socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) as s: s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32) #Set the data header data = "here:" + str(my_number) + ":" + data #Encrypt the data and send it to the auth nodes payload = aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), data) s.sendto(payload, (settings.MULT_ADDR, settings.MULT_PORT))
def broadcast(uid): print("Sending New Share to other Auth Nodes") #grab auth hash for use auth_hash = rsa_encrypt.get_auth_hash() #instantiate a shares list shares = [] #open socket to multicast address with socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) as s: s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32) #For each database for i in settings.DBS: #Open a connection to the db conn = sqlite3.connect(settings.DBdir + i + ".db") conn.row_factory = sqlite3.Row c = conn.cursor() #Grab the provided user's share from this database c.execute("SELECT * FROM enc_shares WHERE id = ?", [uid]) #append the share to the list and close the connection shares.append(c.fetchone()) conn.close() #Connect to the secrets database conn = sqlite3.connect(settings.DBdir + "secrets.db") conn.row_factory = sqlite3.Row c = conn.cursor() #Grab the user's secret entry c.execute("SELECT * FROM secrets WHERE id = ?", [uid]) #append the secret to the list and close the connection shares.append(c.fetchone()) conn.close() #For each share for i in range(len(shares) - 1): #Add no data if this is an empty message if shares[i] == None: continue else: #Grab the data from current database as a string data = settings.DBS[i] + "||" + str( shares[i]['id']) + "||" + str( shares[i]['share']) + "||" + str( shares[i]['timestamp']) #prepend header and send data data = "here:" + str(my_number) + ":" + auth_hash + "||" + data s.sendto( aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), data), ((settings.MULT_ADDR, settings.MULT_PORT))) #grab the data from the secrets database as a string data = "secrets||" + str(shares[-1]['id']) + "||" + str( shares[-1]['name']) + "||" + str( shares[-1]['secret']) + "||" + str(shares[-1]['timestamp']) #Prepend header and send data data = "here:" + str(my_number) + ":" + auth_hash + "||" + data s.sendto(aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), data), ((settings.MULT_ADDR, settings.MULT_PORT)))
def updater(address): #Open a socket to send the shares from, connecting to the provided address with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((address, 55552)) #create a random number for the challenge response authentication challenge = int.from_bytes(Random.get_random_bytes(10), 'big') #Send the number to the recieving node s.send( aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), str(challenge))) #Get the number back, along with the updatee's timestamps #Recieve until done response = b"" temp = b"" try: while 1 == 1: temp = s.recv(4096) if temp and len(temp) == 4096: response += temp else: break response += temp #exit if connection breaks except: return -1 #decrypt response response = aes_crypt.aes_dec(rsa_encrypt.get_priv_key_auth(), response) #return error if data is corrupted if response == -1 or response == -2: return -1 #split response into timestamp and the response number response = str(response, 'ascii').split(":") #confirm that the response is correct if (challenge + 1) == int(response[0], 0): #grab timestamp timestamps = response[1].split("|") #create holder for share information data = "" #for each database for i in settings.DBS: #set up connection conn = sqlite3.connect(settings.DBdir + i + ".db") conn.row_factory = sqlite3.Row c = conn.cursor() #Make sure table exists c.execute( "CREATE TABLE IF NOT EXISTS enc_shares(id PRIMARY KEY, share, timestamp DOUBLE)" ) #Grab all shares from the current database with timestamp greater than the client's timestamp c.execute("SELECT * FROM enc_shares") d = c.fetchall() shares = [] #for each share for i in range(len(d)): #Join the components into a string if they are needed by the updatee if not str(d[i]['timestamp']) in timestamps: shares.append(d[i]["id"] + "|" + d[i]["share"] + "|" + str(d[i]["timestamp"])) #Join each share together shares = "::".join(shares) #add the information from this database to the database string data += (shares + ":::") #close connection conn.close() #open the secrets db conn = sqlite3.connect(settings.DBdir + "secrets.db") conn.row_factory = sqlite3.Row c = conn.cursor() #make sure table exists c.execute( "CREATE TABLE IF NOT EXISTS secrets(id PRIMARY KEY, name, secret, timestamp DOUBLE)" ) #Grab all shares past the client timestamp c.execute("SELECT * FROM secrets") d = c.fetchall() secrets = [] #For each secret for i in range(len(d)): #convert the share to a string if it is needed by the updatee if not str(d[i]['timestamp']) in timestamps: secrets.append(d[i]["id"] + "|" + d[i]["name"] + "|" + d[i]["secret"] + "|" + str(d[i]['timestamp'])) #join all the shares and add them to the db string data += "::".join(secrets) #send the databases to the client and exit s.send(aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), data)) return 0
def updateee(my_number): #open socket to recieve shares into with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind(('0.0.0.0', 55552)) s.listen(5) address = 0 #Attempt to update the node try: #make sure that challenge exits succesfully and grab host address address = challenge(my_number, "woke") while address == 1: address = challenge(my_number, "woke") #If socket times out then return, this is likely the first auth node to be activated except socket.timeout: print("No Auth Nodes Found") return #accept connection from the node that shares will be pulled from cli, addr = s.accept() while not addr[0] == address[0]: cli, addr = s.accept() #Challenge response authentication, the node recieves a number from the auth node responsible for the update #and sends the number + 1 to the other node data = cli.recv(1024) #decrypt number and increment it by one data = aes_crypt.aes_dec(rsa_encrypt.get_priv_key_auth(), data) data = str(data, 'ascii') data = str(int(data) + 1) #encrypt number and return it to the host #send the timestamp of the most recent share along with the number timestamps = grab_timestamps() cli.send( aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), data + ":" + timestamps)) #Recv data until the sender is done data = b"" temp = b"" try: while 1 == 1: temp = cli.recv(4096) if temp and len(temp) == 4096: data += temp else: break data += temp #if the sender loses the connection then quit except: print("registered: 0 updates") return #Decrypt the data with the auth private key data = aes_crypt.aes_dec(rsa_encrypt.get_priv_key_auth(), data) #if the data is invalid return error if data == -2 or data == -1: return -1 #if no databases hold data then return if data == b':::' * settings.TOTAL: print("registered: 0 updates") return #split the data into a list of databases data = str(data, 'ascii').split(":::") #for each database split the entries into a list for i in range(len(data)): data[i] = data[i].split("::") #store the list of db's into a disctonary #they are sent in the order they are listed in settings.py updates = {} for i in range(len(settings.DBS)): updates[settings.DBS[i]] = data[i] #store the secrets database into the dictionary updates['secrets'] = data[-1] #fill the databases fill_dbs(updates) #exit, ptinting the number of shares that were updated print("registered: " + str(len(updates['secrets'])) + " updates") return
def register(): #Create socket to recieve updates from with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.settimeout(5) s.bind(("0.0.0.0", 55550)) s.listen(5) #make sure that challenge executes correctly, else return error print("Looking for Auth Node") address = challenge() if address == -1: return -1 #Create a connection with the auth node, if it is not the #expected address than continue waiting try: cli, addr = s.accept() while not addr[0] == address[0]: cli, addr = s.accept() except socket.timeout: return -1 #Report print("Recieving Updates Now") #Recieve two sums for challenge response authentication #One for the database and one for the public key sums = cli.recv(2048).split(b"::") #Decrypt the sums using the node and db public keys sums[0] = aes_crypt.aes_dec(rsa_encrypt.get_priv_key(), sums[0]) sums[1] = aes_crypt.aes_dec(rsa_encrypt.get_priv_key_db(settings.ID), sums[1]) #if there is an error in the communication of the sums return an error if sums[0] == -1 or sums[0] == -2 or sums[1] == -1 or sums[1] == -2: return 1 #Increment the sums and return them via the auth public key sum1 = str(int(sums[0]) + 1) sum2 = str(int(sums[1]) + 1) #send the incremented sums back to proove node identity payload = aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), sum1 + ":" + sum2) #Fill recv buffer cli.send(payload + b"\x00" * (4096 - len(payload))) #Grab the latest timestamp timestamps = grab_timestamps() #Send the timestamp encrypted with the auth public key cli.send( aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), str(timestamps))) #Run the update process num_updates = shamir_updater.update(cli) #make number presentable if num_updates == -1: num_updates = 0 #Report shares print("Registered: " + str(num_updates) + " updates") #clean up and exit cli.close() return
def updater(address): #Open a socket to send the shares from, connecting to the provided address with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((address, 44441)) #create a random number for the challenge response authentication challenge = int.from_bytes(Random.get_random_bytes(10), 'big') #Send the number to the recieving node s.send( aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), str(challenge))) #Get the number back, along with the most recent timestamp that the recieving server has response = s.recv(2048) #decrypt response response = aes_crypt.aes_dec(rsa_encrypt.get_priv_key_auth(), response) #return error if data is corrupted if response == -1 or response == -2: return -1 #split response into timestamp and the response number response = str(response, 'ascii').split(":") #confirm that the response is correct if (challenge + 1) == int(response[0], 0): #grab timestamp timestamp = response[1] #create holder for share information data = "" #for each database for i in settings.DBS: #set up connection conn = sqlite3.connect(settings.DBdir + i + ".db") conn.row_factory = sqlite3.Row c = conn.cursor() #Make sure table exists c.execute( "CREATE TABLE IF NOT EXISTS enc_shares(id PRIMARY KEY, share, timestamp DOUBLE)" ) #Grab all shares from the current database with timestamp greater than the client's timestamp c.execute("SELECT * FROM enc_shares WHERE timestamp > ?", [float(timestamp)]) d = c.fetchall() #for each share for i in range(len(d)): #Join the components into a string d[i] = d[i]["id"] + "|" + d[i]["share"] + "|" + str( d[i]["timestamp"]) #Join each share together d = "::".join(d) #add the information from this database to the database string data += (d + ":::") #close connection conn.close() #open the secrets db conn = sqlite3.connect(settings.DBdir + "secrets.db") conn.row_factory = sqlite3.Row c = conn.cursor() #make sure table exists c.execute( "CREATE TABLE IF NOT EXISTS secrets(id PRIMARY KEY, name, secret, timestamp DOUBLE)" ) #Grab all shares past the client timestamp c.execute("SELECT * FROM secrets WHERE timestamp > ?", [float(timestamp)]) d = c.fetchall() #For each share for i in range(len(d)): #convert the share to a string d[i] = d[i]["id"] + "|" + d[i]["name"] + "|" + d[i][ "secret"] + "|" + str(d[i]['timestamp']) #join all the shares and add them to the db string data += "::".join(d) #send the databases to the client and exit s.send(aes_crypt.aes_enc(rsa_encrypt.get_pub_key_auth(), data)) return 0