def _GetServerCipher(self): """Returns the cipher for self.server_name.""" if self.server_cipher is not None: expiry = self.server_cipher_age + rdfvalue.Duration.From(1, rdfvalue.DAYS) if expiry > rdfvalue.RDFDatetime.Now(): return self.server_cipher remote_public_key = self._GetRemotePublicKey(self.server_name) self.server_cipher = communicator.Cipher(self.common_name, self.private_key, remote_public_key) self.server_cipher_age = rdfvalue.RDFDatetime.Now() return self.server_cipher
def EncodeMessages(self, message_list, result, destination=None, timestamp=None, api_version=3): """Accepts a list of messages and encodes for transmission. This function signs and then encrypts the payload. Args: message_list: A MessageList rdfvalue containing a list of GrrMessages. result: A ClientCommunication rdfvalue which will be filled in. destination: The CN of the remote system this should go to. timestamp: A timestamp to use for the signed messages. If None - use the current time. api_version: The api version which this should be encoded in. Returns: A nonce (based on time) which is inserted to the encrypted payload. The client can verify that the server is able to decrypt the message and return the nonce. Raises: RuntimeError: If we do not support this api version. """ if api_version not in [3]: raise RuntimeError("Unsupported api version: %s, expected 3." % api_version) remote_public_key = self._GetRemotePublicKey(destination) cipher = communicator.Cipher(self.common_name, self.private_key, remote_public_key) # Make a nonce for this transaction if timestamp is None: self.timestamp = timestamp = int(time.time() * 1000000) packed_message_list = rdf_flows.PackedMessageList(timestamp=timestamp) self.EncodeMessageList(message_list, packed_message_list) result.encrypted_cipher_metadata = cipher.encrypted_cipher_metadata # Include the encrypted cipher. result.encrypted_cipher = cipher.encrypted_cipher serialized_message_list = packed_message_list.SerializeToBytes() # Encrypt the message symmetrically. # New scheme cipher is signed plus hmac over message list. result.packet_iv, result.encrypted = cipher.Encrypt( serialized_message_list) # This is to support older endpoints. result.hmac = cipher.HMAC(result.encrypted) # Newer endpoints only look at this HMAC. It is recalculated for each packet # in the session. Note that encrypted_cipher and encrypted_cipher_metadata # do not change between all packets in this session. result.full_hmac = cipher.HMAC(result.encrypted, result.encrypted_cipher, result.encrypted_cipher_metadata, result.packet_iv.SerializeToBytes(), struct.pack("<I", api_version)) result.api_version = api_version if isinstance(result, rdfvalue.RDFValue): # Store the number of messages contained. result.num_messages = len(message_list) return timestamp