# Path: resources/lib/nvhttp/pairinghash/sha256pairinghash.py
# class Sha256PairingHash(AbstractPairingHash):
#     def get_hash_length(self):
#         return 32
# 
#     def hash_data(self, data):
#         m = hashlib.sha256()
#         m.update(data)
#         return bytearray(m.digest())
# 
# Path: resources/lib/nvhttp/pairinghash/sha1pairinghash.py
# class Sha1PairingHash(AbstractPairingHash):
#     def get_hash_length(self):
#         return 20
# 
#     def hash_data(self, data):
#         m = hashlib.sha1()
#         m.update(data)
#         return bytearray(m.digest())
# 
# Path: resources/lib/nvhttp/pairingmanager/abstractpairingmanager.py
# class AbstractPairingManager(object):
#     __metaclass__ = ABCMeta
# 
#     STATE_NOT_PAIRED = 0
#     STATE_PAIRED = 1
#     STATE_PIN_WRONG = 2
#     STATE_FAILED = 3
# 
#     @abstractmethod
#     def pair(self, request_service, server_info, dialog):
#         pass
# 
#     def unpair(self, request_service, server_info):
#         try:
#             request_service.open_http_connection(
#                 request_service.base_url_http + '/unpair?' + request_service.build_uid_uuid_string(),
#                 True
#             )
#         except ValueError:
#             # Unpairing a host needs to be fire and forget
#             pass
# 
#     @staticmethod
#     def get_pair_state(request_service, server_info):
#         if request_service.get_xml_string(server_info, 'PairStatus') != '1':
#             return AbstractPairingManager.STATE_NOT_PAIRED
#         else:
#             return AbstractPairingManager.STATE_PAIRED
# 
#     @staticmethod
#     def generate_pin_string():
#         return '%s%s%s%s' % (random.randint(0, 9), random.randint(0, 9), random.randint(0, 9), random.randint(0, 9))
# 
#     @staticmethod
#     def update_dialog(pin, dialog):
#         pin_message = 'Please enter the PIN: %s' % pin
#         dialog.update(0, pin_message)


import binascii
import hashlib
import random
from Crypto.Cipher import AES
from Crypto.Util import asn1
from M2Crypto import X509
from resources.lib.nvhttp.pairinghash.sha256pairinghash import Sha256PairingHash
from resources.lib.nvhttp.pairinghash.sha1pairinghash import Sha1PairingHash
from resources.lib.nvhttp.pairingmanager.abstractpairingmanager import AbstractPairingManager

        enc_srv_challenge_response = self._hex_to_bytes(request_service.get_xml_string(challenge_response, 'challengeresponse'))
        dec_srv_challenge_response = self._decrypt_aes(enc_srv_challenge_response, aes_key)

        srv_response = dec_srv_challenge_response[:hash_algo.get_hash_length()]
        srv_challenge = dec_srv_challenge_response[hash_algo.get_hash_length():hash_algo.get_hash_length() + 16]

        client_secret = self._get_random_bytes(16)
        challenge_response_hash = hash_algo.hash_data(
            self._concat_bytes(
                self._concat_bytes(srv_challenge, self.crypto_provider.extract_cert_signature(self.cert)),
                client_secret
            )
        )
        enc_challenge_response = self._encrypt_aes(challenge_response_hash, aes_key)

        secret_response = request_service.open_http_connection(
            request_service.base_url_http + '/pair?' + request_service.build_uid_uuid_string() +
            '&devicename=roth&updateState=1&serverchallengeresp=' + self.bytes_to_hex(enc_challenge_response),
            True
        )
        if int(request_service.get_xml_string(secret_response, 'paired')) != 1:
            request_service.open_http_connection(
                request_service.base_url_http + '/unpair?' + request_service.build_uid_uuid_string(),
                True
            )
            return self.STATE_FAILED

        srv_secret_response = self._hex_to_bytes(request_service.get_xml_string(secret_response, 'pairingsecret'))
        srv_secret = srv_secret_response[:16]

# Path: resources/lib/nvhttp/pairinghash/sha256pairinghash.py
# class Sha256PairingHash(AbstractPairingHash):
#     def get_hash_length(self):
#         return 32
# 
#     def hash_data(self, data):
#         m = hashlib.sha256()
#         m.update(data)
#         return bytearray(m.digest())
# 
# Path: resources/lib/nvhttp/pairinghash/sha1pairinghash.py
# class Sha1PairingHash(AbstractPairingHash):
#     def get_hash_length(self):
#         return 20
# 
#     def hash_data(self, data):
#         m = hashlib.sha1()
#         m.update(data)
#         return bytearray(m.digest())
# 
# Path: resources/lib/nvhttp/pairingmanager/abstractpairingmanager.py
# class AbstractPairingManager(object):
#     __metaclass__ = ABCMeta
# 
#     STATE_NOT_PAIRED = 0
#     STATE_PAIRED = 1
#     STATE_PIN_WRONG = 2
#     STATE_FAILED = 3
# 
#     @abstractmethod
#     def pair(self, request_service, server_info, dialog):
#         pass
# 
#     def unpair(self, request_service, server_info):
#         try:
#             request_service.open_http_connection(
#                 request_service.base_url_http + '/unpair?' + request_service.build_uid_uuid_string(),
#                 True
#             )
#         except ValueError:
#             # Unpairing a host needs to be fire and forget
#             pass
# 
#     @staticmethod
#     def get_pair_state(request_service, server_info):
#         if request_service.get_xml_string(server_info, 'PairStatus') != '1':
#             return AbstractPairingManager.STATE_NOT_PAIRED
#         else:
#             return AbstractPairingManager.STATE_PAIRED
# 
#     @staticmethod
#     def generate_pin_string():
#         return '%s%s%s%s' % (random.randint(0, 9), random.randint(0, 9), random.randint(0, 9), random.randint(0, 9))
# 
#     @staticmethod
#     def update_dialog(pin, dialog):
#         pin_message = 'Please enter the PIN: %s' % pin
#         dialog.update(0, pin_message)


# Path: resources/lib/nvhttp/pairingmanager/advancedpairingmanager.py
import binascii
import hashlib
import random
from Crypto.Cipher import AES
from Crypto.Util import asn1
from M2Crypto import X509
from resources.lib.nvhttp.pairinghash.sha256pairinghash import Sha256PairingHash
from resources.lib.nvhttp.pairinghash.sha1pairinghash import Sha1PairingHash
from resources.lib.nvhttp.pairingmanager.abstractpairingmanager import AbstractPairingManager


        enc_srv_challenge_response = self._hex_to_bytes(request_service.get_xml_string(challenge_response, 'challengeresponse'))
        dec_srv_challenge_response = self._decrypt_aes(enc_srv_challenge_response, aes_key)

        srv_response = dec_srv_challenge_response[:hash_algo.get_hash_length()]
        srv_challenge = dec_srv_challenge_response[hash_algo.get_hash_length():hash_algo.get_hash_length() + 16]

        client_secret = self._get_random_bytes(16)
        challenge_response_hash = hash_algo.hash_data(
            self._concat_bytes(
                self._concat_bytes(srv_challenge, self.crypto_provider.extract_cert_signature(self.cert)),
                client_secret
            )
        )
        enc_challenge_response = self._encrypt_aes(challenge_response_hash, aes_key)

        secret_response = request_service.open_http_connection(
            request_service.base_url_http + '/pair?' + request_service.build_uid_uuid_string() +
            '&devicename=roth&updateState=1&serverchallengeresp=' + self.bytes_to_hex(enc_challenge_response),
            True
        )
        if int(request_service.get_xml_string(secret_response, 'paired')) != 1:
            request_service.open_http_connection(
                request_service.base_url_http + '/unpair?' + request_service.build_uid_uuid_string(),
                True
            )
            return self.STATE_FAILED

        srv_secret_response = self._hex_to_bytes(request_service.get_xml_string(secret_response, 'pairingsecret'))
        srv_secret = srv_secret_response[:16]

        srv_signature = srv_secret_response[16:272]