def stringReceived(self, encryptedMsg): self.responseReceived = True self.transport.loseConnection() blob = self.factory.bank.decrypt_message(encryptedMsg) log_msg("ACoin REQUEST response received.", 4) responseCode, blob = Basic.read_byte(blob) #we had enough credits in our account if responseCode == 0: (newBalance, number), coins = Basic.read_message('!II', blob) #update the balance self.factory.bank.on_new_balance_from_bank(newBalance) acoinStrFormat = "%ss" % (Globals.ACOIN_KEY_BYTES) format = '!' + (acoinStrFormat * number) sigs = list(struct.unpack(format, coins)) while len(self.factory.requests) > 0: request = self.factory.requests.pop(0) sig = sigs.pop(0) coin = BankMessages.parse_acoin_response(self.factory.bank, sig, request, ProgramState.DEBUG) if coin: self.factory.bank.add_acoin(coin) else: log_msg("Got an invalid ACoin from the bank!?", 3) #the bank could not check out the coins because our account doesn't have enough credits! else: (newBalance,), blob = Basic.read_message('!I', blob) self.factory.bank.on_new_balance_from_bank(newBalance)
def handle_dht_request(self, data): log_msg("Got remote DHT request", 4, "dht") #unpack and validate the message: version, data = Basic.read_byte(data) assert version == Node.VERSION #read the infohash: vals, data = Basic.read_message("20s", data) infohash = vals[0] #read each peer: peers = set() while len(data) > 0: #what type of peer? (ip or url) peerType, data = Basic.read_byte(data) #IP peer: if peerType == 0: vals, data = Basic.read_message("!4sH", data) host = socket.inet_ntoa(vals[0]) port = vals[1] #URL peer: elif peerType == 1: host, data = Basic.read_lenstr(data) port, data = Basic.read_short(data) #bad peer type: else: raise Exception("Unknown peer address type: %s" % (peerType)) peers.add((host, port)) #note that there is a new transaction: transactionId = self.currentTransactionId self.responses[transactionId] = "" self.currentTransactionId += 1 #now add each peer: for host, port in peers: #make sure it's not one of our defaults #TODO: in the future, make sure we don't already know about it anyway? Eh, maybe that will break DHT somehow? if (host, port) not in Node.BOOTSTRAP_NODES: log_msg("Neat, someone told us about a new DHT node", 2) self.dhtNode.add_contact(host, port) #and then send out the request: def response(data, transactionId=transactionId): #is this the last message? if len(data) <= 0: #then send the response for this transaction: self._send_peers(transactionId) #otherwise, just accumulate the data for later: else: self.responses[transactionId] += "".join(data[0]) self.dhtNode.get_peers(infohash, response)
def stringReceived(self, data): """Called when the login response arrives""" self.factory.done = True self.responseReceived = True text = None try: protocol, data = Basic.read_byte(data) if protocol == 1: returnCode, data = Basic.read_byte(data) if returnCode == 1: format = '!IIII4sI' (balance, currentACoinInterval, currentACoinIntervalExpiration, nextAcoinIntervalExpiration, host, port), blob = Basic.read_message(format, data) size = struct.calcsize(SymmetricKey.MESSAGE_FORMAT) authBlob = blob[:size] text = blob[size:] host = socket.inet_ntoa(host) self.factory.bank.on_new_info( balance, currentACoinInterval, currentACoinIntervalExpiration, nextAcoinIntervalExpiration) self.factory.bank.on_login_success(balance, authBlob, host, port, text) else: size = struct.calcsize('!I') timeout = struct.unpack('!I', data[:size])[0] text = data[size:] raise BadLoginPasswordError(timeout) else: raise Exception('unknown protocol: %s' % (protocol)) except Exception, error: self.factory.bank.on_login_failure(error, text)
def stringReceived(self, data): self.responseReceived = True self.factory.gotResponse = True data = self.factory.bank.decrypt_message(data) log_msg("ACoin DEPOSIT response received.", 4) (newBalance, interval, expiresCurrent, expiresNext), returnSlip = Basic.read_message('!IIII', data) self.factory.bank.on_new_info(newBalance, interval, expiresCurrent, expiresNext) returnSlip = list(struct.unpack('c'*len(self.factory.coins), returnSlip)) for i in range(0, len(self.factory.coins)): coin = self.factory.coins[i] status = returnSlip[i] gotAcceptableResponse = True badACoin = True if status == "0": badACoin = False elif status == "3": log_msg("ACoin deposit failed. Some node must have double-spent.", 1) elif status == "2": log_msg("ACoin deposit failed. You apparently already sent this acoin.", 1) elif status == "1": log_msg("ACoin deposit failed. ACoin was not valid? %s" % (repr(coin.write_binary())), 0) else: log_msg("Bank returned unknown status message: %s" % (status), 0) gotAcceptableResponse = False if badACoin: #close the circuit, they're trying to cheat us! if coin.originCircuit: coin.originCircuit.close() self.transport.loseConnection()
def sym_decrypt(self, msg): """this is disgusting because we use two different systems for symmetric encryption type 0 uses SmmetricKey while type 1 uses EncryptedDatagram quirks: 0 must also update the nonce stored in the db 1 performs heavy crypto and has non symmetric client/server side encryption/decryption""" if not self.symKey: msgType, msg = Basic.read_byte(msg) if msgType is 0: #get the tor fingerprint so we know how to decrypt the message (binId,), msg = Basic.read_message('!20s', msg) #convert the tor fingerprint back into hex self.hexId = binascii.hexlify(binId).upper() #get the symmetric key out of the database: sql = "SELECT Owner, Public_Key, Msgnum, auth_blob FROM Relays WHERE Tor_Id = %s" inj = (self.hexId,) d = db.read(sql, inj) #get the sym key from the db and decrypt the msg d.addCallback(self.fetch_sym_key, msg) #update the message number in the database d.addCallback(self.update_db) elif msgType is 1: self.symKey = EncryptedDatagram.ServerSymKey(Globals.GENERIC_KEY) d = threads.deferToThread(self.get_sym_key_value, msg) else: raise Exception("Unknown msgType: %s" % (msgType)) else: raise Exception('Passing more than one message per tcp connection is currently not supported') return d
def sym_decrypt(self, msg): """this is disgusting because we use two different systems for symmetric encryption type 0 uses SmmetricKey while type 1 uses EncryptedDatagram quirks: 0 must also update the nonce stored in the db 1 performs heavy crypto and has non symmetric client/server side encryption/decryption""" if not self.symKey: msgType, msg = Basic.read_byte(msg) if msgType is 0: #get the tor fingerprint so we know how to decrypt the message (binId, ), msg = Basic.read_message('!20s', msg) #convert the tor fingerprint back into hex self.hexId = binascii.hexlify(binId).upper() #get the symmetric key out of the database: sql = "SELECT Owner, Public_Key, Msgnum, auth_blob FROM Relays WHERE Tor_Id = %s" inj = (self.hexId, ) d = db.read(sql, inj) #get the sym key from the db and decrypt the msg d.addCallback(self.fetch_sym_key, msg) #update the message number in the database d.addCallback(self.update_db) elif msgType is 1: self.symKey = EncryptedDatagram.ServerSymKey( Globals.GENERIC_KEY) d = threads.deferToThread(self.get_sym_key_value, msg) else: raise Exception("Unknown msgType: %s" % (msgType)) else: raise Exception( 'Passing more than one message per tcp connection is currently not supported' ) return d
def read_binary(self, msg): vals, msg = Basic.read_message(MESSAGE_FORMAT, msg) self.receipt = vals[0] self.interval = vals[1] self.signature = vals[2] self.value = VALUE self.initialized = True if self.interval == 0: temp = 4 return msg
def read_reply(self, data, host): try: #read the header: data = self._read_header(data, "reply") #read the host: vals, data = Basic.read_message("!4s", data) host = socket.inet_ntoa(vals[0]) #read the message: msg = data except AssertionError, error: raise BadEchoMessageFormat(str(error))
def decrypt(self, msg): Basic.validate_type(msg, types.StringType) #decrypt the message encRandomData, msg = Basic.read_message('!%ss'%( BANK_KEY_LENGTH), msg) randomData = self.key.decrypt(encRandomData[0]) self.make_sym_key(randomData) inbuf = cStringIO.StringIO(msg) outbuf = cStringIO.StringIO() outbuf.write(self.decryptCipher.update(inbuf.read())) outbuf.write(self.decryptCipher.final()) msg = outbuf.getvalue() mac = msg[:32] msg = msg[32:] #validate the HMAC if self.make_hmac(msg) != mac: raise Exception('HMAC does not authenticate, is something bad going on?') return msg
def decrypt(self, msg): Basic.validate_type(msg, types.StringType) #decrypt the message encRandomData, msg = Basic.read_message('!%ss' % (BANK_KEY_LENGTH), msg) randomData = self.key.decrypt(encRandomData[0]) self.make_sym_key(randomData) inbuf = cStringIO.StringIO(msg) outbuf = cStringIO.StringIO() outbuf.write(self.decryptCipher.update(inbuf.read())) outbuf.write(self.decryptCipher.final()) msg = outbuf.getvalue() mac = msg[:32] msg = msg[32:] #validate the HMAC if self.make_hmac(msg) != mac: raise Exception( 'HMAC does not authenticate, is something bad going on?') return msg
def stringReceived(self, data): """Called when the login response arrives""" self.factory.done = True self.responseReceived = True text = None try: protocol, data = Basic.read_byte(data) if protocol == 1: returnCode, data = Basic.read_byte(data) if returnCode == 1: format = '!IIII4sI' (balance, currentACoinInterval, currentACoinIntervalExpiration, nextAcoinIntervalExpiration, host, port), blob = Basic.read_message(format, data) size = struct.calcsize(SymmetricKey.MESSAGE_FORMAT) authBlob = blob[:size] text = blob[size:] host = socket.inet_ntoa(host) self.factory.bank.on_new_info(balance, currentACoinInterval, currentACoinIntervalExpiration, nextAcoinIntervalExpiration) self.factory.bank.on_login_success(balance, authBlob, host, port, text) else: size = struct.calcsize('!I') timeout = struct.unpack('!I', data[:size])[0] text = data[size:] raise BadLoginPasswordError(timeout) else: raise Exception('unknown protocol: %s'%(protocol)) except Exception, error: self.factory.bank.on_login_failure(error, text)