Exemplo n.º 1
0
class VirgilKeyGenerator(KeyGeneratorInterface):
    """
    Represents key pair entity for virgil_crypto lib usage only
    """
    def __init__(self,
                 key_type: str,
                 private_key=None,
                 public_key=None,
                 ec_type=VirgilKeyPair.Type_EC_SECP256R1,
                 hash_type=HashAlgorithm.SHA256):
        self._crypto = VirgilCrypto()
        self._crypto.signature_hash_algorithm = hash_type
        self.__hash_type = hash_type
        self.__key_type = key_type
        self.__ec_type = ec_type
        self.__public_key = None if not public_key else b64_to_bytes(
            public_key)
        self.__private_key = None if not private_key else b64_to_bytes(
            private_key)
        self.__key_id = None
        self.__signature = None
        self.device_serial = None

    def generate(self,
                 *,
                 signature_limit=None,
                 rec_pub_keys=None,
                 signer_key: Optional[KeyGeneratorInterface] = None,
                 private_key_base64: Optional[str] = None,
                 start_date: Optional[int] = 0,
                 expire_date: Optional[int] = 0,
                 meta_data: Optional[bytes] = bytes()):
        def make_signature():
            byte_buffer = io.BytesIO()

            # vs_pubkey_dated_t
            byte_buffer.write(
                start_date.to_bytes(4, byteorder='big', signed=False))
            byte_buffer.write(
                expire_date.to_bytes(4, byteorder='big', signed=False))
            byte_buffer.write(
                self.key_type_secmodule.to_bytes(1,
                                                 byteorder='big',
                                                 signed=False))
            byte_buffer.write(
                self.ec_type_secmodule.to_bytes(1,
                                                byteorder='big',
                                                signed=False))
            byte_buffer.write(
                len(meta_data).to_bytes(2, byteorder='big', signed=False))
            byte_buffer.write(meta_data)
            byte_buffer.write(b64_to_bytes(self.public_key))

            bytes_to_sign = byte_buffer.getvalue()
            return signer_key.sign(to_b64(bytes_to_sign), long_sign=False)

        if private_key_base64:
            self.__private_key = b64_to_bytes(private_key_base64)
            virgil_priv_key = self._crypto.import_private_key(
                self.__private_key)
            virgil_pubkey = self._crypto.extract_public_key(virgil_priv_key)
            self.__public_key = VirgilKeyPair.publicKeyToDER(
                virgil_pubkey.raw_key)[-65:]

        if self.__private_key is None:
            virgil_key_pair = VirgilKeyPair.generate(self.ec_type)
            self.__private_key = VirgilKeyPair.privateKeyToDER(
                virgil_key_pair.privateKey())
            self.__public_key = VirgilKeyPair.publicKeyToDER(
                virgil_key_pair.publicKey())[-65:]

        if signer_key:
            self.__signature = make_signature()

        return self

    @property
    def ec_type(self):
        return self.__ec_type

    @property
    def hash_type(self):
        return self.__hash_type

    @property
    def private_key(self):
        return to_b64(self.__private_key)

    @property
    def public_key(self):
        return to_b64(self.__public_key)

    @property
    def public_key_full(self):
        virgil_private_key = self._crypto.import_private_key(
            b64_to_bytes(self.private_key))
        return to_b64(self._crypto.extract_public_key(virgil_private_key))

    @property
    def signature(self):
        return self.__signature

    @property
    def key_id(self):
        return CRCCCITT().calculate(b64_to_bytes(self.public_key))

    @property
    def key_type(self):
        return self.__key_type

    def sign(self, data, long_sign=False):
        data = b64_to_bytes(data)
        private_key = b64_to_bytes(self.private_key)
        signature = self._crypto.sign(
            data, self._crypto.import_private_key(private_key))
        if not long_sign:
            signature = VirgilSignExtractor.extract_sign(signature)
        return to_b64(signature)

    def verify(self, data, signature, long_sign=False):
        data = b64_to_bytes(data)
        public_key = b64_to_bytes(
            self.public_key_full)  # verify  signature with full public key
        return self._crypto.verify(data, signature,
                                   self._crypto.import_public_key(public_key))

    def encrypt(self, data):
        data = b64_to_bytes(data)
        public_key = b64_to_bytes(
            self.public_key_full)  # encrypt with full public key
        encrypted = self._crypto.encrypt(
            data, self._crypto.import_public_key(public_key))
        return to_b64(encrypted)

    def decrypt(self, data):
        data = b64_to_bytes(data)
        private_key = b64_to_bytes(self.private_key)
        decrypted = self._crypto.decrypt(
            data, self._crypto.import_private_key(private_key))
        return to_b64(decrypted)
Exemplo n.º 2
0
class CardRequestsHandler:
    def __init__(self, ui, logger, api_url, app_token):
        self._ui = ui
        self._logger = logger
        self._crypto = VirgilCrypto()
        self._api_host = urlparse(api_url).netloc
        self._app_token = app_token

        self._keys_counter = {
        }  # used for identities calculation: auth_1, auth_2

    def _create_raw_card(self, key_pair: KeyGeneratorInterface,
                         key_info: dict) -> str:
        # Prepare public key in virgil format
        public_key = key_pair.public_key
        public_key = tiny_key_to_virgil(public_key)
        public_key = self._crypto.import_public_key(public_key)

        # Calculate identity.
        identity = key_pair.key_type
        # For keys which amount is 2 there should be identities like auth_1, auth_2
        if key_pair.key_type in (VSKeyTypeS.RECOVERY.value,
                                 VSKeyTypeS.AUTH.value,
                                 VSKeyTypeS.TRUSTLIST.value,
                                 VSKeyTypeS.FIRMWARE.value):
            if key_pair.key_type not in self._keys_counter or self._keys_counter[
                    key_pair.key_type] == 2:
                key_number = 1
            else:
                key_number = 2
            identity = "%s_%s" % (identity, key_number)
            self._keys_counter[key_pair.key_type] = key_number

        # Prepare card content snapshot
        created_at = int(datetime.utcnow().timestamp())
        card_content = RawCardContent(identity=identity,
                                      public_key=public_key,
                                      created_at=created_at)
        card_content_snapshot = card_content.content_snapshot

        # Create raw card
        raw_card = RawSignedModel(card_content_snapshot)

        # Sign combined snapshot (with key_info)
        key_info_b = json.dumps(key_info).encode("utf-8")
        key_info_b64 = to_b64(key_info_b)
        combined_snapshot = to_b64(
            b64_to_bytes(card_content_snapshot) + b64_to_bytes(key_info_b64))

        signature = key_pair.sign(combined_snapshot, long_sign=True)
        if not signature:
            err_msg = "[ERROR]: Virgil Card creation request: signing failed"
            self._ui.print_error(err_msg)
            self._logger.error(err_msg)
            sys.exit(1)

        raw_signature = RawSignature(
            signer="self",
            signature=b64_to_bytes(signature),
            signature_snapshot=b64_to_bytes(key_info_b64))

        # Append signature to card
        raw_card.signatures.append(raw_signature)

        # Return card request as json string
        return raw_card.to_json()

    def _register_card(self, card_b64):
        """
        Send card request to Things service
        """
        conn = http.client.HTTPSConnection(host=self._api_host)
        conn.request(method="POST",
                     url=CARD_REGISTRATION_ENDPOINT,
                     body=card_b64,
                     headers={"AppToken": self._app_token})
        response = conn.getresponse()
        resp_body = response.read()
        if response.status != 200:
            err_msg = (
                "[ERROR]: Failed to register Virgil card at {host}{endpoint}\n"
                "Card: {card_b64}\n"
                "Response status code: {status}\n"
                "Response body: {body}".format(
                    card_b64=card_b64,
                    host=self._api_host,
                    endpoint=CARD_REGISTRATION_ENDPOINT,
                    status=response.status,
                    body=resp_body))
            self._ui.print_error(err_msg)
            self._logger.error(err_msg)
            sys.exit(1)
        self._ui.print_message("Virgil Card for key successfully registered")
        self._logger.info("Card registered. Response: %s" % resp_body)

    def create_and_register_card(self, key: KeyGeneratorInterface,
                                 key_info: dict):
        card = self._create_raw_card(key, key_info)
        self._logger.info("Card request prepared: %s" % card)
        self._register_card(card)