Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Avatar
Paragoon2
Člen
Avatar
Paragoon2:6.11.2023 1:51
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel, QLineEdit, QPushButton, QVBoxLayout, QWidget, QMessageBox, QTableWidget, QTableWidgetItem, QGridLayout, QPlainTextEdit
from PyQt6.uic import loadUi
from random import shuffle, choice
from itertools import product, accumulate
from numpy import floor, sqrt

class ADFGVXCipherApp(QMainWindow):
    def __init__(self):
        super().__init__()
        loadUi("gui.ui", self)  # Load the UI from the XML file


        self.encrypt_button.clicked.connect(self.encrypt_message)
        self.decrypt_button.clicked.connect(self.decrypt_message)
        self.alphabet_entry.textChanged.connect(self.update_alphabet_table)
        self.alphabet_entry.textChanged.connect(self.check_alphabet)

        self.display_adfgvx_pairs_button.clicked.connect(self.display_adfgvx_pairs)
        self.update_key_button.clicked.connect(self.update_key_table)
        self.display_decrypt_pairs_button.clicked.connect(self.display_decryption_adfgvx_pairs)

        self.decrypt_key_table_button.clicked.connect(self.decrypt_key_table)

        self.generate_alphabet_button.clicked.connect(self.generate_random_alphabet)

        self.alphabet_entry.textChanged.connect(self.validate_alphabet)

    ALLOWED_CHARACTERS = {
        'ADFGVX': 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
        'ADFGX_CZ': 'ABCDEFGHIKLMNOPQRSTUVWXYZ',
        'ADFGX_EN': 'ABCDEFGHIJKLMNOPQRSTUVXYZ',
    }

    def prepare_input_message(self, input_message, mode):
        # Převeďte vstupní zprávu na velká písmena
        input_message = input_message.upper()

        # Pro režim ADFGX_CZ: Nahraďte 'J' za 'I'
        if mode == 'ADFGX_CZ':
            input_message = input_message.replace('J', 'I')

        # Pro režim ADFGX_EN: Nahraďte 'W' za 'V'
        if mode == 'ADFGX_EN':
            input_message = input_message.replace('W', 'V')

        return input_message

    def validate_alphabet(self, text):
        # Get the current text from alphabet_entry
        current_text = self.alphabet_entry.text().upper()

        # Ensure that each character in the current text is allowed
        allowed_chars = self.ALLOWED_CHARACTERS[self.alphabet_mode_combobox.currentText()]
        valid_text = ''.join(char for char in current_text if char in allowed_chars)

        # Update the text in alphabet_entry with only valid characters
        self.alphabet_entry.setText(valid_text)


    def decrypt_key_table(self):
        try:
            # Získání klíče pro dešifrování z pole vstupního klíče
            decryption_key_text = self.decryption_key.text().upper()

            # Získání zašifrovaného textu z pole zašifrovaného vstupu
            ciphertext = self.ciphertext_entry2.text().upper()

            # Seřazení klíče abecedně
            sorted_decryption_key = ''.join(sorted(decryption_key_text))

            # Nastavení seřazeného klíče v prvním řádku tabulky
            decrypt_key_table = self.findChild(QTableWidget, 'decrypt_table')
            decrypt_key_table.setRowCount(1)
            decrypt_key_table.setColumnCount(len(sorted_decryption_key))
            for i, char in enumerate(sorted_decryption_key):
                item = QTableWidgetItem(char)
                decrypt_key_table.setItem(0, i, item)

            # Spočítáme počet řádků na základě délky šifrovaného textu a délky klíče
            num_rows = (len(ciphertext) + len(sorted_decryption_key) - 1) // len(sorted_decryption_key)
            decrypt_key_table.setRowCount(num_rows)

            # Naplníme tabulku podle sloupců, ne řádků, použijeme seřazený klíč
            for i, char in enumerate(ciphertext):
                row = i % num_rows
                col = i // num_rows
                item = QTableWidgetItem(char)
                decrypt_key_table.setItem(row, col, item)

            # Upravit šířku sloupců, aby se vešlo obsah
            decrypt_key_table.resizeColumnsToContents()
        except Exception as e:
            # Zachycení a zpracování výjimky (chyby)
            error_message = str(e)  # Získání textového popisu chyby
            self.show_error("Error", f"An error occurred: {error_message}")

    def display_decryption_adfgvx_pairs(self):
        encrypted_message = self.decrypted_message_entry.toPlainText().upper()
        key = self.encryption_key.text().upper()
        alphabet = self.alphabet_entry.text().upper()
        adfgvx_pairs = []

        for char in encrypted_message:
            if char in alphabet:
                encoded_char = self.encrypt_ADFGVX(char, key)
                adfgvx_pairs.append(encoded_char)

        # Reverse each character in adfgvx_pairs for the second row
        adfgvx_pairs_second_row = [pair[::-1] for pair in adfgvx_pairs]

        # Create a new QTableWidget with 2 rows and the same number of columns as the encrypted message length
        num_columns = len(adfgvx_pairs)  # Use the length of adfgvx_pairs
        self.decrypt_pairs_table.setColumnCount(num_columns)
        self.decrypt_pairs_table.setRowCount(2)

        # Set the encrypted_message in the first row
        for i, char in enumerate(encrypted_message):
            item = QTableWidgetItem(char)
            self.decrypt_pairs_table.setItem(0, i, item)

        # Set the reversed ADFGVX pairs in the second row
        for i, pair in enumerate(adfgvx_pairs_second_row):
            item = QTableWidgetItem(pair)
            self.decrypt_pairs_table.setItem(1, i, item)

        # Adjust column widths to fit the content
        self.decrypt_pairs_table.resizeColumnsToContents()

    def update_key_table(self):
        message_pairs_table = self.findChild(QTableWidget, 'message_pairs_table')
        if not message_pairs_table.item(0, 0):
            self.show_error("Error", "Please display ADFGVX pairs first.")
            return

        encryption_key_text = self.encryption_key.text().upper()
        message_pairs_table = self.findChild(QTableWidget, 'message_pairs_table')
        key_table = self.findChild(QTableWidget, 'key_table')

        num_columns = message_pairs_table.columnCount()
        encryption_key_length = len(encryption_key_text)

        # Create a dictionary to map characters to their position in the key
        char_to_position = {}
        char_count = {}  # Počet výskytů každého znaku v klíči

        # Počítání výskytů znaků v klíči
        for char in encryption_key_text:
            if char in char_count:
                char_count[char] += 1
            else:
                char_count[char] = 1

        # Calculate the number of rows needed to display the entire message
        num_rows = (num_columns + encryption_key_length - 1) // encryption_key_length

        # Create the key table with the appropriate number of rows and columns
        key_table.setRowCount(num_rows)
        key_table.setColumnCount(encryption_key_length)

        # Replace characters with their position in the key for matching characters
        for i in range(encryption_key_length):
            char = encryption_key_text[i]
            if char_count[char] > 1:
                if char in char_to_position:
                    char_to_position[char] += 1
                else:
                    char_to_position[char] = 1
                item = QTableWidgetItem(f"{char_to_position[char]}")
            else:
                item = QTableWidgetItem(char)
            key_table.setItem(0, i, item)

        # Get the text from the second row of the message_pairs_table
        adfgvx_text = [message_pairs_table.item(1, i).text() for i in range(num_columns)]

        # Split the pairs into individual characters
        individual_characters = [char for pair in adfgvx_text for char in pair]

        # Populate the key table with the individual characters from message_pairs_table
        for i, char in enumerate(individual_characters):
            row = (i // encryption_key_length) + 1
            col = i % encryption_key_length
            if char_count.get(char, 0) > 1:
                if char in char_to_position:
                    item = QTableWidgetItem(f"{char_to_position[char]}")
                else:
                    item = QTableWidgetItem(char)
            else:
                item = QTableWidgetItem(char)
            # If the row doesn't exist, create it
            while row >= key_table.rowCount():
                key_table.insertRow(key_table.rowCount())
            key_table.setItem(row, col, item)

        # Adjust column widths to fit the content
        key_table.resizeColumnsToContents()

    def display_adfgvx_pairs(self):
        input_message = self.input_message.text().upper()
        key = self.encryption_key.text().upper()
        alphabet = self.alphabet_entry.text().upper()
        adfgvx_pairs = []

        for char in input_message:
            if char in alphabet:
                encoded_char = self.encrypt_ADFGVX(char, key)
                adfgvx_pairs.append(encoded_char)  # Append only the encoded character

        # Reverse each character in adfgvx_pairs for the second row
        adfgvx_pairs_second_row = [pair[::-1] for pair in adfgvx_pairs]

        # Create a new QTableWidget with 2 rows and the same number of columns as the input message length
        num_columns = len(adfgvx_pairs)  # Use the length of adfgvx_pairs
        self.message_pairs_table.setColumnCount(num_columns)
        self.message_pairs_table.setRowCount(2)

        # Set the input_message in the first row
        for i, char in enumerate(input_message):
            item = QTableWidgetItem(char)
            self.message_pairs_table.setItem(0, i, item)

        # Set the reversed ADFGVX pairs in the second row
        for i, pair in enumerate(adfgvx_pairs_second_row):
            item = QTableWidgetItem(pair)
            self.message_pairs_table.setItem(1, i, item)

        # Adjust column widths to fit the content
        self.message_pairs_table.resizeColumnsToContents()

    def check_alphabet(self, text):
        # Získáme aktuální text z alphabet_entry
        current_text = self.alphabet_entry.text().upper()

        # Odstraníme duplicity znaků
        unique_characters = ''.join(sorted(set(current_text), key=current_text.index))

        # Aktualizujeme text v alphabet_entry
        self.alphabet_entry.setText(unique_characters)

    def update_alphabet_table(self):
        alphabet = self.alphabet_entry.text().upper()
        alphabet_table = self.findChild(QTableWidget, 'alphabet_table')

        num_rows = 0
        num_columns = 0
        custom_row_headers = []
        custom_col_headers = []
        missing_characters = set()

        # Determine the dimensions, headers, and missing characters based on the selected mode
        mode_index = self.alphabet_mode_combobox.currentIndex()
        if mode_index == 0:  # ADFGVX
            num_rows = 6
            num_columns = 6
            custom_row_headers = ['A', 'D', 'F', 'G', 'V', 'X']
            custom_col_headers = ['A', 'D', 'F', 'G', 'V', 'X']
            missing_characters = set("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") - set(alphabet)
        elif mode_index == 1:  # ADFGX_CZ
            num_rows = 5
            num_columns = 5
            custom_row_headers = ['A', 'D', 'F', 'G', 'V', 'X']
            custom_col_headers = ['A', 'D', 'F', 'G', 'X']
            missing_characters = set("ABCDEFGHIKLMNOPQRSTUVWXYZ") - set(alphabet)
        elif mode_index == 2:  # ADFGX_EN
            num_rows = 5
            num_columns = 5
            custom_row_headers = ['A', 'D', 'F', 'G', 'V', 'X']
            custom_col_headers = ['A', 'D', 'F', 'G', 'X']
            missing_characters = set("ABCDEFGHIJKLMNOPQRSTUVXYZ") - set(alphabet)

        alphabet_table.setRowCount(num_rows)
        alphabet_table.setColumnCount(num_columns)

        used_characters = set()

        for row in range(num_rows):
            for col in range(num_columns):
                index = row * num_columns + col
                if index < len(alphabet):
                    char = alphabet[index]
                    item = QTableWidgetItem(char)
                    alphabet_table.setItem(row, col, item)
                    used_characters.add(char)
                else:
                    item = QTableWidgetItem('')
                    alphabet_table.setItem(row, col, item)

        missing_characters_text = ", ".join(sorted(missing_characters))
        self.missing_characters_label.setText(f"Chybějící znaky: {missing_characters_text}")

        # Set the custom row headers
        for row, header in enumerate(custom_row_headers):
            alphabet_table.setVerticalHeaderItem(row, QTableWidgetItem(header))

        # Set the custom column headers
        for col, header in enumerate(custom_col_headers):
            alphabet_table.setHorizontalHeaderItem(col, QTableWidgetItem(header))

    def generate_random_alphabet(self):
        mode_index = self.alphabet_mode_combobox.currentIndex()
        modes = ['ADFGVX', 'ADFGX_CZ', 'ADFGX_EN']  # Add more modes as needed
        selected_mode = modes[mode_index] if 0 <= mode_index < len(modes) else 'ADFGVX'

        if selected_mode == 'ADFGVX':
            alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
        elif selected_mode == 'ADFGX_CZ':
            alphabet = 'ABCDEFGHIKLMNOPQRSTUVWXYZ'
        elif selected_mode == 'ADFGX_EN':
            alphabet = 'ABCDEFGHIJKLMNOPQRSTUVXYZ'
        else:
            # Default to ADFGVX alphabet if the mode is not recognized
            alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'

        custom_dictionary = [alphabet[i:i + 6] for i in range(0, len(alphabet), 6)]
        shuffle(custom_dictionary)
        self.alphabet_entry.setText(''.join(custom_dictionary))
        self.update_alphabet_table()

    # Add a function to handle mode selection
    def select_alphabet_mode(self, index):
        modes = ['ADFGVX', 'ADFGX_CZ', 'ADFGX_EN']  # Add more modes as needed
        selected_mode = modes[index] if 0 <= index < len(modes) else 'ADFGVX'
        self.generate_random_alphabet(selected_mode)

    def create_encode_dict(self):
        """ Create the ADFGVX encoding dictionary. """
        matrices = list('ADFGVX')
        pairs = [p[0] + p[1] for p in product(matrices, matrices)]
        return dict(zip(self.alphabet_entry.text().upper(), pairs))

    def encrypt_ADFGVX(self, msg, key):
        """ Encrypt with the ADFGVX cipher. """
        alphabet = list(self.alphabet_entry.text().upper())
        key = list(key.upper())
        pdim = int(floor(sqrt(len(alphabet))))
        encode = self.create_encode_dict()

        chars = []
        for c in msg.upper():
            if c in alphabet:
                chars.extend(encode[c])
            elif c.isspace():  # Replace spaces with a special character
                chars.append('Q')  # Use '#' as the special character for spaces

        colvecs = [(lett, chars[i:len(chars):len(key)]) for (i, lett) in enumerate(key)]
        colvecs.sort(key=lambda x: x[0])
        return ''.join([''.join(a[1]) for a in colvecs])

    def decrypt_ADFGVX(self, cod, key):
        """ Decrypt with the ADFGVX cipher. Preserves spacing in encoded text """
        matrices = list('ADFGVX')
        chars = [c for c in cod if c in matrices or c == 'Q']  # Recognize and replace the special character
        key = list(key.upper())
        sortedkey = sorted(key)
        order = [key.index(ch) for ch in sortedkey]
        originalorder = [sortedkey.index(ch) for ch in key]
        base, extra = divmod(len(chars), len(key))
        strides = [base + (1 if extra > i else 0) for i in order]
        starts = list(accumulate(strides[:-1], lambda x, y: x + y))
        starts = [0] + starts
        ends = [starts[i] + strides[i] for i in range(len(key))]
        cols = [chars[starts[i]:ends[i]] for i in originalorder]
        pairs = []
        for i in range((len(chars) - 1) // len(key) + 1):
            for j in range(len(key)):
                if i * len(key) + j < len(chars):
                    pairs.append(cols[j][i])

        decode = dict((v, k) for (k, v) in self.create_encode_dict().items())
        plaintext = ''.join([decode[pairs[i] + pairs[i + 1]] for i in range(0, len(pairs), 2)])

        # Replace the special character '#' with spaces
        plaintext = plaintext.replace('Q', ' ')

        return plaintext

    def generate_alphabet(self):
        self.generate_random_alphabet()
        self.update_alphabet_table()

    def handle_alphabet_mode_change(self, index):
        self.generate_random_alphabet()

    def encrypt_message(self):
        input_message = self.input_message.text()
        key = self.encryption_key.text()
        mode = self.alphabet_mode_combobox.currentText()

        # Předzpracujte vstupní zprávu podle režimu
        processed_input_message = self.prepare_input_message(input_message, mode)

        if not processed_input_message or not key or not self.alphabet_entry.text():
            self.show_error("Error", "Please enter message, key, and alphabet")
            return

        ciphertext = self.encrypt_ADFGVX(processed_input_message, key)
        self.ciphertext_entry.setPlainText(ciphertext)

    def decrypt_message(self):
        ciphertext = self.ciphertext_entry2.text()
        key = self.decryption_key.text()
        alphabet = self.alphabet_entry.text().upper()

        if not ciphertext or not key or not alphabet:
            self.show_error("Error", "Please enter ciphertext, key, and alphabet")
            return

        try:
            # Kontrola délky šifrovaného textu a klíče
            if len(ciphertext) % len(key) != 0:
                self.show_error("Decryption Error",
                                "Ciphertext length is not compatible with the decryption key length.")
                return

            decrypted_message = self.decrypt_ADFGVX(ciphertext, key)
            self.decrypted_message_entry.setPlainText(decrypted_message)
        except Exception as e:
            self.show_error("Decryption Error", f"An error occurred during decryption: {str(e)}")

    def show_error(self, title, message):
        msg_box = QMessageBox(self)
        msg_box.setIcon(QMessageBox.Icon.Critical)
        msg_box.setWindowTitle(title)
        msg_box.setText(message)
        msg_box.exec()

def main():
    app = QApplication(sys.argv)
    ex = ADFGVXCipherApp()
    ex.show()
    sys.exit(app.exec())

if __name__ == '__main__':
    main()

Chci docílit: Potřeboval bych pomoct, nejde mi dosahnout zachovaní mezer, snažil jsem se nahradit mezeru jiným znakem ale dešifrování nefunguje

 
Odpovědět
6.11.2023 1:51
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:6.11.2023 8:47

Ten kod mi prijde dost zmateny. V ALLOWED_CHARACTERS nemas mezeru. A asi nijak nesouvisi s dalsim kodem, protoze alfabeth generujes zcela nezavisle od tohoto pole. Takze, kdyz neco zmenis v jednom, musis to upravovat i v tom druhem. A kdyz jsi externi programator, tak nevis, ze ten clovek to ma na dvou mistech, nijak nepropojenych, dokud nezjistis, ze uprava na miste A se nijak neprojevila :) A ted koukam, ze tam mas jeste misto C.

ALLOWED_CHARACTERS
alphabet
missing_characters

Jinak, nechce se mi ten kod vice studovat. Prijde mi to pomerne slozite. Bylo by mozne treba napsat, jak to sifrovani ma presne probihat, nebo, jakou sifru to mas?

Ja treba prisel na to, ze mnohem efektivnejsi je pouzit nejake nezvyke sifrovani. Treba posupn pismen.
kod = pismeno + poradi pismene ve slove + 1 (predchozi pismeno samohlaska) -2 (predchozi pismeno souhlaska)
Zkus to lustit beznymi metodami :) Pripade, predchozi pismeno pouzij ze zasifrovaneho kodu ne vychozi zpravy

Editováno 6.11.2023 8:48
Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
 
Nahoru Odpovědět
6.11.2023 8:47
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 2 zpráv z 2.