def extractMessages( self, data, aes ): """ Unpacks (i.e., decrypts and authenticates) protocol messages. The raw `data' coming directly from the wire is decrypted using `aes' and authenticated. The payload (be it a session ticket or actual payload) is then returned as unencrypted protocol messages. In case of invalid headers or HMACs, an exception is raised. """ assert aes and (data is not None) self.recvBuf += data msgs = [] # Keep trying to unpack as long as there is at least a header. while len(self.recvBuf) >= const.HDR_LENGTH: # If necessary, extract the header fields. if self.totalLen == self.payloadLen == self.flags == None: self.totalLen = pack.ntohs(aes.decrypt(self.recvBuf[16:18])) self.payloadLen = pack.ntohs(aes.decrypt(self.recvBuf[18:20])) self.flags = ord(aes.decrypt(self.recvBuf[20])) if not message.isSane(self.totalLen, self.payloadLen, self.flags): raise base.PluggableTransportError("Invalid header.") # Parts of the message are still on the wire; waiting. if (len(self.recvBuf) - const.HDR_LENGTH) < self.totalLen: break rcvdHMAC = self.recvBuf[0:const.HMAC_SHA256_128_LENGTH] vrfyHMAC = mycrypto.HMAC_SHA256_128(self.recvHMAC, self.recvBuf[const.HMAC_SHA256_128_LENGTH: (self.totalLen + const.HDR_LENGTH)]) if rcvdHMAC != vrfyHMAC: raise base.PluggableTransportError("Invalid message HMAC.") # Decrypt the message and remove it from the input buffer. extracted = aes.decrypt(self.recvBuf[const.HDR_LENGTH: (self.totalLen + const.HDR_LENGTH)])[:self.payloadLen] msgs.append(message.new(payload=extracted, flags=self.flags)) self.recvBuf = self.recvBuf[const.HDR_LENGTH + self.totalLen:] # Protocol message processed; now reset length fields. self.totalLen = self.payloadLen = self.flags = None return msgs
def extract(self, data, aes, hmacKey): """ Extracts (i.e., decrypts and authenticates) protocol messages. The raw `data' coming directly from the wire is decrypted using `aes' and authenticated using `hmacKey'. The payload is then returned as unencrypted protocol messages. In case of invalid headers or HMACs, an exception is raised. """ self.recvBuf += data msgs = [] # Keep trying to unpack as long as there is at least a header. while len(self.recvBuf) >= const.HDR_LENGTH: # If necessary, extract the header fields. if self.totalLen == self.payloadLen == self.flags == None: self.totalLen = pack.ntohs(aes.decrypt(self.recvBuf[16:18])) self.payloadLen = pack.ntohs(aes.decrypt(self.recvBuf[18:20])) self.flags = ord(aes.decrypt(self.recvBuf[20])) if not isSane(self.totalLen, self.payloadLen, self.flags): raise base.PluggableTransportError("Invalid header.") # Parts of the message are still on the wire; waiting. if (len(self.recvBuf) - const.HDR_LENGTH) < self.totalLen: break rcvdHMAC = self.recvBuf[0:const.HMAC_SHA256_128_LENGTH] vrfyHMAC = mycrypto.HMAC_SHA256_128( hmacKey, self.recvBuf[const.HMAC_SHA256_128_LENGTH:(self.totalLen + const.HDR_LENGTH)]) if rcvdHMAC != vrfyHMAC: raise base.PluggableTransportError("Invalid message HMAC.") # Decrypt the message and remove it from the input buffer. extracted = aes.decrypt(self.recvBuf[const.HDR_LENGTH:( self.totalLen + const.HDR_LENGTH)])[:self.payloadLen] msgs.append(ProtocolMessage(payload=extracted, flags=self.flags)) self.recvBuf = self.recvBuf[const.HDR_LENGTH + self.totalLen:] # Protocol message processed; now reset length fields. self.totalLen = self.payloadLen = self.flags = None return msgs
def unpack(self, data, aes): # Input buffer which is not yet processed and forwarded. self.recvBuf += data fwdBuf = "" # Keep trying to unpack as long as there seems to be enough data. while len(self.recvBuf) >= const.HDR_LENGTH: # Extract length fields if we don't have them already. if self.totalLen == None: self.totalLen = pack.ntohs(aes.decrypt(self.recvBuf[16:18])) self.payloadLen = pack.ntohs(aes.decrypt(self.recvBuf[18:20])) # Abort immediately if the extracted lengths do not make sense. if not message.saneLengths(self.totalLen, self.payloadLen): raise base.PluggableTransportError("Invalid message " \ "length(s): totalLen=%d, payloadLen=%d." % \ (self.totalLen, self.payloadLen)) log.debug("Message header: totalLen=%d, payloadLen=%d." % \ (self.totalLen, self.payloadLen)) if (len(self.recvBuf) - const.HDR_LENGTH) < self.totalLen: return fwdBuf # We have a full message; let's extract it. else: log.debug("Extracting fully received protocol message.") rcvdHMAC = self.recvBuf[0:const.HMAC_LENGTH] vrfyHMAC = mycrypto.MyHMAC_SHA256_128(self.recvHMAC, \ self.recvBuf[const.HMAC_LENGTH:(self.totalLen + \ const.HDR_LENGTH)]) # Abort immediately if the HMAC is invalid. if rcvdHMAC != vrfyHMAC: raise base.PluggableTransportError("Invalid HMAC!") fwdBuf += aes.decrypt(self.recvBuf[const.HDR_LENGTH: \ (self.totalLen+const.HDR_LENGTH)])[:self.payloadLen] self.recvBuf = self.recvBuf[const.HDR_LENGTH + self.totalLen:] # Protocol message extracted - resetting length fields. self.totalLen = self.payloadLen = None log.debug("Unpacked %d bytes of data: 0x%s..." % \ (len(fwdBuf), fwdBuf[:10].encode('hex'))) return fwdBuf
def unpack(self, data, aes): # Input buffer which is not yet processed and forwarded. self.recvBuf += data fwdBuf = "" # Keep trying to unpack as long as there seems to be enough data. while len(self.recvBuf) >= const.HDR_LENGTH: # Extract length fields if we don't have them already. if self.totalLen == None: self.totalLen = pack.ntohs(aes.decrypt(self.recvBuf[16:18])) self.payloadLen = pack.ntohs(aes.decrypt(self.recvBuf[18:20])) # Abort immediately if the extracted lengths do not make sense. if not message.saneLengths(self.totalLen, self.payloadLen): raise base.PluggableTransportError( "Invalid message " "length(s): totalLen=%d, payloadLen=%d." % (self.totalLen, self.payloadLen) ) log.debug("Message header: totalLen=%d, payloadLen=%d." % (self.totalLen, self.payloadLen)) if (len(self.recvBuf) - const.HDR_LENGTH) < self.totalLen: return fwdBuf # We have a full message; let's extract it. else: log.debug("Extracting fully received protocol message.") rcvdHMAC = self.recvBuf[0 : const.HMAC_LENGTH] vrfyHMAC = mycrypto.MyHMAC_SHA256_128( self.recvHMAC, self.recvBuf[const.HMAC_LENGTH : (self.totalLen + const.HDR_LENGTH)] ) # Abort immediately if the HMAC is invalid. if rcvdHMAC != vrfyHMAC: raise base.PluggableTransportError("Invalid HMAC!") fwdBuf += aes.decrypt(self.recvBuf[const.HDR_LENGTH : (self.totalLen + const.HDR_LENGTH)])[ : self.payloadLen ] self.recvBuf = self.recvBuf[const.HDR_LENGTH + self.totalLen :] # Protocol message extracted - resetting length fields. self.totalLen = self.payloadLen = None log.debug("Unpacked %d bytes of data: 0x%s..." % (len(fwdBuf), fwdBuf[:10].encode("hex"))) return fwdBuf
def _get_ext_orport_command(self, buf): """ Reads an Extended ORPort command from 'buf'. Returns (command, body) if it was well-formed, where 'command' is the Extended ORPort command type, and 'body' is its body. Throws NeedMoreData. """ if len(buf) < AUTH_PROTOCOL_HEADER_LEN: raise NeedMoreData("Not enough data for header.") header = buf.peek(AUTH_PROTOCOL_HEADER_LEN) cmd = srlz.ntohs(header[:2]) bodylen = srlz.ntohs(header[2:4]) if (bodylen > len(buf) - AUTH_PROTOCOL_HEADER_LEN): # Not all here yet raise NeedMoreData("Not enough data for body.") # We have a whole command. Drain the header. buf.drain(4) body = buf.read(bodylen) return (cmd, body)
def getargsLen(self, string=None): """Return `argsLen` field from buffer.""" return pack.ntohs(self.getMessageField(const.ARGS_TOTAL_LENGTH_POS, const.ARGS_TOTAL_LENGTH_LEN, string))
def getTotalLen(self, string=None): """Return `totalLen` field from buffer.""" return pack.ntohs(self.getMessageField(const.TOTLENGTH_POS, const.TOTLENGTH_LEN, string))
def getPayloadLen(self, string=None): """Return `payloadLen` field from buffer.""" return pack.ntohs(self.getMessageField(const.PAYLOAD_POS, const.PAYLOAD_LEN, string))
def getargsLen(self, string=None): """Return `argsLen` field from buffer.""" return pack.ntohs( self.getMessageField(const.ARGS_TOTAL_LENGTH_POS, const.ARGS_TOTAL_LENGTH_LEN, string))
def getTotalLen(self, string=None): """Return `totalLen` field from buffer.""" return pack.ntohs( self.getMessageField(const.TOTLENGTH_POS, const.TOTLENGTH_LEN, string))
def getPayloadLen(self, string=None): """Return `payloadLen` field from buffer.""" return pack.ntohs( self.getMessageField(const.PAYLOAD_POS, const.PAYLOAD_LEN, string))