def generate_keys(): dh = DiffieHellman() private_key, public_key = dh.get_private_key(), dh.gen_public_key() return jsonify({ "private_key": private_key, "public_key": public_key, })
class Person35(Person34): def start(self): print self.name, 'Starting experiment' self.dh = DiffieHellman() self.other.rcv_msg1(self.dh.p, self.dh.g) def rcv_msg1(self, p, g): self.dh = DiffieHellman(p=p, g=g) self.other_dh = DiffieHellman(p=p, g=g) self.other.rcv_msg2('ACK') def rcv_msg2(self, msg): assert msg == 'ACK' self.other.rcv_msg3(self.dh.public) def rcv_msg3(self, A): self.other_dh.public = A print self.name, 'generating shared secret' self.shared_secret = self.dh.exchange(self.other_dh) self.key = self.make_key(self.shared_secret) self.other.rcv_msg4(self.dh.public) def rcv_msg4(self, B): self.other_dh = DiffieHellman(p=self.dh.p, g=self.dh.g, public=B) print self.name, 'generating shared secret' self.shared_secret = self.dh.exchange(self.other_dh) self.key = self.make_key(self.shared_secret) iv = keygen() enc_iv = cbc_encrypt(self.msg, self.key, iv) + iv print self.name, 'sending', self.msg self.other.rcv_msg5(enc_iv) def rcv_msg5(self, enc_iv): rec_iv = enc_iv[-16:] rec_enc = enc_iv[:-16] rec_msg = cbc_decrypt(rec_enc, self.key, rec_iv) print self.name, 'received', rec_msg iv = keygen() enc = cbc_encrypt(rec_msg, self.key, iv) print self.name, 'sending', rec_msg self.other.rcv_msg6(enc + iv) def rcv_msg6(self, enc_iv): iv = enc_iv[-16:] enc = enc_iv[:-16] msg = cbc_decrypt(enc, self.key, iv) print self.name, 'received', msg
def logInUser(self, **kwargs): """Server Side logIn User User sends his username (Unique Identifier) and his password Security: Message from user ciphered with Server Public Key Session Management: Create a Public Key with DiffieHellman""" # Decipher the Message with Server Private Key receivedData = dm.decryptMessageReceived(kwargs['data'].decode('hex')) print receivedData['userID'] # Verify if the user exists and has finished the regist process if DBmodule.db_registAuthenticate(receivedData['userID']) and \ DBmodule.db_getLogIn(receivedData['userID'], receivedData['password']) == 1: # Create Session print receivedData['userID'] print receivedData['password'] serverSession = DiffieHellman.DiffieHellman() # Create challenge token = os.urandom(20) um.addSession(receivedData['userID'], serverSession, token) # Send to client the Token and the session public key tf = tempfile.NamedTemporaryFile(delete=True) pub_key = DBmodule.db_getUserPubKey( DBmodule.db_getUserID(receivedData['userID'])).decode('hex') security.encrypt_RSA(security.importkey_RSA(pub_key), token, tf) messageToSend = { 'token': tf.read().encode('hex'), 'session': serverSession.publicKey } return json.dumps(messageToSend) elif DBmodule.db_registNotAuthenticate(receivedData['userID']): return "REGIST_AGAIN" else: return "ERROR"
def request_start_dh(data): """Client is requesting a communication. Receive P and G for Diffie-Hellman """ STORAGE['dh'] = DiffieHellman(p_g=data) logger.info('Client connected. Recieved DH request, sending public key') return 'MY_PUBLIC,{0}'.format(STORAGE['dh'].get_my_public())
def rcv_msg4(self, B): self.other_dh = DiffieHellman(p=self.dh.p, g=self.dh.g, public=B) print self.name, 'generating shared secret' self.shared_secret = self.dh.exchange(self.other_dh) self.key = self.make_key(self.shared_secret) iv = keygen() enc_iv = cbc_encrypt(self.msg, self.key, iv) + iv print self.name, 'sending', self.msg self.other.rcv_msg5(enc_iv)
def generate_shared_key(): try: local_private_key = request.args.get("local_private_key") remote_public_key = request.args.get("remote_public_key") except: return jsonify({"message": "Invalid parameters"}), 400 try: shared_key = DiffieHellman.gen_shared_key_static( local_private_key, remote_public_key) except: return jsonify({"message": "Invalid public key"}), 400 return jsonify({"shared_key": shared_key})
def BeginExchange(self, data): self.match_nonce = os.urandom(SafeSlingerExchange.NONCE_LEN) self.wrong_nonce = os.urandom(SafeSlingerExchange.NONCE_LEN) # match_extrahash = sha3(match_nonce) self.match_extrahash = CryptoEngine.sha3_digest(self.match_nonce) # wrong_hash = sha3(wrong_nonce) self.wrong_hash = CryptoEngine.sha3_digest(self.wrong_nonce) # match_hash = sha3(match_extrahash) self.match_hash = CryptoEngine.sha3_digest(self.match_extrahash) # encrypted_data = aes_cbc(enckey, exchange_data) self.encrypted_data = CryptoEngine.aes256_cbc_encryption(data, self.match_nonce) #compute protocol_commitment = sha3(match_hash||wrong_hash) self.protocol_commitment = CryptoEngine.sha3_digest(self.match_hash + self.wrong_hash) # generate Diffie Hellman Key self.dhkey = DiffieHellman() self.dhpubkey = self.dhkey.getHexData(self.dhkey.publicKey).strip() self.dhkey_len = len(self.dhpubkey) # data_commitment = sha3(protocol_commitment||DHPubKey||encrypted_data) self.data_commitment = CryptoEngine.sha3_digest(self.protocol_commitment+self.dhpubkey+self.encrypted_data) # initialize network object self.httpclient = HTTPClient(self.address)
def configure(self, data): p, g, ya, xb, yb, zz = [data[key] for key in ('P', 'G', 'YstatCAVS', 'XstatIUT', 'YstatIUT', 'Z')] dh = DiffieHellman(g, p, ya) dh.my_private_key = xb return dh, yb, zz
def start(self): print self.name, 'Starting experiment' self.dh = DiffieHellman() self.other.rcv_msg1(self.dh.p, self.dh.g)
def logInUser(userID, password, card): """Function for Logging into the server. handled server-side Security: Encrypted with Server Public Key """ register_openers().add_handler( urllib2.HTTPCookieProcessor(cookielib.CookieJar())) try: pwd = security.PBKDKF2.pwsend(password) params = {'userID': userID, 'password': pwd} sendparam = encryptMessageToSendRSA(params) datagen, headers = multipart_encode(sendparam) request = urllib2.Request('https://localhost:8080/logInUser', datagen, headers) result = urllib2.urlopen(request).read() if result == "ERROR": return False elif result == "REGIST_AGAIN": return False else: clientSession = DiffieHellman.DiffieHellman() # receive token and decrypt it with private_file = os.path.join('PrivateKeys', 'Private_key_' + str(userID)) with open(private_file, 'rb') as f: private_key = security.importkey_RSA(f.read()) loginMessage = json.loads(result) receivedMessage = security.decrypt_RSA( private_key, loginMessage['token'].decode('hex')) # sign token """ -----------------SIGN CC/PrivateKey By PWD -------------------- """ reply = card.connect(0l) if reply: tokenSigned = card.sign(receivedMessage) card.disconnect() else: tokenSigned = "" """ -----------------SIGN CC/PrivateKey By PWD -------------------- """ message = {'userID': userID, 'password': pwd} # send token back tokenchiphered = encryptMessageToSendRSA( {'token': tokenSigned}) sendparam = encryptMessageToSendRSA(message) messageToSend = { 'message': sendparam, 'session': json.dumps(clientSession.publicKey), 'token': tokenchiphered } datagen, headers = multipart_encode(messageToSend) request = urllib2.Request( 'https://localhost:8080/authTokenValidation', datagen, headers) result = urllib2.urlopen(request).read() if result == "OK": # Establish Session clientSession.genKey(loginMessage['session']) destination = os.path.join('download', 'session.txt') user = User(userID, clientSession.getKey().encode('hex')) print "Logged In: " + str(userID) return user return False except urllib2.URLError as e: print e.reason print 'Currently, you are not a valid user!\nSafeBox Team' return False
def rcv_msg1(self, p, g): self.dh = DiffieHellman(p=p, g=g) self.other_dh = DiffieHellman(p=p, g=g) self.other.rcv_msg2('ACK')
def client(): """Client mode work flow.""" downlink = Connection('downlink', 'r') uplink = Connection('uplink', 'w+') # Establish connection dh = DiffieHellman() p, g = dh.get_pg() uplink.send('INIT,{0},{1}'.format(p, g)) response = get_response(downlink, 'MY_PUBLIC', 2, 'Failed to authenticate via DH') public = dh.get_my_public() uplink.send('MY_PUBLIC,{0}'.format(public)) key = dh.compute_shared(response[1]) logging.debug('Key established: {0}'.format(key.hexdigest())) # Start encrypted communication response = get_response(downlink, 'AES', 2, 'Failed to start AES') aes = AES.new(key.digest(), AES.MODE_CBC, b64decode(response[1])) # Verify identity using FFS while True: ffs = FFSProver() # Send X msg = msg_encrypt(aes, str(ffs.get_x())) uplink.send('FFS_X,{0}'.format(msg)) # Get A vector response = get_response(downlink, 'FFS_A', 2, 'Failed to verify identity via FFS') a_vector = [int(a) for a in msg_decrypt(aes, response[1])] # Solve Y msg = msg_encrypt(aes, str(ffs.solve(a_vector))) uplink.send('FFS_Y,{0}'.format(msg)) # Get result response = next(downlink.receive()) if response not in ('FFS_OK', 'FFS_DONE'): raise RuntimeError('Failed to verify identity via FFS') if response == 'FFS_DONE': break # Send messages print('Connection established, communication channel open.') print('If you want to end this program press CTRL(C') while True: # Snd message raw_msg = raw_input('Enter message: ') msg = msg_encrypt(aes, raw_msg) uplink.send('MSG,{0}'.format(msg)) # Get response response = next(downlink.receive()) response = response.split(',') if len(response) != 2 or response[0] != 'SHA256': raise RuntimeError('Channel compromised') # Compare Hashes our_hash = sha256(raw_msg).hexdigest() their_hash = msg_decrypt(aes, response[1]) print('Recieved: ' + their_hash) if their_hash != our_hash: print('Hash mismatch!') raise RuntimeError('Channel compromised') else: print('Hash matches')
def associate(self): assoc_type = request.form.get('openid.assoc_type') if assoc_type not in ('HMAC-SHA1', 'HMAC-SHA256'): return err_response( error="Unknown association type requested", error_code="unsupported-type", assoc_type="HMAC-SHA256", session_type="DH-SHA256", ) session_type = request.form.get('openid.session_type') if session_type == 'no-encryption': # TODO: support no-encryption if we can tell we're on SSL? return err_response( error="Session type no-encryption is not supported on non-HTTPS connections", error_code="unsupported-type", assoc_type="HMAC-SHA256", session_type="DH-SHA256", ) if session_type not in ('DH-SHA1', 'DH-SHA256'): return err_response( error="Unknown session type requested", error_code="unsupported-type", assoc_type="HMAC-SHA256", session_type="DH-SHA256", ) mac_key = os.urandom(20 if assoc_type == 'HMAC-SHA1' else 32) assoc_handle = b64encode(os.urandom(20)) expires = datetime.utcnow() + timedelta(seconds=1000) logging.debug("Formed a shared association %s with key %r!", assoc_handle, mac_key) cur = g.db_conn.cursor() cur.execute("INSERT INTO openid_associations (handle, private, secret, assoc_type, expires) VALUES (%s, false, %s, %s, %s)", (assoc_handle, bytearray(mac_key), assoc_type, expires)) g.db_conn.commit() cur.close() dh_mod = request.form.get('openid.dh_modulus') dh_gen = request.form.get('openid.dh_gen') if dh_mod is not None: dh_mod = unbtwoc(b64decode(dh_mod)) if dh_gen is not None: dh_gen = unbtwoc(b64decode(dh_gen)) try: dh_consumer_public = request.form['openid.dh_consumer_public'] except KeyError: return err_response(error="Required parameter dh_consumer_public not provided") dh_consumer_public = unbtwoc(b64decode(dh_consumer_public)) dh = DiffieHellman(dh_gen, dh_mod, dh_consumer_public) dh.select_key() dh_server_public = b64encode(btwoc(dh.calculate_public_key())) dh_secret = dh.calculate_secret() logging.debug("Calculated our shared secret is %r", dh_secret) hasher = hashlib.sha1 if session_type == 'DH-SHA1' else hashlib.sha256 hashed_session_key = hasher(btwoc(dh_secret)).digest() logging.debug("Hashed session key is %r", hashed_session_key) cipher_key_bytes = xor(hashed_session_key, mac_key) logging.debug("Ciphered key bytes are %r", cipher_key_bytes) enc_mac_key = b64encode(cipher_key_bytes) logging.debug("Base64-encoded ciphered key bytes are %r", enc_mac_key) return direct_response( assoc_type=assoc_type, session_type=session_type, assoc_handle=assoc_handle, expires_in=1000, dh_server_public=dh_server_public, enc_mac_key=enc_mac_key, )
msg, addr = sock.recvfrom(1024) data = unwrap(msg, crypto.DEFAULT_KEY) assert(data is not None) assert(len(data['chunks']) == 1) RHello = data['chunks'][0] if RHello[0] != 0x70: print hexlify(msg), data assert(RHello[0] == 0x70) assert(RHello[1] == len(RHello[2])) (taglen, msg) = vread(RHello[2]) assert(taglen == 16) assert(msg[:16] == '0123456789ABCDEF') (cookielen, msg) = vread(msg[16:]) cookie = msg[:cookielen] # ignore RHello options, the server will be using an ephemeral key dh = DiffieHellman() pcert = '\x1d\x02' + packl(dh.publicKey) pcert = vwrite(len(pcert)) + pcert sknc = '\x02\x1d\x02\x03\x1a\x00\x00\x02\x1e\x00' msg = '1234' + vwrite(cookielen) + cookie + vwrite(len(pcert)) + pcert + vwrite(len(sknc)) + sknc + 'X' IIKeying = prep("\x38" + struct.pack('!H', len(msg)) + msg, 0, 3, crypto.DEFAULT_KEY) sock.sendto(IIKeying, (UDP_IP, UDP_PORT)) msg, addr = sock.recvfrom(1024) data = unwrap(msg, crypto.DEFAULT_KEY) assert(data is not None) assert(len(data['chunks']) == 1) RIKeying = data['chunks'][0] assert(RIKeying[0] == 0x78) assert(RIKeying[1] == len(RIKeying[2]))
import hashlib import secrets from dh import DiffieHellman def gen_hmac(msg, key): # takes ints return hashlib.sha256((str(key) + str(msg)).encode()).hexdigest() def test_hmac(msg, key, hmac): # takes ints return hashlib.sha256((str(key) + str(msg)).encode()).hexdigest() == hmac C = DiffieHellman( int( "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff", 16), 2) # A S = DiffieHellman( int( "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff", 16), 2) # B # client and server agree beforehand N = int( "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff", 16) g = 2 k = 3 I = "*****@*****.**" P = "password"
def GroupDHComputation(self): # Doing DH group key construction position = 0 currentKeyNodeNumber = 0 firstKeynode = True self.uidSet.sort() for x in self.uidSet: if x == self.userID: break else: position += 1 # If position 1 or 0 # print "position = %d" % position if position < 2: # If 1 set keynode 1 to be pubkey 0 and vice versa currentKeyNodeNumber = 2 self.keyNodes[1] = bytearray(self.dhpubkeySet[self.uidSet[1-position]]) else: # Check if you have the keynode corresponding to you position. try: elem = self.keyNodes[position] except KeyError: datagram = self.httpclient.sync_keynodes(self.userID) self.handleSyncKeyNodes(datagram) return currentKeyNodeNumber = position+1 currentKeynode = DiffieHellman() sharedKey = None while currentKeyNodeNumber <= len(self.uidSet): #For the first keynode that you generate use your private key and keynode as public key if firstKeynode: pubKey = int(binascii.hexlify(self.keyNodes[currentKeyNodeNumber-1]), 16) sharedKey = self.dhkey.genSecret(self.dhkey.privateKey, pubKey) firstKeynode = False else: pubKey = int(binascii.hexlify(bytearray(self.dhpubkeySet[self.uidSet[currentKeyNodeNumber-1]])), 16) sharedKey = self.dhkey.genSecret(currentKeynode.privateKey, pubKey) # Storing generated shared key in DH struct for key node, currentKeynode->priv_key = sharedKey currentKeynode.privateKey = sharedKey # If position 1 or 0 if position < 2 and currentKeyNodeNumber < len(self.uidSet): # Send exponentiated keynode to server expKeyNode = pow(currentKeynode.generator, currentKeynode.privateKey, currentKeynode.prime) hex_string = hex(expKeyNode) expKeyNodeRaw = hex_string[2:-1].decode("hex") datagram = self.httpclient.sync_requestkeynodes(self.userID, self.uidSet[currentKeyNodeNumber], expKeyNodeRaw) currentKeyNodeNumber += 1 # compute group DH key hex_string = hex(sharedKey).strip() #print "sharedKey: %s" % hex_string[2:-1] self.groupkey = hex_string[2:-1].decode("hex") del sharedKey self.SyncMatch()
class SafeSlingerExchange: # constants MINI_USERS = 2 NONCE_LEN = 32 def __init__(self, address="slinger-dev.appspot.com"): # networking object self.version = 1 << 24 | 8 << 16 self.address = address self.httpclient = None # predefined data structures self.match_nonce = None self.wrong_nonce = None self.match_extrahash = None self.match_hash = None self.encrypted_data = None self.protocol_commitment = None self.dhkey = None self.dhpubkey = None self.data_commitment = None self.num_users = 0 self.userID = None self.correct_index = -1 self.selected_index = -1 self.dhkey_len = -1 self.groupkey = None self.uidSet = [] self.dataCommitmentSet = {} self.protoCommitmentSet = {} self.dhpubkeySet = {} self.receivedcipherSet = {} self.matchExtraHashSet = {} self.wrongHashSet = {} self.matchHashSet = {} self.keyNodes = {} self.matchNonceSet = {} # load dictionary files ins = open( "odd-dict.txt", "r" ) self.odd_array = [] for line in ins: self.odd_array.append( line.rstrip() ) ins.close() ins = open( "even-dict.txt", "r" ) self.even_array = [] for line in ins: self.even_array.append( line.rstrip() ) ins.close() def SelecGroupSize(self): while True: try: numUsers = int(raw_input("How many users in the exchange? [2-10] ")) if numUsers >= 2 and numUsers <=10: self.num_users = numUsers break else: print "A minimum of %d members are required to exchange data." % SafeSlingerExchange.MINI_USERS except Exception: print "A minimum of %d members are required to exchange data." % SafeSlingerExchange.MINI_USERS def BeginExchange(self, data): self.match_nonce = os.urandom(SafeSlingerExchange.NONCE_LEN) self.wrong_nonce = os.urandom(SafeSlingerExchange.NONCE_LEN) # match_extrahash = sha3(match_nonce) self.match_extrahash = CryptoEngine.sha3_digest(self.match_nonce) # wrong_hash = sha3(wrong_nonce) self.wrong_hash = CryptoEngine.sha3_digest(self.wrong_nonce) # match_hash = sha3(match_extrahash) self.match_hash = CryptoEngine.sha3_digest(self.match_extrahash) # encrypted_data = aes_cbc(enckey, exchange_data) self.encrypted_data = CryptoEngine.aes256_cbc_encryption(data, self.match_nonce) #compute protocol_commitment = sha3(match_hash||wrong_hash) self.protocol_commitment = CryptoEngine.sha3_digest(self.match_hash + self.wrong_hash) # generate Diffie Hellman Key self.dhkey = DiffieHellman() self.dhpubkey = self.dhkey.getHexData(self.dhkey.publicKey).strip() self.dhkey_len = len(self.dhpubkey) # data_commitment = sha3(protocol_commitment||DHPubKey||encrypted_data) self.data_commitment = CryptoEngine.sha3_digest(self.protocol_commitment+self.dhpubkey+self.encrypted_data) # initialize network object self.httpclient = HTTPClient(self.address) def AssignUser(self): datagram = self.httpclient.assign_user(self.data_commitment) userID = (struct.unpack("!i", datagram[0:4]))[0] self.userID = userID # store parameters self.dataCommitmentSet[userID] = self.data_commitment self.protoCommitmentSet[userID] = self.protocol_commitment self.dhpubkeySet[userID] = self.dhpubkey self.receivedcipherSet[userID] = self.encrypted_data print ("Assigned ID = %d.\n\nThis number is used to create a unique group of users. Compare, and then enter the lowest number." % self.userID ) def SelectLowestNumber(self): low_num = -1 while True: try: low_num = int(raw_input("Enter Lowest Number: ")) if low_num > 0: break else: print 'Please enter a positive integer.' except Exception: print 'Please enter a positive integer.' print "%d users, Lowest %d\nRequesting Membership..." % (self.num_users, low_num) numUsers_Recv = 1 self.uidSet[:] = [] self.uidSet.insert(0, self.userID) retry = 0 while (numUsers_Recv < self.num_users): datagram = self.httpclient.send_minid(self.userID, low_num, self.uidSet, self.data_commitment) minVersion = (struct.unpack("!i", datagram[0:4]))[0] count = (struct.unpack("!i", datagram[4:8]))[0] delta_count = (struct.unpack("!i", datagram[8:12]))[0] # Collect all data commitments Ci from other users if delta_count > 0: offset = 12 for i in range(delta_count): uid = (struct.unpack("!i", datagram[offset:offset+4]))[0] self.uidSet.append(uid) offset += 4 commitLen = (struct.unpack("!i", datagram[offset:offset+4]))[0] offset += 4 self.dataCommitmentSet[uid] = struct.unpack("%dB" %commitLen, datagram[offset:offset+commitLen]) offset += commitLen numUsers_Recv += 1 print "Received (%d/%d) Items" % (numUsers_Recv, self.num_users-1) retry += 1 time.sleep(retry) if retry >= 10: print "Error: reached maximum retries" quit() self.SyncData() def SyncData(self): print "Waiting for all users to join..." numUsers_Recv = 1 self.uidSet[:] = [] self.uidSet.insert(0, self.userID) retry = 0 while (numUsers_Recv < self.num_users): datagram = self.httpclient.sync_data(self.userID, self.uidSet, self.protocol_commitment, self.dhpubkey, self.encrypted_data) count = (struct.unpack("!i", datagram[0:4]))[0] delta_count = (struct.unpack("!i", datagram[4:8]))[0] # Collect all data commitments Ci from other users if delta_count > 0: offset = 8 for i in range(delta_count): uid = (struct.unpack("!i", datagram[offset:offset+4]))[0] self.uidSet.append(uid) offset += 4 # proto commitment total_len = (struct.unpack("!i", datagram[offset:offset+4]))[0] offset += 4 self.protoCommitmentSet[uid] = struct.unpack("%dB" % SafeSlingerExchange.NONCE_LEN, datagram[offset:offset+SafeSlingerExchange.NONCE_LEN]) offset += SafeSlingerExchange.NONCE_LEN #dhkey self.dhpubkeySet[uid] = struct.unpack("%dB" % self.dhkey_len, datagram[offset:offset+self.dhkey_len]) offset += self.dhkey_len # encrypted_dataSet encrypted_len = total_len-SafeSlingerExchange.NONCE_LEN-self.dhkey_len self.receivedcipherSet[uid] = struct.unpack("%dB" % encrypted_len, datagram[offset:offset+encrypted_len]) offset += encrypted_len numUsers_Recv += 1 print "Received (%d/%d) commitments" % (numUsers_Recv, self.num_users) retry += 1 time.sleep(retry) if retry >= 10: print "Error: reached maximum retries" quit() def Compute3Wordphrases(self): #compute 3-word phrases, step 1 compute hash total_len = 0 self.uidSet.sort() buffer = bytearray() for x in self.uidSet: buffer.extend(self.protoCommitmentSet[x]) buffer.extend(self.dhpubkeySet[x]) buffer.extend(self.receivedcipherSet[x]) #print 'buffer: ', binascii.hexlify(buffer) wordhash = CryptoEngine.sha3_digest(bytes(buffer)) #print 'word hash: ', binascii.hexlify(wordhash) del buffer # generate 3-word phrases hashint = [0, 0, 0, 0, 0, 0] # create empty byte array evenVec = bytearray(256) oddVec = bytearray(256) evenVec[ord(wordhash[0])] = 1 # set to True oddVec[ord(wordhash[1])] = 1 evenVec[ord(wordhash[2])] = 1 # essentially need to sort list of user ids first # generate wordlist for every user id up to ours # then generate our wordlist count = 0 foundUser = False hasharray = None decoy1 = None decoy2 = None for x in self.uidSet: if x == self.userID: foundUser = True # unsigned char *buf = malloc(HASHLEN + 1); buf = bytearray() buf.append(count) buf.extend(wordhash) whash = CryptoEngine.sha3_digest(bytes(buf)) hasharray = bytearray(whash) del buf # 2 decoy wordlists for each user for d in range(2): while evenVec[hasharray[0 + 3*d]] == 1: if hasharray[0 + 3*d] == 255: hasharray[0 + 3*d] = hasharray[0 + 3*d] - 255 else: hasharray[0 + 3*d] = hasharray[0 + 3*d] + 1 while oddVec[hasharray[1 + 3*d]] == 1: if hasharray[1 + 3*d] == 255: hasharray[1 + 3*d] = hasharray[1 + 3*d] - 255 else: hasharray[1 + 3*d] = hasharray[1 + 3*d] + 1 while evenVec[hasharray[2+ 3*d]] == 1: if hasharray[2 + 3*d] == 255: hasharray[2 + 3*d] = hasharray[2 + 3*d] - 255 else: hasharray[2 + 3*d] = hasharray[2 + 3*d] + 1 #print 'modified hasharray hash: ', binascii.hexlify(hasharray), 'len:', len(hasharray) evenVec[hasharray[0+3*d]] = 1 oddVec[hasharray[1+3*d]] = 1 evenVec[hasharray[2+3*d]] = 1 # compute decoy strings only if user is found if (d == 0) and (foundUser == True): hashint[0] = hasharray[0] hashint[1] = hasharray[1] hashint[2] = hasharray[2] decoy1 = "%s %s %s" % (self.even_array[hashint[0]], self.odd_array[hashint[1]], self.even_array[hashint[2]]) elif foundUser == True: hashint[3] = hasharray[3] hashint[4] = hasharray[4] hashint[5] = hasharray[5] decoy2 = "%s %s %s" %(self.even_array[hashint[3]], self.odd_array[hashint[4]], self.even_array[hashint[5]]) #end of d loop if foundUser == True: break count = count + 1 #end of x loop # to set the correct wordlist at some random position self.correct_index = random.randint(0, sys.maxint) % 3 #print 'correct_index = ', self.correct_index d1Added = False wordlist_labels = [] numberlist_labels = [] hashbytes = bytearray(wordhash) number = 0 # numeric labels for i in range(3): numberstr = '' if i == self.correct_index: for j in range(3): number = hashbytes[j] if (j % 2) != 0: number = number + 256 number = number + 1 numberstr = numberstr+"%d "%(number) else: if not d1Added: for j in range(3): number = hashint[j] if (j % 2) != 0: number = number + 256 number = number + 1 numberstr = numberstr+"%d "%(number) d1Added = True else: for j in range(3): number = hashint[j+3] if (j % 2) != 0: number = number + 256 number = number + 1 numberstr = numberstr+"%d "%(number) numberlist_labels.append(numberstr) d1Added = False for i in range(3): if i == self.correct_index: # correct phrases correct_phrase = "%s %s %s" % (self.even_array[hashbytes[0]], self.odd_array[hashbytes[1]], self.even_array[hashbytes[2]]) wordlist_labels.append(correct_phrase) else: if not d1Added: wordlist_labels.append(decoy1) d1Added = True else: wordlist_labels.append(decoy2) print "All phones must match one of the 3-word phrases. Compare, and then pick the matching phrase." print "[-1]: No Match." for i in range(3): print "[%d]: %s (%s)" % (i, wordlist_labels[i], numberlist_labels[i]) while True: try: idx = int(raw_input("Enter the index number to show your decision:")) if idx <= 2 and idx >= -1 : self.selected_index = idx break else: print 'Enter a correct index!' except Exception: print 'Not an integer number!' print "Waiting for verification from all members..." def PhrasesVerification(self): if self.selected_index == self.correct_index: numUsers_Recv = 1 del self.uidSet[:] self.uidSet.insert(0, self.userID) while (numUsers_Recv < self.num_users): datagram = self.httpclient.sync_signatures(self.userID, self.uidSet, self.match_extrahash, self.wrong_hash) # match_extrahash || wrong_hash count = (struct.unpack("!i", datagram[0:4]))[0] delta_count = (struct.unpack("!i", datagram[4:8]))[0] # Collect all data commitments Ci from other users if delta_count > 0: offset = 8 for i in range(delta_count): uid = (struct.unpack("!i", datagram[offset:offset+4]))[0] self.uidSet.append(uid) offset += 4 # proto commitment total_len = (struct.unpack("!i", datagram[offset:offset+4]))[0] offset += 4 # Nmh Nmh = struct.unpack("%dB" % SafeSlingerExchange.NONCE_LEN, datagram[offset:offset+SafeSlingerExchange.NONCE_LEN]) offset += SafeSlingerExchange.NONCE_LEN # Sha3Nmh Sha3Nmh = CryptoEngine.sha3_digest(bytes(bytearray(Nmh))) # wH wH = struct.unpack("%dB" % SafeSlingerExchange.NONCE_LEN, datagram[offset:offset+SafeSlingerExchange.NONCE_LEN]) offset += SafeSlingerExchange.NONCE_LEN buf = bytearray(Sha3Nmh) buf.extend(wH) cPC = CryptoEngine.sha3_digest(bytes(buf)) del buf rPC = self.protoCommitmentSet[uid] # verify if protocol commitments match # also make sure that neither is nil if cPC == bytearray(rPC): print "Recievd (%d/%d) Match nonces" % (numUsers_Recv, self.num_users) self.matchExtraHashSet[uid] = Nmh self.wrongHashSet[uid] = wH self.matchHashSet[uid] = Sha3Nmh else: print "Someone reported a difference in phrases. Begin the exchange again." return False numUsers_Recv += 1 return True else: ret = self.httpclient.sync_signatures(self.userID, self.uidSet, self.match_hash, self.wrong_nonce) return False def handleSyncKeyNodes(self, datagram): position = 0 for x in self.uidSet: if x == self.userID: break else: position += 1 if position == 0 or position == 1: return else: keyNodeFound = (struct.unpack("!i", datagram[0:4]))[0] if keyNodeFound > 0: keyNodeLen = (struct.unpack("!i", datagram[4:8]))[0] keyNodeData = struct.unpack("%dB" % keyNodeLen, datagram[8:8+keyNodeLen]) self.keyNodes[position] = bytearray(keyNodeData) self.GroupDHComputation() else: datagram = self.httpclient.sync_keynodes(self.userID) self.handleSyncKeyNodes(datagram) def GroupDHComputation(self): # Doing DH group key construction position = 0 currentKeyNodeNumber = 0 firstKeynode = True self.uidSet.sort() for x in self.uidSet: if x == self.userID: break else: position += 1 # If position 1 or 0 # print "position = %d" % position if position < 2: # If 1 set keynode 1 to be pubkey 0 and vice versa currentKeyNodeNumber = 2 self.keyNodes[1] = bytearray(self.dhpubkeySet[self.uidSet[1-position]]) else: # Check if you have the keynode corresponding to you position. try: elem = self.keyNodes[position] except KeyError: datagram = self.httpclient.sync_keynodes(self.userID) self.handleSyncKeyNodes(datagram) return currentKeyNodeNumber = position+1 currentKeynode = DiffieHellman() sharedKey = None while currentKeyNodeNumber <= len(self.uidSet): #For the first keynode that you generate use your private key and keynode as public key if firstKeynode: pubKey = int(binascii.hexlify(self.keyNodes[currentKeyNodeNumber-1]), 16) sharedKey = self.dhkey.genSecret(self.dhkey.privateKey, pubKey) firstKeynode = False else: pubKey = int(binascii.hexlify(bytearray(self.dhpubkeySet[self.uidSet[currentKeyNodeNumber-1]])), 16) sharedKey = self.dhkey.genSecret(currentKeynode.privateKey, pubKey) # Storing generated shared key in DH struct for key node, currentKeynode->priv_key = sharedKey currentKeynode.privateKey = sharedKey # If position 1 or 0 if position < 2 and currentKeyNodeNumber < len(self.uidSet): # Send exponentiated keynode to server expKeyNode = pow(currentKeynode.generator, currentKeynode.privateKey, currentKeynode.prime) hex_string = hex(expKeyNode) expKeyNodeRaw = hex_string[2:-1].decode("hex") datagram = self.httpclient.sync_requestkeynodes(self.userID, self.uidSet[currentKeyNodeNumber], expKeyNodeRaw) currentKeyNodeNumber += 1 # compute group DH key hex_string = hex(sharedKey).strip() #print "sharedKey: %s" % hex_string[2:-1] self.groupkey = hex_string[2:-1].decode("hex") del sharedKey self.SyncMatch() def SyncMatch(self): self.match_nonce = CryptoEngine.aes256_cbc_encryption(self.match_nonce, self.groupkey) numUsers_Recv = 1 del self.uidSet[:] self.uidSet.insert(0, self.userID) retry = 0 while (numUsers_Recv < self.num_users): datagram = self.httpclient.sync_match(self.userID, self.uidSet, self.match_nonce) count = (struct.unpack("!i", datagram[0:4]))[0] delta_count = (struct.unpack("!i", datagram[4:8]))[0] # Collect all data commitments Ci from other users if delta_count > 0: offset = 8 for i in range(delta_count): uid = (struct.unpack("!i", datagram[offset:offset+4]))[0] self.uidSet.append(uid) offset += 4 total_len = (struct.unpack("!i", datagram[offset:offset+4]))[0] offset += 4 keyNonce = struct.unpack("%dB" % total_len, datagram[offset:offset+total_len]) keyNonce = CryptoEngine.aes256_cbc_decryption(keyNonce, self.groupkey) nh = CryptoEngine.sha3_digest(bytes(keyNonce)) meh = self.matchExtraHashSet[uid] if nh == bytearray(meh): self.matchNonceSet[uid] = keyNonce else: print "An error occurred during commitment verification." quit() offset += total_len numUsers_Recv += 1 retry += 1 time.sleep(retry) if retry >= 10: print "Error: reached maximum retries" quit() def ObtainGatherData(self): # decrypted the final data _decrypted = {} for x in self.uidSet: if x == self.userID: continue individualData = CryptoEngine.aes256_cbc_decryption(self.receivedcipherSet[x], self.matchNonceSet[x]) _decrypted[x] = individualData return _decrypted def __del__(self): self.httpclient.close() del self.httpclient # predefined data structures del self.match_nonce del self.wrong_nonce del self.match_extrahash del self.match_hash del self.encrypted_data del self.protocol_commitment del self.dhkey del self.data_commitment del self.userID del self.groupkey del self.uidSet del self.dataCommitmentSet del self.protoCommitmentSet del self.dhpubkeySet del self.receivedcipherSet del self.matchExtraHashSet del self.wrongHashSet del self.matchHashSet del self.keyNodes del self.matchNonceSet # load dictionary files del self.odd_array del self.even_array
import hashlib import secrets from Crypto.Cipher import AES from dh import DiffieHellman # normal protocol alice = DiffieHellman(int("ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff", 16), 2) bob = DiffieHellman(int("ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff", 16), 2) p = alice.p g = alice.g A = alice.get_public_key() B = bob.get_public_key() s = alice.get_shared_key(B) key = hashlib.sha256(s.to_bytes(2 ** 16, "little")).hexdigest()[:32] # 16 bytes alice_iv = secrets.token_bytes(16) bob_iv = secrets.token_bytes(16) alice_cipher = AES.new(bytes.fromhex(key), AES.MODE_CBC, alice_iv) alice_to_bob = alice_cipher.encrypt(b"YELLOW SUBMARINE") + alice_iv print(alice_to_bob) bob_cipher = AES.new(bytes.fromhex(key), AES.MODE_CBC, alice_to_bob[-16:]) bob_decrypted = bob_cipher.decrypt(alice_to_bob) print(bob_decrypted) bob_cipher = AES.new(bytes.fromhex(key), AES.MODE_CBC, bob_iv) bob_to_alice = bob_cipher.encrypt(bob_decrypted[:-16]) + bob_iv print(bob_to_alice) # mitm attack alice = DiffieHellman(int("ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff", 16), 2) bob = DiffieHellman(int("ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff", 16), 2) p = alice.p g = alice.g
msg, addr = sock.recvfrom(1024) data = unwrap(msg, crypto.DEFAULT_KEY) assert (data is not None) assert (len(data['chunks']) == 1) RHello = data['chunks'][0] if RHello[0] != 0x70: print hexlify(msg), data assert (RHello[0] == 0x70) assert (RHello[1] == len(RHello[2])) (taglen, msg) = vread(RHello[2]) assert (taglen == 16) assert (msg[:16] == '0123456789ABCDEF') (cookielen, msg) = vread(msg[16:]) cookie = msg[:cookielen] # ignore RHello options, the server will be using an ephemeral key dh = DiffieHellman() pcert = '\x1d\x02' + packl(dh.publicKey) pcert = vwrite(len(pcert)) + pcert sknc = '\x02\x1d\x02\x03\x1a\x00\x00\x02\x1e\x00' msg = '1234' + vwrite(cookielen) + cookie + vwrite( len(pcert)) + pcert + vwrite(len(sknc)) + sknc + 'X' IIKeying = prep("\x38" + struct.pack('!H', len(msg)) + msg, 0, 3, crypto.DEFAULT_KEY) sock.sendto(IIKeying, (UDP_IP, UDP_PORT)) msg, addr = sock.recvfrom(1024) data = unwrap(msg, crypto.DEFAULT_KEY) assert (data is not None) assert (len(data['chunks']) == 1) RIKeying = data['chunks'][0]