def __encrypt_symmetric_key(symmetric_key: bytes,
                             public_keys: List[IPublicKey]) -> List[bytes]:
     key_encryptions = []
     for public_key in public_keys:
         encryption = Constants.PUBLIC_KEY_ALGORITHM().encrypt_bytes(
             symmetric_key, public_key)
         key_encryptions.append(encryption)
     return key_encryptions
Beispiel #2
0
    def send_message(self, message_type: MessageType, message: str, recipients: List[str]) -> (int, int, int):
        recipients_public_keys = []
        for recipient in recipients:
            public_key = Constants.PUBLIC_KEY_ALGORITHM().get_public_key_class().parse(bytes.fromhex(recipient))
            recipients_public_keys.append(public_key)

        sender = self.selected_user
        return MessageService.send_message(sender=sender, message_type=message_type, message=message, recipients_public_keys=recipients_public_keys)
    def __parse_plain_message_block(
            blockchain_message_block: BlockchainMessageBlock, timestamp: int,
            compression_algorithm: CompressionAlgorithm,
            encoding: Encoding) -> Message:

        public_key_algorithm = Constants.PUBLIC_KEY_ALGORITHM()
        message_block_as_bytes = blockchain_message_block.data

        byte_index = Constants.FLAGS_LENGTH

        signature_length = public_key_algorithm.signature_length()
        signature = message_block_as_bytes[byte_index:byte_index +
                                           signature_length]
        byte_index += signature_length

        message_content = message_block_as_bytes[:Constants.
                                                 FLAGS_LENGTH]  # flags
        message_content += message_block_as_bytes[byte_index:]

        compressed_data = message_block_as_bytes[byte_index:]
        decompressed_data = Compressor.decompress(
            algorithm=compression_algorithm, data=compressed_data)
        byte_index = 0

        message_type_bytes = decompressed_data[byte_index:byte_index +
                                               Constants.MESSAGE_TYPE_LENGTH]
        byte_index += Constants.MESSAGE_TYPE_LENGTH
        message_type_value = struct.unpack('!B', message_type_bytes)[0]
        message_type = MessageType(message_type_value)

        public_key_length = public_key_algorithm.get_public_key_class(
        ).key_length()
        sender_bytes = decompressed_data[byte_index:byte_index +
                                         public_key_length]
        byte_index += public_key_length
        sender = public_key_algorithm.get_public_key_class().parse(
            sender_bytes)

        nonce_timestamp = GeneralUtils.decode_unix_timestamp(
            decompressed_data[byte_index:byte_index +
                              Constants.TIMESTAMP_LENGTH])
        byte_index += Constants.TIMESTAMP_LENGTH

        message_bytes = decompressed_data[byte_index:]

        encoding_str = Encoding.get_str(encoding)
        message = message_bytes.decode(encoding_str)

        MessageBlockParser.__check_signature(message=message_content,
                                             public_key=sender,
                                             signature=signature)

        return Message(block_hash=blockchain_message_block.block_hash,
                       sender=sender,
                       message_type=message_type,
                       message=message,
                       timestamp=timestamp,
                       nonce_timestamp=nonce_timestamp)
    def __build_encrypted_message_block(
            message: str,
            message_type: MessageType,
            sender: User,
            recipients_public_keys: List[IPublicKey],
            encoding: Encoding = Constants.DEFAULT_ENCODING) -> MessageBlock:
        public_key_algorithm = Constants.PUBLIC_KEY_ALGORITHM()

        content_to_be_compressed = b''

        encoding_str = Encoding.get_str(encoding)
        encoded_message = message.encode(encoding=encoding_str)

        message_type_value = struct.pack('!B', message_type.value)
        assert len(message_type_value) == Constants.MESSAGE_TYPE_LENGTH
        content_to_be_compressed += message_type_value

        sender_public_key = sender.encryption_key_pair.public_key.to_bytes()
        assert len(
            sender_public_key) == public_key_algorithm.get_public_key_class(
            ).key_length()
        content_to_be_compressed += sender_public_key
        content_to_be_compressed += GeneralUtils.get_current_unix_timestamp(
        )  # nonce timestamp

        content_to_be_compressed += encoded_message

        compression_algorithm, compressed_content = Compressor.compress_with_best_algorithm(
            content_to_be_compressed)

        compressed_content_length = struct.pack('!H', len(compressed_content))
        assert len(
            compressed_content_length) == Constants.MESSAGE_LENGTH_LENGTH
        content_to_be_encrypted = compressed_content_length + compressed_content

        symmetric_key = CryptoUtils.generate_random_symmetric_key()
        assert len(symmetric_key) == Constants.SYMMETRIC_KEY_LENGTH
        key_encryptions = MessageBlockBuilder.__encrypt_symmetric_key(
            symmetric_key=symmetric_key, public_keys=recipients_public_keys)
        for key_encryption in key_encryptions:
            assert len(
                key_encryption
            ) == public_key_algorithm.symmetric_key_encryption_length()

        encrypted_data, iv = CryptoUtils.encrypt_bytes(
            symmetric_key=symmetric_key, message=content_to_be_encrypted)
        assert len(iv) == Constants.AES_BLOCK_SIZE

        return EncryptedMessageBlock(
            iv=iv,
            encrypted_content=encrypted_data,
            compression_algorithm=compression_algorithm,
            key_encryptions=key_encryptions,
            encoding=encoding,
            encryption_key_pair=sender.encryption_key_pair)
Beispiel #5
0
    def create_user_with_ether(self, amount_of_ether: int) -> int:
        if amount_of_ether > 0:
            eth_keys = AccountService().create_account_with_ether(amount_of_ether)
        else:
            eth_keys = AccountService().create_account()
        encryption_key_pair = Constants.PUBLIC_KEY_ALGORITHM().generate_random_key_pair()
        user = User(eth_key_pair=eth_keys, encryption_key_pair=encryption_key_pair)
        self.users.append(user)
        user_index = len(self.users)-1
        if user_index == 0:
            self.selected_user_index = user_index

        self.users_messages[user.eth_key_pair.public_key] = []
        self.users_lastest_fetch_time[user.eth_key_pair.public_key] = 0

        return user_index
    def __get_key(message_block_as_bytes: bytes,
                  private_key: IPrivateKey) -> bytes:
        assert MessageBlockParser.__is_encrypted(message_block_as_bytes)

        public_key_algorithm = Constants.PUBLIC_KEY_ALGORITHM()
        symmetric_key_encryption_length = public_key_algorithm.symmetric_key_encryption_length(
        )

        byte_index = 0
        candidate_encrypted_key = message_block_as_bytes[
            -symmetric_key_encryption_length:]
        while len(candidate_encrypted_key) == symmetric_key_encryption_length:
            try:
                return public_key_algorithm.decrypt_bytes(
                    candidate_encrypted_key, private_key)
            except UnableToDecrypt:
                byte_index -= symmetric_key_encryption_length
                candidate_encrypted_key = message_block_as_bytes[
                    -symmetric_key_encryption_length + byte_index:byte_index]

        raise NotIntendedReceiver  # Message block is not addressed to the private key
Beispiel #7
0
    def get_test_users() -> List[User]:

        public_key_algorithm = Constants.PUBLIC_KEY_ALGORITHM()

        encryption_key_pair_A = public_key_algorithm.generate_random_key_pair()
        # TODO: define user A Ethereum key pair (from Ganache)
        eth_public_key_A = '__PUBLIC_KEY_A__'
        eth_private_key_A = '__PRIVATE_KEY_A__'
        eth_key_pair_A = EthKeyPair(public_key=eth_public_key_A,
                                    private_key=eth_private_key_A)
        user_A = User(eth_key_pair=eth_key_pair_A,
                      encryption_key_pair=encryption_key_pair_A)

        encryption_key_pair_B = public_key_algorithm.generate_random_key_pair()
        # TODO: define user B Ethereum key pair (from Ganache)
        eth_public_key_B = '__PUBLIC_KEY_B__'
        eth_private_key_B = '__PRIVATE_KEY_B__'
        eth_key_pair_B = EthKeyPair(public_key=eth_public_key_B,
                                    private_key=eth_private_key_B)
        user_B = User(eth_key_pair=eth_key_pair_B,
                      encryption_key_pair=encryption_key_pair_B)

        return [user_A, user_B]
 def __check_signature(message: bytes, public_key: IPublicKey,
                       signature: bytes):
     if not Constants.PUBLIC_KEY_ALGORITHM().verify_signature(
             message=message, signature=signature, public_key=public_key):
         raise InvalidSignature
    def __parse_encrypted_message_block(
            blockchain_message_block: BlockchainMessageBlock,
            private_key: IPrivateKey,
            compression_algorithm: CompressionAlgorithm,
            encoding: Encoding) -> Message:

        public_key_algorithm = Constants.PUBLIC_KEY_ALGORITHM()
        message_block_as_bytes = blockchain_message_block.data

        byte_index = Constants.FLAGS_LENGTH

        signature = message_block_as_bytes[byte_index:byte_index +
                                           public_key_algorithm.
                                           signature_length()]
        byte_index += public_key_algorithm.signature_length()

        message_content = message_block_as_bytes[:Constants.
                                                 FLAGS_LENGTH]  #flags
        message_content += message_block_as_bytes[byte_index:]
        iv = message_block_as_bytes[byte_index:byte_index +
                                    Constants.AES_BLOCK_SIZE]
        byte_index += Constants.AES_BLOCK_SIZE

        encrypted_content_and_keys = message_block_as_bytes[byte_index:]
        symmetric_key = MessageBlockParser.__get_key(message_block_as_bytes,
                                                     private_key)

        byte_index = 0
        first_block = encrypted_content_and_keys[byte_index:byte_index +
                                                 Constants.AES_BLOCK_SIZE]
        decrypted_first_block = CryptoUtils.decrypt_bytes(
            symmetric_key=symmetric_key,
            ciphertext=first_block,
            iv=iv,
            unpad_bytes=False)

        compressed_content_length = struct.unpack(
            '!H', decrypted_first_block[:Constants.MESSAGE_LENGTH_LENGTH])[0]

        encrypted_content_length = Constants.MESSAGE_LENGTH_LENGTH + compressed_content_length

        # Adjust length for padding
        if encrypted_content_length % Constants.AES_BLOCK_SIZE != 0:
            encrypted_content_length += Constants.AES_BLOCK_SIZE - encrypted_content_length % Constants.AES_BLOCK_SIZE

        encrypted_content = encrypted_content_and_keys[:
                                                       encrypted_content_length]
        decrypted_content = CryptoUtils.decrypt_bytes(
            symmetric_key=symmetric_key, ciphertext=encrypted_content, iv=iv)
        compressed_content = decrypted_content[Constants.
                                               MESSAGE_LENGTH_LENGTH:]

        decompressed_content = Compressor.decompress(
            algorithm=compression_algorithm, data=compressed_content)

        message_type_value = struct.unpack(
            '!B', decompressed_content[:Constants.MESSAGE_TYPE_LENGTH])[0]
        message_type = MessageType(message_type_value)

        byte_index = Constants.MESSAGE_TYPE_LENGTH

        public_key_length = public_key_algorithm.get_public_key_class(
        ).key_length()
        sender = public_key_algorithm.get_public_key_class().parse(
            decompressed_content[byte_index:byte_index + public_key_length])
        byte_index += public_key_length

        nonce_timestamp = GeneralUtils.decode_unix_timestamp(
            decompressed_content[byte_index:byte_index +
                                 Constants.TIMESTAMP_LENGTH])
        byte_index += Constants.TIMESTAMP_LENGTH

        encoding_str = Encoding.get_str(encoding)
        message = decompressed_content[byte_index:].decode(encoding_str)

        MessageBlockParser.__check_signature(message=message_content,
                                             public_key=sender,
                                             signature=signature)

        return Message(block_hash=blockchain_message_block.block_hash,
                       sender=sender,
                       message_type=message_type,
                       message=message,
                       timestamp=blockchain_message_block.timestamp,
                       nonce_timestamp=nonce_timestamp)
def generate_public_key() -> str:
    return Constants.PUBLIC_KEY_ALGORITHM().generate_random_key_pair(
    ).public_key.to_bytes().hex()
Beispiel #11
0
 def __sign(self, private_key: IPrivateKey) -> bytes:
     public_key_algorithm = Constants.PUBLIC_KEY_ALGORITHM()
     return public_key_algorithm.sign(self.flags + self.content, private_key)