DOMANDA Qualcuno che mi aiuta capire un codice scritto in c?

Xeno_01

Nuovo Utente
16
1
Ciao a tutti, sto cercando di imparare il linguaggio c e mi sono imbattuto in questo sito in cui si trattava del cifrario di vigenere ma tramutato in c (mi interessano molto questi argomenti), solo che alcune cose non riesco a capirle ma vorrei tanto farlo per accumulare esperienza.
Innanzitutto il sito è questo: https://www.techiedelight.com/it/vigenere-cipher-implementation/

C:
for (i = n; i < size - 1; i++) {
        key[i] = key[i - n];
    }
 
    while (count != size)
    {
        ch = getc(in);
        if (isupper(ch)) {
            putc(table[key[count] - 65][ch - 65] + 65, out);
        }
        else {
            putc(table[key[count] - 65][ch - 97 + 26] + 97, out);
        }
        count++;
    }

in particolar modo, non riesco a capire il significato di quel ciclo for e poi non capisco cosa stiano ad indicare i numeri 65, 97 e 26. Il tutto si trova alla linea 56.
 
Ultima modifica:

ilfe98

Moderatore
Staff Forum
Utente Èlite
3,052
1,278
CPU
Intel i7 7700K
Dissipatore
Bequiet Dark rock pro 4
Scheda Madre
Msi pc mate z270
HDD
Seagate barracuda 1tb, silicon power NVME 500gb
RAM
Patriot viper steel 3733Mhz
GPU
Inno 3d gtx 1080 herculez design
Monitor
Asus mg279q
PSU
Corsair HX750
Case
Itek lunar 23
Net
Tiscali ftth
OS
windows 10,mint,debian,Arch linux
Viene utilizzato il valore ascii per stampare il carattere.
Per il for è legato al funzionamento della chiave, non ricordo esattamente il cifrario in questione come funzioni, appena ho tempo lo rispolvero
 

Xeno_01

Nuovo Utente
16
1
Viene utilizzato il valore ascii per stampare il carattere.
Per il for è legato al funzionamento della chiave, non ricordo esattamente il cifrario in questione come funzioni, appena ho tempo lo rispolvero
Ma volendo non potrebbe mettere il carattere direttamente al posto del codice ascii?
Poi ho visto che 26 corrisponde a "substitute", cosa sta ad indicare??
 

GraveKeeper

Utente Èlite
7,033
3,188
CPU
AMD Ryzen 7 3700X
Dissipatore
Enermax LiqMax III ARGB 240 Nero ARGB
Scheda Madre
Asus Tuf Gaming B550-PLUS (WIFI)
HDD
Samsung 970 EVO Plus 500GB NVMe + Crucial MX500 1TB + 2 x WD10EZEX Blue 1TB
RAM
Adata XPG Spectrix 16gb (2x8) 3200Mhz RGB
GPU
Asus NVIDIA GeForce GTX 750ti OC 2GB (in attesa di meglio)
Audio
Behringer U-PHORIA UM2 (chissà, magari un giorno prenderò una Scarlett Solo)
Monitor
LG 27GN800 UltraGear QHD IPS 27" 1ms 144Hz
PSU
ITEK GF 750W 80Gold
Case
NZXT H510i Nero
Periferiche
Studio Monitor Speakers Presonus Eris E3.5, Audio Technica ATH-M30x
OS
Windows 10 Home 64-bit
Ma volendo non potrebbe mettere il carattere direttamente al posto del codice ascii?
Poi ho visto che 26 corrisponde a "substitute", cosa sta ad indicare??

Avevao iniziato a guardarlo prima ed è complessino.

Allora innanzitutto la tabella creata è di 26*52 (che è 26*2) da quanto ho capito per avere 2 cifrari uno accanto all'altro, per distinguere le lettere maiuscole da quelle minuscole e usare questa singola grossa matrice come un unico cifrario per entrambi i tipi di caratteri.
Questo perchè nella tabella dei caratteri ascii, le lettere maiuscole hanno codici numerici differenti per ragioni ovvie.

Non puoi utilizzare il carattere direttamente perchè viene pensato come uno shiftare del carattere. In pratica sommando numeri al codice ascii iniziale, ottieni un numero finale corrispondente a un altro carattere, la lettera cifrata in base alla chiave.

Credo che si possa implementare anche creando una matrice di char e ricostituendo la nuova stringa da zero prendendo i caratteri giusti dalla tabella, però non ho capito per bene tutto il codice, c'è anche una parte di i/o su file mi pare di capire, e magari in quel caso l'input ottenuto dal file è di codici ascii e non caratteri, da cui l'implementazione tramite ascii.
 

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,223
1,854
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Si, potrebbe anche mettere il carattere. Quando prenderai un pò la mano però vedrai che alcune conversioni come quelle le farai in automatico a mente; non è ostico come sembra a prima vista.

A quanto deduco già solo dal codice che hai postato sopra, la tabella contiene degli indici, e metà della tabella viene usata per i caratteri minuscoli, mentre l'altra metà per quelli maiuscoli.

Guardando infatti la dimensione della matrice, si tratta di una 26x52: 26 righe, che è la quantità di lettere, e 52 colonne, che è il doppio di 26 (maiuscole e minuscole).

La key viene usata per identificare la riga della matrice da considerare (e fa -65 perchè è in maiuscolo la key):


La sua matrice però ha 26 colonne in più, per le minuscole. Come valore della colonna infatti seleziona ch - 97 + 26 (posizione dalla quale iniziano le minuscole) + 97, per convertire in ASCII.

Mi sembra complessa come implementazione, probabilmente anche in modo inutile.

Comunque quel codice ha un errore che mi sembra anche abbastanza grave, a prima vista:

C:
for (i = n; i < size - 1; i++) {
    key[i] = key[i - n];
}

qui va a scrivere nelle locazioni successive alla stringa, per "ripeterla" e portarla alla lunghezza del testo. Non mi sembra il modo corretto di farlo, anche perchè il testo non si sa quanto sarà lungo.
 
  • Mi piace
Reazioni: ilfe98

Xeno_01

Nuovo Utente
16
1
Si, potrebbe anche mettere il carattere. Quando prenderai un pò la mano però vedrai che alcune conversioni come quelle le farai in automatico a mente; non è ostico come sembra a prima vista.

A quanto deduco già solo dal codice che hai postato sopra, la tabella contiene degli indici, e metà della tabella viene usata per i caratteri minuscoli, mentre l'altra metà per quelli maiuscoli.

Guardando infatti la dimensione della matrice, si tratta di una 26x52: 26 righe, che è la quantità di lettere, e 52 colonne, che è il doppio di 26 (maiuscole e minuscole).

La key viene usata per identificare la riga della matrice da considerare (e fa -65 perchè è in maiuscolo la key):


La sua matrice però ha 26 colonne in più, per le minuscole. Come valore della colonna infatti seleziona ch - 97 + 26 (posizione dalla quale iniziano le minuscole) + 97, per convertire in ASCII.

Mi sembra complessa come implementazione, probabilmente anche in modo inutile.

Comunque quel codice ha un errore che mi sembra anche abbastanza grave, a prima vista:

C:
for (i = n; i < size - 1; i++) {
    key[i] = key[i - n];
}

qui va a scrivere nelle locazioni successive alla stringa, per "ripeterla" e portarla alla lunghezza del testo. Non mi sembra il modo corretto di farlo, anche perchè il testo non si sa quanto sarà lungo.
Innanzitutto vi devo ringraziare per il grande aiuto che mi state dando.
Non capisco il perché deve convertire la key in maiuscolo e poi nella table [][] non capisco quale dei due array corrisponda alla caratteri maiuscoli e minuscoli.
Poi dalla linea 53 alla 57 (o dalla 96 alla 107 nel metodo decrypt) non riesco proprio a capire il ragionamento dietro a quelle operazione..da quel poco che ho capito prende un carattere per volta con getc(), vede se il carattere è maiuscolo o minuscolo e in base a quello fa determinati calcoli. Poi ch essendo un char, quando viene fatto ch-65, come fa a capire che deve convertire in ascii?
Perdona le tante domande ma tutto ciò mi interessa assai.
P.s. il for come lo ottimizzeresti te?
 

GraveKeeper

Utente Èlite
7,033
3,188
CPU
AMD Ryzen 7 3700X
Dissipatore
Enermax LiqMax III ARGB 240 Nero ARGB
Scheda Madre
Asus Tuf Gaming B550-PLUS (WIFI)
HDD
Samsung 970 EVO Plus 500GB NVMe + Crucial MX500 1TB + 2 x WD10EZEX Blue 1TB
RAM
Adata XPG Spectrix 16gb (2x8) 3200Mhz RGB
GPU
Asus NVIDIA GeForce GTX 750ti OC 2GB (in attesa di meglio)
Audio
Behringer U-PHORIA UM2 (chissà, magari un giorno prenderò una Scarlett Solo)
Monitor
LG 27GN800 UltraGear QHD IPS 27" 1ms 144Hz
PSU
ITEK GF 750W 80Gold
Case
NZXT H510i Nero
Periferiche
Studio Monitor Speakers Presonus Eris E3.5, Audio Technica ATH-M30x
OS
Windows 10 Home 64-bit
Innanzitutto vi devo ringraziare per il grande aiuto che mi state dando.
Non capisco il perché deve convertire la key in maiuscolo e poi nella table [][] non capisco quale dei due array corrisponda alla caratteri maiuscoli e minuscoli.
Poi dalla linea 53 alla 57 (o dalla 96 alla 107 nel metodo decrypt) non riesco proprio a capire il ragionamento dietro a quelle operazione..da quel poco che ho capito prende un carattere per volta con getc(), vede se il carattere è maiuscolo o minuscolo e in base a quello fa determinati calcoli. Poi ch essendo un char, quando viene fatto ch-65, come fa a capire che deve convertire in ascii?
Perdona le tante domande ma tutto ciò mi interessa assai.
P.s. il for come lo ottimizzeresti te?

Per il fatto che converte la chiave in maiuscolo, la matrice è 26x52, non 52x52, quindi una delle 2 stringhe va interpretata con caratteri tutti minuscoli o tutti maiuscoli. In questo caso lo fa sulla chiave. Non so bene il motivo, immagino sia un qualche standard.

La table purtroppo è troppo larga da riuscire a visualizzare per bene e ragionarci sopra, avevo provato a fare una bella stampa in un compiler c online e comunque è bella grande.

A occhio dovrebbe essere la parte interna di questa tabella (quindi escludi la prima riga e la prima colonna come da foto), x2, quindi con un'altra uguale affiancata a sè stessa, e con i numeri da 0 a 25 al posto delle lettere da A a Z.

1658352196061.png

Volendo puoi incollare questo codice

C:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
 
int table[26][52];
 
void init_matrix()
{
    int i, j;
 
    for (i = 0; i < 26; i++)
    {
        for (j = 0; j < 26 - i; j++) {
            table[i][j] = j + i;
        }
 
        for (j = 26 - i; j < 26; j++) {
            table[i][j] = (j + i) - 26;
        }
 
        for (j = 26; j < 52 - i; j++) {
            table[i][j] = j + i - 26;
        }
 
        for (j = 52 - i; j < 52; j++) {
            table[i][j] = (j + i) - 52;
        }
    }
}

void print_matrix() {
    
    int i, j;
    
    for(i = 0; i < 26; i++) {
        for(j = 0; j < 52; j++) {
            printf("%d ", table[i][j]);
        }
        
        printf("\n");
        
    }
    
}

int main()
{
    init_matrix();
    print_matrix();
}

All'interno di questo compilatore online, e premere run per avere una risposta visiva della matrice dopo che è stata inizializzata, per quanto larga.

Questo assumendo che io ricordi ancora il c e non ho fatto cagate nella stampa.

Per la parte dopo che hai indicato, a rivederla è probabile che si stia lavorando sui char presi dall'input in effetti. Di norma in c come in molti altri linguaggi alle variabili di tipo char si possono sommare numeri interi tranquillamente, il codice si occuperà di conversioni di suo, e aggiungerà il numero al char_code corrispondente, creando un nuovo char_code e restituendo il carattere corrispondente al nuovo codice ascii. Questo almeno per quanto riguarda ascii.
 
  • Mi piace
Reazioni: ilfe98 e Xeno_01

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,223
1,854
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Innanzitutto vi devo ringraziare per il grande aiuto che mi state dando.
Non capisco il perché deve convertire la key in maiuscolo e poi nella table [][] non capisco quale dei due array corrisponda alla caratteri maiuscoli e minuscoli.
A giudicare da quell'if che hai mostrato si capisce che se le lettere minuscole iniziano dalla posizione 26 in avanti.

C:
        if (isupper(ch)) {
            putc(table[key[count] - 65][ch - 65] + 65, out);
        }
        else {
            putc(table[key[count] - 65][ch - 97 + 26] + 97, out);
        }

Poi dalla linea 53 alla 57 (o dalla 96 alla 107 nel metodo decrypt) non riesco proprio a capire il ragionamento dietro a quelle operazione..da quel poco che ho capito prende un carattere per volta con getc(), vede se il carattere è maiuscolo o minuscolo e in base a quello fa determinati calcoli.

Quello che viene fatto qui:

C:
    fseek(in, 0, SEEK_END);     // cerco di terminare il file
    size = ftell(in);           // ottiene il puntatore al file corrente
    fseek(in, 0, SEEK_SET);     // cerca di tornare all'inizio del file
 
    for (i = n; i < size - 1; i++) {
        key[i] = key[i - n];
    }
 
    while (count != size)
    {
        ch = getc(in);
        if (isupper(ch)) {
            putc(table[key[count] - 65][ch - 65] + 65, out);
        }
        else {
            putc(table[key[count] - 65][ch - 97 + 26] + 97, out);
        }
        count++;
    }

prima del for setta il puntatore al file (cursore) alla fine del file; poi legge il numero di bytes. In buona sostanza "size" conterrà la lunghezza del testo che è presente nel file. Poi il puntatore viene riposizionato all'inizio del file, in posizione 0.

L'algoritmo di Vigenere hai capito come funziona?
La prima colonna (quindi la posizione 0 di ogni riga), identifica il carattere della key.
La prima riga identifica invece il carattere da cifrare. Il punto in cui si intersecano le due rette è la lettera che ottieni come carattere cifrato.

La particolarità è che ogni singola riga, a partire dalla seconda, è shiftata di 1 posizione. Quindi la prima riga inizia con la lettera A, la seconda con B, la terza con C e via discorrendo.

Diciamo che hai questo testo da cifrare:
Codice:
TESTODIESEMPIO

e come key usi invece:
Codice:
TOMSHW

Come noti la lunghezza del testo e quello della key non coincide. Il ciclo for che vedi li sopra va a "colmare" la differenza.
In sostanza il ciclo inizia da n, lunghezza della key, e copia i caratteri stessi della key nelle posizioni successive, sino al raggiungimendo di 'size' (lunghezza del testo).

Quindi alla fine avrai:
Codice:
TESTODIESEMPIO
TOMSHWTOMSH

A questo punto il while usa un indice chiamato "count" per scorrere ogni singolo carattere della key, e di conseguenza del testo (sono lunghi uguali ora).
Tramite getc() legge, come dicevi, dal buffer di input, che in questo caso è il file aperto in precedenza.

Il carattere letto viene verificato con isupper per controllare se è maiuscolo o minuscolo: se è maiuscolo entra nell'if (riporto il codice, per comodità):

C:
        if (isupper(ch)) {
            putc(table[key[count] - 65][ch - 65] + 65, out);
        }
        else {
            putc(table[key[count] - 65][ch - 97 + 26] + 97, out);
        }

viene considerato quindi il carattere in posizione count (che sarà 0, al primo ciclo): l'elemento della riga della matrice viene ottenuto facendo key[count] - 65. Questo perchè viene preso il primo carattere della key, nell'esempio che ho fatto sopra la lettera 'T', e viene sottratto 65 ('A', in ASCII) = 19. La riga selezionata è la nr. 19 della matrice; se guardi la matrice messa anche sotto spoiler da Grave e conterai le righe della colonna 1, vedrai che la 19 sarà la lettera T.

La posizione del carattere da cifrare, quindi il testo in chiaro (letto dal file), lo si ottiene facendo ch-65: questo perchè 'ch' in questo momento è compreso tra 'A' e 'Z'. La matrice in queste posizioni contiene il numero 12: se sommi 12+65=77, che è la lettera M.

Se tiri una linea immaginaria dalla T della riga (perchè è la lettera della key che stiamo considerando) e dalla colonna T, vedrai che il punto di incontro è sulla M.

Poi ch essendo un char, quando viene fatto ch-65, come fa a capire che deve convertire in ascii?
Perdona le tante domande ma tutto ciò mi interessa assai.

Figurati, le domande sono sempre ben accette. ?
Praticamente tutti (non tutti in realtà) i linguaggi consentono di effettuare questa operazione; il cast del tipo avviene in automatico.

Da notare che lui non capisce che deve convertire in ASCII. Ogni numero (considera ad esempio la tabella linkata sopra da ilfe98) se lo casti esplicitamente in char ha una corrispondenza: ciò che succede è che viene preso il numero e viene mostrato sullo schermo secondo la codifica ASCII. Non tutti i caratteri sono visualizzabili, quindi se stampi caratteri non visualizzabili, vedrai dei simboli strani.

Considera l'Invio ad esempio (l'andare a capo): questo è un carattere non visualizzabile, in Windows è codificato con due byte noti come CR LF (fai riferimento sempre alla tabella ASCII): Carriege Return e Life Feed. In una stringa in C vedrai: \r\n. Se li stampi sul terminale e poi scrivi altro, vedrai che va a capo.
P.s. il for come lo ottimizzeresti te?

Cambierei ben più del for. Ho modificato un pò il codice mostrato sul sito:

C:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
 
int table[26][26];
 
void init_matrix()
{
    for (int i = 0; i < 26; i++)
    {
        for (int j = 0; j < 26; j++) {
            table[i][j] = (j + i) % 26;
        }
    } 
}
 
void encrypt(char *filename, char *key, int n)
{
    int count = 0, size = 0;
    char ch;
 
    FILE *in, *out;
    in = fopen(filename, "r");
    if (in == NULL)
    {
        printf("Cannot open source file.\n");
        exit(1);
    }
 
    out = fopen("CipherText.txt", "w+");
    if (out == NULL)
    {
        printf("Cannot open destination file.\n");
        exit(1);
    }
 
    fseek(in, 0, SEEK_END);     // cerco di terminare il file
    size = ftell(in);           // ottiene il puntatore al file corrente
    fseek(in, 0, SEEK_SET);     // cerca di tornare all'inizio del file
 
    for (int i = n; i < size - 1; i++) {
        key[i] = key[i - n];
    }
 
    while (count != size)
    {
        ch = getc(in);
     
        int ch_size = isupper(ch) ? 65 : 97;
        putc(table[key[count] - 65][ch - ch_size] + ch_size, out);

        count++;
    }
 
    fclose(in);
    fclose(out);
}
 
void decrypt(char *key)
{
    int size = 0, count = 0;
    char ch;
 
    FILE *in, *out;
    in = fopen("CipherText.txt", "r");
 
    if (in == NULL)
    {
        printf("Cannot open encrypted file.\n");
        exit(1);
    }
 
    out = fopen("DecryptedText.txt", "w+");
    if (out == NULL)
    {
        printf("Cannot open destination file.\n");
        exit(1);
    }
 
    fseek(in, 0, SEEK_END); // cerco di terminare il file
    size = ftell(in);    // ottiene il puntatore al file corrente
    fseek(in, 0, SEEK_SET); // cerca di tornare all'inizio del file
 
    while (count != size)
    {
        ch = getc(in);
        int ch_size = isupper(ch) ? 65 : 97;
 
        for (int i = 0; i < 26; i++)
        {
            if (table[key[count] - 65][i] == ch - ch_size) {
                fputc(i + ch_size, out);
            }
        }
     
        count++;
    }
    fclose(out);
    fclose(in);
}
 
// funzione principale
int main()
{
    char filename[] = "PlainText.txt";
 
    char key[] = "TOMSHW";
    int n = strlen(key);
 
    // converte la chiave in maiuscolo
    for (int j = 0; j < n; j++) {
        key[j] = toupper(key[j]);
    }
 
    init_matrix();
 
    // crittografa usando il codice Vigenère
    encrypt(filename, key, n);
 
    // decifrare usando il codice Vigenère
    decrypt(key);
 
    return 0;
}

Mi sembra più semplice di prima scritto in questo modo. Prova a dargli uno sguardo, poi domanda pure.

Faccio sempre notare che non ho risolto il bug presente, ovvero:
C:
    for (int i = n; i < size - 1; i++) {
        key[i] = key[i - n];
    }

mi sono infatti accorto che - ovviamente - produce problemi.

EDIT: se fai un print della tabella, ora è:

Codice:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 0
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 0 1
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 0 1 2
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 0 1 2 3
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 0 1 2 3 4
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 0 1 2 3 4 5
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 0 1 2 3 4 5 6
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 0 1 2 3 4 5 6 7
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 0 1 2 3 4 5 6 7 8
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 0 1 2 3 4 5 6 7 8 9
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 0 1 2 3 4 5 6 7 8 9 10
12 13 14 15 16 17 18 19 20 21 22 23 24 25 0 1 2 3 4 5 6 7 8 9 10 11
13 14 15 16 17 18 19 20 21 22 23 24 25 0 1 2 3 4 5 6 7 8 9 10 11 12
14 15 16 17 18 19 20 21 22 23 24 25 0 1 2 3 4 5 6 7 8 9 10 11 12 13
15 16 17 18 19 20 21 22 23 24 25 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
16 17 18 19 20 21 22 23 24 25 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
17 18 19 20 21 22 23 24 25 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
18 19 20 21 22 23 24 25 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
19 20 21 22 23 24 25 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
20 21 22 23 24 25 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
21 22 23 24 25 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
22 23 24 25 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
23 24 25 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
24 25 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
25 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

ovvero una 26x26.

PS. per evitare il bug si può sempre usare l'operazione "modulo". Ora sono da telefono, ma a occhio dovrebbe bastare un "count % n" come indice di key.
 
Ultima modifica:
  • Mi piace
Reazioni: ilfe98

Xeno_01

Nuovo Utente
16
1
La posizione del carattere da cifrare, quindi il testo in chiaro (letto dal file), lo si ottiene facendo ch-65: questo perchè 'ch' in questo momento è compreso tra 'A' e 'Z'. La matrice in queste posizioni contiene il numero 12: se sommi 12+65=77, che è la lettera M.
Mi hai aperto un mondo credimi. Vi ringrazio ancora. Non ho capito quel 12..ch la prima volta legge T, che equivale ad 84 che meno 65 fa 19.

Poi
C:
if (isupper(ch)) {
            putc(table[key[count] - 65][ch - 65] + 65, out);
        }
        else {
            putc(table[key[count] - 65][ch - 97 + 26] + 97, out);
        }
sempre in questa parte, nel caso in cui i caratteri sono minuscoli (ovvero l'else), perché fa - e + 97? che in ascii corrisponde ad "a"?

Ho visto il tuo codice ed ha dimezzato la table, in pratica hai tolto la differenza tra caratteri minuscoli e maiuscoli?
 

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,223
1,854
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Mi hai aperto un mondo credimi. Vi ringrazio ancora. Non ho capito quel 12..ch la prima volta legge T, che equivale ad 84 che meno 65 fa 19.

Oh, meno male, mi fa piacere. ?

Nel primo ciclo sia la lettera del testo da cifrare che la lettera della chiave sono la lettera T. La riga della matrice sarà quindi data da 84 - 65 = 19.
La colonna considerata sarà sempre 19 (ch - 65 = T - 65 = 19). Se usi la matrice numerica che ho riportato li sopra nel mio output, vedrai che il valore che otterrai sarà 12, perchè è l'incrocio tra riga 19 e colonna 19.

Poi
C:
if (isupper(ch)) {
            putc(table[key[count] - 65][ch - 65] + 65, out);
        }
        else {
            putc(table[key[count] - 65][ch - 97 + 26] + 97, out);
        }
sempre in questa parte, nel caso in cui i caratteri sono minuscoli (ovvero l'else), perché fa - e + 97? che in ascii corrisponde ad "a"?
Per lo stesso motivo che viene fatto -65 sopra: perchè ch è in ascii, avrà un valore compreso tra 97 e 122 ('a' - 'z'), quindi visto che la tabella è usata come una mappa, è necessario sottrarre il carattere che consideri al valore 'a'.

Guarda sempre il mio output numerico li sopra, che sono i valori di table: la prima riga da 0 a 25 mappa l'intero alfabeto da 'A' a 'Z' (maiuscoli e minuscoli, nel mio caso). E' come se nella riga 0, colonna 0, trovi il valore di A, nella colonna 1 di B e via sino alla Z.

Sapendo che A è nella prima posizione farai 'A' - 'A' (65 - 65) e accedi quindi alla colonna 0. Se ch = 'B' (66), farai 66 - 65, e accederai alla colonna 1.

Puoi vedere quella matrice come A=0, B=1, C=2,.... sino alla Z = 25.
La secona riga della tabella parte da 1 se noti, quindi è come se ci fosse B, e a seguire le altre lettere. Se noti è infatti questa la forma della tabella del cifrario di Vigenere.

Ho visto il tuo codice ed ha dimezzato la table, in pratica hai tolto la differenza tra caratteri minuscoli e maiuscoli?

Si, tolta nel senso che sono sufficienti 26 valori per rappresentarli tutti.
Il motivo è semplice: se A=0, B=1... Z=25 allora nel caso del suo algoritmo avevi 'a' = 26 = 0, 'b' = 27 = 1,... 'z' = 52 = 25 (questo per il conto che faceva, se noti arrivato a 25, ripartiva a contare da 0).
In pratica sia 'A' che 'a' avevano il medesimo valore, così come le altre lettere.

Ecco perchè era inutile avere una griglia di 26x52, in quanto 26 caratteri (i minuscoli) avevano in realtà i medesimi valori dei maiuscoli.

Se vuoi vedere l'output della sua tabella, compila il codice di @GraveKeeper

Ad ogni modo la versione corretta, senza il bug sulla key, è questa:

C:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
 
int table[26][26];
 
void init_matrix()
{
    for (int i = 0; i < 26; i++)
    {
        for (int j = 0; j < 26; j++) {
            table[i][j] = (j + i) % 26;
        }
    }
}
 
void encrypt(char *filename, char *key, int n)
{
    int count = 0, size = 0;
    char ch;
 
    FILE *in, *out;
    in = fopen(filename, "r");
    if (in == NULL)
    {
        printf("Cannot open source file.\n");
        exit(1);
    }
 
    out = fopen("CipherText.txt", "w+");
    if (out == NULL)
    {
        printf("Cannot open destination file.\n");
        exit(1);
    }
 
    fseek(in, 0, SEEK_END);
    size = ftell(in);
    fseek(in, 0, SEEK_SET);
 
    while (count < size)
    {
        ch = getc(in);
     
        int ch_size = isupper(ch) ? 65 : 97;
        putc(table[key[count % n] - 65][ch - ch_size] + ch_size, out);

        count++;
    }
 
    fclose(in);
    fclose(out);
}
 
void decrypt(char *key)
{
    int size = 0, count = 0;
    char ch;
 
    FILE *in, *out;
    in = fopen("CipherText.txt", "r");
 
    if (in == NULL)
    {
        printf("Cannot open encrypted file.\n");
        exit(1);
    }
 
    out = fopen("DecryptedText.txt", "w+");
    if (out == NULL)
    {
        printf("Cannot open destination file.\n");
        exit(1);
    }
 
    fseek(in, 0, SEEK_END); 
    size = ftell(in);
    fseek(in, 0, SEEK_SET);
 
    int n = strlen(key);
    while (count < size-1)
    {
        ch = getc(in);
        int ch_size = isupper(ch) ? 65 : 97;
 
        for (int i = 0; i < 26; i++)
        {
            if (table[key[count % n] - 65][i] == ch - ch_size) {
                fputc(i + ch_size, out);
            }
        }
     
        count++;
    }
    fclose(out);
    fclose(in);
}
 
// funzione principale
int main()
{
    char filename[] = "PlainText.txt";
 
    char key[] = "TOMSHW";
    int n = strlen(key);
 
    // converte la chiave in maiuscolo
    for (int j = 0; j < n; j++) {
        key[j] = toupper(key[j]);
    }
 
    init_matrix();
    encrypt(filename, key, n);
    decrypt(key);
 
    return 0;
}

Files (Input):
Codice:
TESTOdiPROVA

CipherText
Codice:
MSELVzbDDGCWg

Decrypted
Codice:
TESTOdiPROVA

la cosa migliore, per comprendere i concetti, è eserguire e fare delle prove modificando il codice, così vedi i risultati e cosa contengono le variabili.
 

Xeno_01

Nuovo Utente
16
1
Oh, meno male, mi fa piacere. ?

Nel primo ciclo sia la lettera del testo da cifrare che la lettera della chiave sono la lettera T. La riga della matrice sarà quindi data da 84 - 65 = 19.
La colonna considerata sarà sempre 19 (ch - 65 = T - 65 = 19). Se usi la matrice numerica che ho riportato li sopra nel mio output, vedrai che il valore che otterrai sarà 12, perchè è l'incrocio tra riga 19 e colonna 19.


Per lo stesso motivo che viene fatto -65 sopra: perchè ch è in ascii, avrà un valore compreso tra 97 e 122 ('a' - 'z'), quindi visto che la tabella è usata come una mappa, è necessario sottrarre il carattere che consideri al valore 'a'.

Guarda sempre il mio output numerico li sopra, che sono i valori di table: la prima riga da 0 a 25 mappa l'intero alfabeto da 'A' a 'Z' (maiuscoli e minuscoli, nel mio caso). E' come se nella riga 0, colonna 0, trovi il valore di A, nella colonna 1 di B e via sino alla Z.

Sapendo che A è nella prima posizione farai 'A' - 'A' (65 - 65) e accedi quindi alla colonna 0. Se ch = 'B' (66), farai 66 - 65, e accederai alla colonna 1.

Puoi vedere quella matrice come A=0, B=1, C=2,.... sino alla Z = 25.
La secona riga della tabella parte da 1 se noti, quindi è come se ci fosse B, e a seguire le altre lettere. Se noti è infatti questa la forma della tabella del cifrario di Vigenere.



Si, tolta nel senso che sono sufficienti 26 valori per rappresentarli tutti.
Il motivo è semplice: se A=0, B=1... Z=25 allora nel caso del suo algoritmo avevi 'a' = 26 = 0, 'b' = 27 = 1,... 'z' = 52 = 25 (questo per il conto che faceva, se noti arrivato a 25, ripartiva a contare da 0).
In pratica sia 'A' che 'a' avevano il medesimo valore, così come le altre lettere.

Ecco perchè era inutile avere una griglia di 26x52, in quanto 26 caratteri (i minuscoli) avevano in realtà i medesimi valori dei maiuscoli.

Se vuoi vedere l'output della sua tabella, compila il codice di @GraveKeeper

Ad ogni modo la versione corretta, senza il bug sulla key, è questa:

C:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
 
int table[26][26];
 
void init_matrix()
{
    for (int i = 0; i < 26; i++)
    {
        for (int j = 0; j < 26; j++) {
            table[i][j] = (j + i) % 26;
        }
    }
}
 
void encrypt(char *filename, char *key, int n)
{
    int count = 0, size = 0;
    char ch;
 
    FILE *in, *out;
    in = fopen(filename, "r");
    if (in == NULL)
    {
        printf("Cannot open source file.\n");
        exit(1);
    }
 
    out = fopen("CipherText.txt", "w+");
    if (out == NULL)
    {
        printf("Cannot open destination file.\n");
        exit(1);
    }
 
    fseek(in, 0, SEEK_END);
    size = ftell(in);
    fseek(in, 0, SEEK_SET);
 
    while (count < size)
    {
        ch = getc(in);
    
        int ch_size = isupper(ch) ? 65 : 97;
        putc(table[key[count % n] - 65][ch - ch_size] + ch_size, out);

        count++;
    }
 
    fclose(in);
    fclose(out);
}
 
void decrypt(char *key)
{
    int size = 0, count = 0;
    char ch;
 
    FILE *in, *out;
    in = fopen("CipherText.txt", "r");
 
    if (in == NULL)
    {
        printf("Cannot open encrypted file.\n");
        exit(1);
    }
 
    out = fopen("DecryptedText.txt", "w+");
    if (out == NULL)
    {
        printf("Cannot open destination file.\n");
        exit(1);
    }
 
    fseek(in, 0, SEEK_END);
    size = ftell(in);
    fseek(in, 0, SEEK_SET);
 
    int n = strlen(key);
    while (count < size-1)
    {
        ch = getc(in);
        int ch_size = isupper(ch) ? 65 : 97;
 
        for (int i = 0; i < 26; i++)
        {
            if (table[key[count % n] - 65][i] == ch - ch_size) {
                fputc(i + ch_size, out);
            }
        }
    
        count++;
    }
    fclose(out);
    fclose(in);
}
 
// funzione principale
int main()
{
    char filename[] = "PlainText.txt";
 
    char key[] = "TOMSHW";
    int n = strlen(key);
 
    // converte la chiave in maiuscolo
    for (int j = 0; j < n; j++) {
        key[j] = toupper(key[j]);
    }
 
    init_matrix();
    encrypt(filename, key, n);
    decrypt(key);
 
    return 0;
}

Files (Input):
Codice:
TESTOdiPROVA

CipherText
Codice:
MSELVzbDDGCWg

Decrypted
Codice:
TESTOdiPROVA

la cosa migliore, per comprendere i concetti, è eserguire e fare delle prove modificando il codice, così vedi i risultati e cosa contengono le variabili.
Perfetto sei stato chiarissimo e ti ringrazio veramente tanto per il tempo che mi hai dedicato?.
L'unica cosa che vorrei dirti è che nel codice fixato, mi da errore sul primo for della table.
C:
[Error] 'for' loop initial declarations are only allowed in C99 or C11 mode
Questo è quello che mi dice
 

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,223
1,854
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Perfetto sei stato chiarissimo e ti ringrazio veramente tanto per il tempo che mi hai dedicato?.
L'unica cosa che vorrei dirti è che nel codice fixato, mi da errore sul primo for della table.
C:
[Error] 'for' loop initial declarations are only allowed in C99 or C11 mode
Questo è quello che mi dice

Di niente. ?

Stai usando ANSI C invece delle versioni più recenti (c99 o c11, ad esempio).
Come compili esattamente?
 

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,223
1,854
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Che ambiente stai utilizzando per compilare? Che IDE?
Da riga di comando c'è un flag da passare, li dovrai aggiungerlo alle opzioni. Cerca online in base all'IDE che hai. Il flag se non vado errato è --std=c11.

Il decrypt è l'opposto dell'altro algoritmo. Ma qui dovresti capire il funzionamento di Vigenere, per capire il codice.
Comunque: prendiamo il caso di prima, il primo carattere cifrato è 'M'. La key è sempre 'T'. Viene fatta una ricerca usando il for da 0 a 26 per identificare la colonna che ha come valore ch-65 ovvero M - 65 che è uguale a 77 - 65.
Quando questo valore viene trovato in table, significa che nella colonna attuale (identificata da i), troverai il valore 12. Visto che la matrice è identica a prima, la colonna in questione è la 19 (i = 19): quindi viene inserito come carattere decifrato 19 + 65 = 84, che è la T.
 

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!