Encrypt an ESP packet

        @param sa:   the SecurityAssociation associated with the ESP packet.
        @param esp:  an unencrypted _ESPPlain packet with valid padding
        @param key:  the secret key used for encryption

        @return:    a valid ESP packet encrypted with this algorithm

def encrypt(self, sa, esp, key):
        """
        Encrypt an ESP packet

        @param sa:   the SecurityAssociation associated with the ESP packet.
        @param esp:  an unencrypted _ESPPlain packet with valid padding
        @param key:  the secret key used for encryption

        @return:    a valid ESP packet encrypted with this algorithm
        """
        data = esp.data_for_encryption()

        if self.cipher:
            mode_iv = self._format_mode_iv(algo=self, sa=sa, iv=esp.iv)
            cipher = self.new_cipher(key, mode_iv)
            encryptor = cipher.encryptor()

            if self.is_aead:
                aad = struct.pack('!LL', esp.spi, esp.seq)
                encryptor.authenticate_additional_data(aad)
                data = encryptor.update(data) + encryptor.finalize()
                data += encryptor.tag[:self.icv_size]
            else:
                data = encryptor.update(data) + encryptor.finalize()

        return ESP(spi=esp.spi, seq=esp.seq, data=esp.iv + data)