Exemple #1
0
        def decrypt_data():
            aes_cipher = AESCipher(client.secret_key)
            encrypted_uri = self.handler.request.headers.get(
                'X-Api-Encrypted-Uri')
            if encrypted_uri:
                request.uri = aes_cipher.decrypt(utf8(encrypted_uri))
                logger.debug('decrypted uri %s' % request.uri)

            encrypted_headers = self.handler.request.headers.get(
                'X-Api-Encrypted-Headers')

            if encrypted_headers:
                headers_str = aes_cipher.decrypt(utf8(encrypted_headers))
                headers = dict(json.loads(headers_str))
                logger.debug('raw headers %s' % request.headers)
                for k, v in headers.iteritems():
                    # 要全部使用 text_type,否则会出现有的为 str,有的为 unicode
                    # 导致422错误
                    request.headers[text_type(k)] = text_type(v)

                logger.debug('decrypted headers %s' % request.headers)

            if request.body and len(request.body) > 0:
                logger.debug('解密 body')
                logger.debug(request.body)
                request.body = aes_cipher.decrypt(utf8(request.body))
Exemple #2
0
        def decrypt_data():
            aes_cipher = AESCipher(client.secret_key)
            encrypted_uri = self.handler.request.headers.get('X-Api-Encrypted-Uri')
            if encrypted_uri:
                request.uri = aes_cipher.decrypt(utf8(encrypted_uri))
                logger.debug('decrypted uri %s' % request.uri)
                # 因为修改了 uri,需要重新生成 query_arguments
                request.path, sep, request.query = request.uri.partition('?')
                request.arguments = parse_qs_bytes(request.query, keep_blank_values=True)
                request.query_arguments = copy.deepcopy(request.arguments)

            encrypted_headers = self.handler.request.headers.get('X-Api-Encrypted-Headers')

            if encrypted_headers:
                headers_str = aes_cipher.decrypt(utf8(encrypted_headers))
                headers = dict(json_decode(headers_str))
                # logger.debug('raw headers %s' % request.headers)
                for k, v in iteritems(headers):
                    # 要全部使用 text_type,否则会出现有的为 str,有的为 unicode
                    # 导致422错误
                    request.headers[text_type(k)] = text_type(v)

                # logger.debug('decrypted headers %s' % request.headers)

            if request.body and len(request.body) > 0:
                logger.debug('解密 body')
                logger.debug(request.body)
                request.body = aes_cipher.decrypt(utf8(request.body))
                # 因为修改了 body,需要重新 _parse_body
                request._parse_body()
Exemple #3
0
 def getKey(self, cmd=False):
     if os.path.isfile('wallets/' + self.name + '.privkey'):
         with open('wallets/' + self.name + '.privkey',
                   'r',
                   encoding='utf-8') as key:
             encKey = key.read()
             enc = AESCipher(self.phrase)
             try:
                 self.key = enc.decrypt(encKey)
             except UnicodeDecodeError:
                 print(color.E('\nIncorrect passphrase for wallet!\n'))
     else:
         self.key = False
         print(color.E('\nWallet not found!\n'))
Exemple #4
0
    def decrypt_data(self, body):
        try:
            aes_cipher = AESCipher(self.secret_key)
            if body and len(body) > 0:
                logger.debug('解密 body')
                logger.debug(body.encode('hex'))
                body = aes_cipher.decrypt(utf8(body))
                # logger.debug(body.decode('hex'))
        except Exception as e:
            logger.error('解密数据出错')
            logger.error(e)
            logger.error(traceback.format_exc())
            return None

        return body
Exemple #5
0
    def decrypt_data(self, body):
        try:
            aes_cipher = AESCipher(self.secret_key)
            if body and len(body) > 0:
                logger.debug('解密 body')
                logger.debug(body.encode('hex'))
                body = aes_cipher.decrypt(utf8(body))
                # logger.debug(body.decode('hex'))
        except Exception as e:
            logger.error('解密数据出错')
            logger.error(e)
            logger.error(traceback.format_exc())
            return None

        return body
Exemple #6
0
    def decrypt_data(self, body):
        try:
            aes_cipher = AESCipher(self.secret_key)
            if body and len(body) > 0:
                logger.debug('解密 body')
                body = aes_cipher.decrypt(utf8(body))
                # logger.debug(body.decode('hex'))
        except Exception as e:
            logger.error('解密数据出错')
            logger.error(e)
            logger.error(traceback.format_exc())
            return None

        # 由于 requests 的 content 不是 unicode 类型, 为了兼容, 这里改成 utf8
        if isinstance(body, text_type):
            body = body.encode('utf-8')

        return body
def callback(message):
    logging.info("********** Start PubsubMessage ")
    message.ack()
    logging.info('Received message ID: {}'.format(message.message_id))
    logging.info('Received message publish_time: {}'.format(
        message.publish_time))

    if args.mode == 'decrypt':
        try:
            ac = AESCipher(key)
            logging.info("Loaded Key: " + ac.printKeyInfo())
            decrypted_data = ac.decrypt(message.data, associated_data='')
            logging.info('Decrypted data ' + decrypted_data)
            logging.info("ACK message")
            message.ack()
        except Exception as e:
            logging.info("Unable to decrypt message; NACK pubsub message " +
                         str(e))
            message.nack()
        logging.info("End AES decryption")

    if args.mode == 'verify':
        try:
            logging.info("Starting HMAC")
            hmac = message.attributes.get('signature')
            hh = HMACFunctions(key)
            logging.info("Loaded Key: " + hh.printKeyInfo())
            logging.info("Verify message: " + str(message.data))
            logging.info('  With HMAC: ' + str(hmac))
            hashed = hh.hash(message.data)
            if (hh.verify(message.data, base64.b64decode(hashed))):
                logging.info("Message authenticity verified")
                message.ack()
            else:
                logging.error("Unable to verify message")
                message.nack()
        except Exception as e:
            logging.info("Unable to verify message; NACK pubsub message " +
                         str(e))
            message.nack()

    logging.info("********** End PubsubMessage ")
Exemple #8
0
def callback(message):

    logging.info("********** Start PubsubMessage ")
    logging.info('Received message ID: {}'.format(message.message_id))
    logging.info('Received message publish_time: {}'.format(
        message.publish_time))

    if args.mode == "verify":
        try:
            key_id = message.attributes['key_id']
            service_account = message.attributes['service_account']
            signature = message.attributes['signature']

            m = hashlib.sha256()
            m.update(message.data)
            data_to_verify = m.digest()

            logging.info("Attempting to verify message: " + str(message.data))
            logging.info("data_to_verify " +
                         base64.b64encode(data_to_verify).decode('utf-8'))
            logging.info("Verify message with signature: " + str(signature))
            logging.info("  Using service_account/key_id: " + service_account +
                         " " + key_id)

            cert_url = 'https://www.googleapis.com/service_accounts/v1/metadata/x509/' + service_account
            r = requests.get(cert_url)
            pem = r.json().get(key_id)
            v = crypt.RSAVerifier.from_string(pem)

            if v.verify(data_to_verify, base64.b64decode(signature)):
                logging.info("Message integrity verified")
                message.ack()
            else:
                logging.info("Unable to verify message")
                message.nack()
            logging.info("********** End PubsubMessage ")
        except Exception as e:
            logging.info("Unable to verify message; NACK pubsub message " +
                         str(e))
            message.nack()

    if args.mode == "decrypt":
        try:
            key_id = message.attributes['key_id']
            msg_service_account = message.attributes['service_account']

            logging.info("Attempting to decrypt message: " + str(message.data))
            logging.info("  Using service_account/key_id: " +
                         msg_service_account + " " + key_id)

            if args.cert_service_account == None:
                logging.error(
                    "********** cert_service_account must be specified to decrypt "
                )
                message.nack()
                sys.exit()

            credentials = Credentials.from_service_account_file(
                args.cert_service_account)
            key_key_id = credentials._signer._key_id

            key_service_account_email = credentials.service_account_email
            if (msg_service_account != key_service_account_email):
                logging.info(
                    "Service Account specified in command line does not match message payload service account"
                )
                logging.info(msg_service_account + " --- " +
                             args.cert_service_account)
                message.nack()
                return
            else:
                private_key = credentials._signer._key
                rs = RSACipher(private_key=private_key)
                try:
                    logging.debug(
                        'Received message attributes["dek_wrapped"]: {}'.
                        format(message.attributes['dek_wrapped']))
                    dek_wrapped = message.attributes['dek_wrapped']
                    logging.info('Wrapped DEK ' + dek_wrapped)
                    dek_cleartext = rs.decrypt(dek_wrapped)
                    logging.info('Decrypted DEK ' + dek_cleartext)
                    dek = AESCipher(encoded_key=dek_cleartext)
                    logging.info(dek.printKeyInfo())
                    plaintext = dek.decrypt(message.data, associated_data="")
                except ValueError:
                    logging.error(
                        "dek_wrapped not sent, attempting to decrypt with svc account rsa key"
                    )
                    plaintext = rs.decrypt(message.data)
                except Exception as e:
                    logging.error("Error Decrypting payload " + str(e))
                    message.nack()
                    return
                logging.info("Decrypted Message payload: " + plaintext)
                message.ack()
        except Exception as e:
            logging.info("Unable to decrypt message; NACK pubsub message " +
                         str(e))
            message.nack()

        logging.info("********** End PubsubMessage ")
Exemple #9
0
class ClientConnector(Protocol):
    """Handle one connection to a client.

    Its functions include:
        - Initiate connection to client.
        - Send an authentication message to client to start transmission.
        - Receive encrypted data packets from client, separated by split_char.
        - Decrypt data packets. Get the ID (first 2 bytes of decrypted text).
          Create a connection to HTTP proxy for each unique ID.
        - Forward request to HTTP proxy. Encrypt and send back the response.
        - Close connection to HTTP proxy for a given ID if a packet
          of the ID with close_char is received.
    """
    def __init__(self, initiator):
        self.initiator = initiator

        self.main_pw = self.initiator.main_pw
        # control characters
        self.split_char = chr(27) + chr(28) + "%X" % struct.unpack(
            'B', self.main_pw[-2:-1])[0] + "%X" % struct.unpack(
                'B', self.main_pw[-3:-2])[0] + chr(31)
        self.client_pub = self.initiator.client_pub
        self.session_pw = urandom(16)
        self.cipher = AESCipher(self.session_pw, self.main_pw)
        self.authenticated = False
        self.buffer = ""
        self.latency = 10000
        self.i = initiator.register()
        self.idchar = (str(self.i) if 10 <= self.i <= 99 else '0' +
                       str(self.i))
        self.cronjob = None
        self.cancel_job = None

    def generate_auth_msg(self):
        """Generate encrypted message. For auth and init.

        The message is in the form
            server_sign(main_pw) (HEX) +
            client_pub(session_pw) + id
        Total length is 512 + 256 + 2 = 770 bytes
        """
        pw_enc = self.client_pub.encrypt(self.session_pw, None)[0]
        return '\r\n'.join(
            (self.initiator.signature_to_client, pw_enc, self.idchar,
             repr(self.initiator.client_recv_index_dict[self.i])))

    def ping_send(self):
        """Send the initial ping message to the client at a certain interval.

        Ping mechanism (S for server, C for client, t-i for i-th timestamp):
            packet 0: S->C, t-0
            packet 1: C->S, t-0 + t-1
            packet 2: S->C, t-1
        In this way, both server and client get the round-trip latency.

        Packet format (before encryption):
            "1"         (1 byte)          (type flag for ping)
            seq         (1 byte)          (0, 1 or 2)
            timestamp   (11 or 22 bytes)  (time in milliseconds, in hexagon)
        """
        raw_packet = "1" + "0" + get_timestamp()
        to_write = self.cipher.encrypt(raw_packet) + self.split_char
        if self.authenticated:
            #logging.debug("send ping0")
            self.transport.write(to_write)
            interval = random.randint(500, 1500) / 100
            if self.initiator.obfs_level == 3:
                RESET_INTERVAL = 5
            else:
                RESET_INTERVAL = 2
            self.cronjob = reactor.callLater(interval, self.ping_send)
            self.cancel_job = reactor.callLater(RESET_INTERVAL, self.close)

    def ping_recv(self, msg):
        """Parse ping 1 (without flag & seq) and send ping 2."""
        #logging.debug("recv ping1")
        self.cancel_job.cancel()
        time0 = parse_timestamp(msg[:11])
        self.latency = int(time() * 1000) - time0
        logging.debug("latency: %dms" % self.latency)
        raw_packet = "1" + "2" + msg[11:]
        to_write = self.cipher.encrypt(raw_packet) + self.split_char
        if self.transport:
            #logging.debug("send ping2")
            self.transport.write(to_write)

    def connectionMade(self):
        """Event handler of being successfully connected to the client."""
        logging.info("connected to client " +
                     addr_to_str(self.transport.getPeer()))
        self.transport.write(self.generate_auth_msg() + self.split_char)

    def dataReceived(self, recv_data):
        """Event handler of receiving some data from client.

        Split, decrypt and hand them back to Control.
        """
        # Avoid repetition caused by ping
        # logging.debug("received %d bytes from client " % len(recv_data) +
        #              addr_to_str(self.transport.getPeer()))

        self.buffer += recv_data

        # a list of encrypted data packages
        # the last item may be incomplete
        recv = self.buffer.split(self.split_char)
        # leave the last (may be incomplete) item intact
        for text_enc in recv[:-1]:
            text_dec = self.cipher.decrypt(text_enc)
            # flag is 0 for normal data packet, 1 for ping packet, 2 for auth
            flag = int(text_dec[0])
            if flag == 0:
                self.initiator.client_recv(text_dec[1:], self)
            elif flag == 2:
                auth_str = "AUTHENTICATED" + self.idchar
                if text_dec[1:].startswith(auth_str):
                    max_recved_idx = eval(text_dec[1:].lstrip(auth_str))
                    self.authenticate_success()
                    self.initiator.retransmit_clientconn_reload(
                        self, max_recved_idx)
                else:
                    self.close()
            else:
                # strip off type and seq (both are always 1)
                self.ping_recv(text_dec[2:])

        self.buffer = recv[-1]  # incomplete message

    def authenticate_success(self):
        self.authenticated = True
        logging.debug("Authentication confirm string received.")
        self.initiator.add_cli(self)
        self.ping_send()

    def close(self):
        '''a secure way to abort the connection'''
        try:
            self.cronjob.cancel()
        except Exception:
            pass
        # self.initiator.remove_cli(self)
        self.transport.loseConnection()

    def connectionLost(self, reason):
        """Event handler of losing the connection to the client.

        Call Control to handle it.
        """
        if self.authenticated:
            logging.info("client connection lost: " +
                         addr_to_str(self.transport.getPeer()))
        self.authenticated = False
        self.initiator.client_lost(self.i)

    def write(self, data, conn_id, index):
        """Encrypt and write data the client.

        Encrypted packets should be separated by split_char.
        Raw packet structure:
            type    (1 byte)   (0 for normal data packet)
            id      (2 bytes)
            index   (6 bytes)
            data
        """
        if index < 100000:
            index = '0' * (6 - len(str(index))) + str(index)
        else:
            index = str(index)
        # get current time with base 36 as a string in a certain length .
        to_write = self.cipher.encrypt("0" + conn_id + index + data) +\
            self.split_char
        logging.debug(
            "sending %d bytes to client %s with id %s" %
            (len(data), addr_to_str(self.transport.getPeer()), conn_id))
        self.transport.write(to_write)
Exemple #10
0
class ClientConnector(Protocol):
    """Handle one connection to a client.

    Its functions include:
        - Initiate connection to client.
        - Send an authentication message to client to start transmission.
        - Receive encrypted data packets from client, separated by split_char.
        - Decrypt data packets. Get the ID (first 2 bytes of decrypted text).
          Create a connection to HTTP proxy for each unique ID.
        - Forward request to HTTP proxy. Encrypt and send back the response.
        - Close connection to HTTP proxy for a given ID if a packet
          of the ID with close_char is received.
    """

    def __init__(self, initiator):
        self.initiator = initiator

        self.main_pw = self.initiator.main_pw
        # control characters
        # self.split_char = chr(27) + chr(28) + chr(29) + chr(30) + chr(31)
        self.split_char = chr(27) + chr(28) + "%X" % struct.unpack('B', self.main_pw[-2:-1])[
            0] + "%X" % struct.unpack('B', self.main_pw[-3:-2])[0] + chr(31)
        self.pri = self.initiator.initiator.pri
        self.client_pub = self.initiator.client_pub
        self.session_pw = urandom(16)
        self.cipher = AESCipher(self.session_pw, self.main_pw)
        self.authenticated = False
        self.buffer = ""
        self.latency = 10000
        self.idchar = initiator.register()
        self.cronjob = None
        self.cancel_job = None

    def generate_auth_msg(self):
        """Generate encrypted message.

        The message is in the form
            server_sign(main_pw) (HEX) +
            client_pub(session_pw) + id
        Total length is 512 + 256 + 2 = 770 bytes
        """
        hex_sign = '%X' % self.pri.sign(self.main_pw, None)[0]
        pw_enc = self.client_pub.encrypt(self.session_pw, None)[0]
        return hex_sign + pw_enc + self.idchar

    def ping_send(self):
        """Send the initial ping message to the client at a certain interval.

        Ping mechanism (S for server, C for client, t-i for i-th timestamp):
            packet 0: S->C, t-0
            packet 1: C->S, t-0 + t-1
            packet 2: S->C, t-1
        In this way, both server and client get the round-trip latency.

        Packet format (before encryption):
            "1"         (1 byte)          (type flag for ping)
            seq         (1 byte)          (0, 1 or 2)
            timestamp   (11 or 22 bytes)  (time in milliseconds, in hexagon)
        """
        raw_packet = "1" + "0" + get_timestamp()
        to_write = self.cipher.encrypt(raw_packet) + self.split_char
        if self.authenticated:
            #logging.debug("send ping0")
            self.transport.write(to_write)
            interval = random.randint(500, 1500) / 100
            if self.initiator.obfs_level == 3:
                RESET_INTERVAL = 5
            else:
                RESET_INTERVAL = 2
            self.cronjob = reactor.callLater(interval, self.ping_send)
            self.cancel_job = reactor.callLater(RESET_INTERVAL, self.close)

    def ping_recv(self, msg):
        """Parse ping 1 (without flag & seq) and send ping 2."""
        #logging.debug("recv ping1")
        self.cancel_job.cancel()
        time0 = parse_timestamp(msg[:11])
        self.latency = int(time() * 1000) - time0
        logging.debug("latency: %dms" % self.latency)
        raw_packet = "1" + "2" + msg[11:]
        to_write = self.cipher.encrypt(raw_packet) + self.split_char
        if self.transport:
            #logging.debug("send ping2")
            self.transport.write(to_write)

    def connectionMade(self):
        """Event handler of being successfully connected to the client."""
        logging.info("connected to client " +
                     addr_to_str(self.transport.getPeer()))
        self.transport.write(self.generate_auth_msg())

    def dataReceived(self, recv_data):
        """Event handler of receiving some data from client.

        Split, decrypt and hand them back to Control.
        """
        # Avoid repetition caused by ping
        # logging.debug("received %d bytes from client " % len(recv_data) +
        #              addr_to_str(self.transport.getPeer()))

        self.buffer += recv_data

        # a list of encrypted data packages
        # the last item may be incomplete
        recv = self.buffer.split(self.split_char)
        # leave the last (may be incomplete) item intact
        for text_enc in recv[:-1]:
            text_dec = self.cipher.decrypt(text_enc)
            # flag is 0 for normal data packet, 1 for ping packet
            flag = int(text_dec[0])
            if flag == 0:
                self.initiator.client_recv(text_dec[1:])
            elif flag == 2:
                if text_dec[1:] == "AUTHENTICATED" + self.idchar:
                    self.authenticate_success()
                else:
                    self.close()
            else:
                # strip off type and seq (both are always 1)
                self.ping_recv(text_dec[2:])

        self.buffer = recv[-1]  # incomplete message

    def authenticate_success(self):
        self.authenticated = True
        logging.debug("Authentication confirm string received.")
        self.initiator.add_cli(self)
        self.ping_send()

    def close(self):
        '''a secure way to abort the connection'''
        try:
            self.cronjob.cancel()
        except Exception:
            pass
        self.transport.loseConnection()

    def connectionLost(self, reason):
        """Event handler of losing the connection to the client.

        Call Control to handle it.
        """
        if self.authenticated:
            logging.info("client connection lost: " +
                         addr_to_str(self.transport.getPeer()))
        self.authenticated = False
        self.initiator.client_lost(self)

    def write(self, data, conn_id, index):
        """Encrypt and write data the client.

        Encrypted packets should be separated by split_char.
        Raw packet structure:
            type    (1 byte)   (0 for normal data packet)
            id      (2 bytes)
            index   (6 bytes)
            data
        """

        to_write = self.cipher.encrypt("0" + conn_id + index + data) +\
            self.split_char
        logging.debug("sending %d bytes to client %s with id %s" % (len(data),
                                                                    addr_to_str(
                                                                        self.transport.getPeer()),
                                                                    conn_id))
        self.transport.write(to_write)
Exemple #11
0
def callback(message):

    if (args.mode == "verify"):
        try:
            logging.info("********** Start PubsubMessage ")
            logging.info('Received message ID: {}'.format(message.message_id))
            logging.info('Received message publish_time: {}'.format(
                message.publish_time))
            logging.info('Received message attributes["kms_key"]: {}'.format(
                message.attributes['kms_key']))
            logging.debug(
                'Received message attributes["sign_key_wrapped"]: {}'.format(
                    message.attributes['sign_key_wrapped']))
            logging.info('Received message attributes["signature"]: {}'.format(
                message.attributes['signature']))
            signature = message.attributes['signature']
            name = message.attributes['kms_key']
            sign_key_wrapped = message.attributes['sign_key_wrapped']

            try:
                unwrapped_key = cache[sign_key_wrapped]
                logging.info("Using Cached DEK")
            except KeyError:
                logging.info(
                    ">>>>>>>>>>>>>>>>   Starting KMS decryption API call")
                decrypted_message = kms_client.decrypt(
                    request={
                        'name':
                        name,
                        'ciphertext':
                        base64.b64decode(sign_key_wrapped.encode('utf-8')),
                        'additional_authenticated_data':
                        tenantID.encode('utf-8')
                    })
                logging.info("Decrypted HMAC " +
                             decrypted_message.plaintext.decode('utf-8'))

                unwrapped_key = HMACFunctions(
                    encoded_key=decrypted_message.plaintext)
                logging.info(unwrapped_key.printKeyInfo())
                cache[sign_key_wrapped] = unwrapped_key

                logging.info("End KMS decryption API call")
                logging.debug("Verify message: " +
                              message.data.decode('utf-8'))
                logging.debug('  With HMAC: ' + signature)

            sig = unwrapped_key.hash(message.data)

            if (unwrapped_key.verify(message.data, base64.b64decode(sig))):
                logging.info("Message authenticity verified")
                message.ack()
            else:
                logging.error("Unable to verify message")
                message.nack()
            logging.debug("********** End PubsubMessage ")
        except Exception as e:
            logging.info("Unable to decrypt message; NACK pubsub message " +
                         str(e))
            message.nack()

    if (args.mode == "decrypt"):
        try:
            logging.info("********** Start PubsubMessage ")
            logging.info('Received message ID: {}'.format(message.message_id))
            logging.info('Received message publish_time: {}'.format(
                message.publish_time))
            logging.info('Received message attributes["kms_key"]: {}'.format(
                message.attributes['kms_key']))
            logging.info(
                'Received message attributes["dek_wrapped"]: {}'.format(
                    message.attributes['dek_wrapped']))
            dek_wrapped = message.attributes['dek_wrapped']
            name = message.attributes['kms_key']

            try:
                dek = cache[dek_wrapped]
                logging.info("Using Cached DEK")
            except KeyError:
                logging.info(
                    ">>>>>>>>>>>>>>>>   Starting KMS decryption API call")
                decrypted_message = kms_client.decrypt(
                    request={
                        'name': name,
                        'ciphertext': base64.b64decode(
                            dek_wrapped.encode('utf-8')),
                        'additional_authenticated_data': tenantID.encode(
                            'utf-8')
                    })
                logging.info("Decrypted DEK " +
                             decrypted_message.plaintext.decode('utf-8'))

                dek = AESCipher(encoded_key=decrypted_message.plaintext)
                logging.info(dek.printKeyInfo())
                cache[dek_wrapped] = dek

            logging.debug("Starting AES decryption")

            decrypted_data = dek.decrypt(message.data,
                                         associated_data=tenantID)
            logging.debug("End AES decryption")
            logging.info('Decrypted data ' + decrypted_data)
            message.ack()
            logging.debug("ACK message")
            logging.info("********** End PubsubMessage ")
        except Exception as e:
            logging.info("Unable to decrypt message; NACK pubsub message " +
                         str(e))
            message.nack()
Exemple #12
0
def callback(message):

    if (args.mode == "verify"):

        logging.info("********** Start PubsubMessage ")
        logging.info('Received message ID: {}'.format(message.message_id))
        logging.info('Received message publish_time: {}'.format(
            message.publish_time))
        logging.info('Received message attributes["kms_key"]: {}'.format(
            message.attributes['kms_key']))
        logging.info(
            'Received message attributes["sign_key_wrapped"]: {}'.format(
                message.attributes['sign_key_wrapped']))
        logging.info('Received message attributes["signature"]: {}'.format(
            message.attributes['signature']))
        signature = message.attributes['signature']
        name = message.attributes['kms_key']
        sign_key_wrapped = message.attributes['sign_key_wrapped']

        try:
            unwrapped_key = cache[sign_key_wrapped]
        except KeyError:
            logging.info("Starting KMS decryption API call")

            name = message.attributes['kms_key']
            unwrapped_key_struct = kms_client.decrypt(
                name=name,
                ciphertext=base64.b64decode(
                    message.attributes['sign_key_wrapped']),
                additional_authenticated_data=tenantID.encode('utf-8'))

            unwrapped_key = unwrapped_key_struct.plaintext

            logging.info("End KMS decryption API call")
            logging.debug("Verify message: " + message.data.decode('utf-8'))
            logging.debug('  With HMAC: ' + signature)
            logging.debug('  With unwrapped key: ' +
                          base64.b64encode(unwrapped_key).decode('utf-8'))
            cache[sign_key_wrapped] = unwrapped_key

        hh = HMACFunctions(unwrapped_key)
        sig = hh.hash(message.data)

        if (hh.verify(message.data, base64.b64decode(sig))):
            logging.info("Message authenticity verified")
            message.ack()
        else:
            logging.error("Unable to verify message")
            message.nack()
        logging.debug("********** End PubsubMessage ")

    if (args.mode == "decrypt"):
        logging.info("********** Start PubsubMessage ")
        logging.info('Received message ID: {}'.format(message.message_id))
        logging.debug('Received message publish_time: {}'.format(
            message.publish_time))
        logging.debug('Received message attributes["kms_key"]: {}'.format(
            message.attributes['kms_key']))
        logging.debug('Received message attributes["dek_wrapped"]: {}'.format(
            message.attributes['dek_wrapped']))
        dek_wrapped = message.attributes['dek_wrapped']
        name = message.attributes['kms_key']

        try:
            dek = cache[dek_wrapped]
        except KeyError:
            logging.info("Starting KMS decryption API call")

            name = message.attributes['kms_key']
            unwrapped_key_struct = kms_client.decrypt(
                name=name,
                ciphertext=base64.b64decode(dek_wrapped),
                additional_authenticated_data=tenantID.encode('utf-8'))

            dek = unwrapped_key_struct.plaintext

            logging.info("End KMS decryption API call")
            logging.info('Received aes_encryption_key : {}'.format(
                base64.b64encode(dek).decode('utf-8')))

            cache[dek_wrapped] = dek

        logging.debug("Starting AES decryption")
        ac = AESCipher(dek)
        decrypted_data = ac.decrypt(message.data, associated_data="")
        logging.debug("End AES decryption")
        logging.info('Decrypted data ' + decrypted_data)
        message.ack()
        logging.debug("ACK message")
        logging.info("********** End PubsubMessage ")