[Algoritmi, C] Crittoanalisi
Salve, tempo fa svolsi un esercizio di informatica che chiedeva di sviluppare un semplice algoritmo di cifratura la cui traccia chiedeva di sommare ad ogni carattere di una stringa il carattere della chiave. A questo algoritmo ora ho implementato un paio di elaborazioni in più sul testo molto dipendenti dalla chiave di cifratura scelta. L'algoritmo è il seguente:
La crittazione avviene sia nel main con i cicli for (che possono essere resi con uno unico, li ho separati per renderlo più leggibile, non più ottimizzato), sia nelle funzioni; infatti nel primo for si svolge quello che faceva anche il vecchio algoritmo, nel secondo la crittazione richiama le funzioni; nella funzione lettere(), che conta quante vocali e consonanti ci sono nella chiave, si decide alla fine anche quale valore ritornare in base alle caratteristiche della chiave inserita (lunghezza della chiave, parità o disparità della lunghezza).
Secondo voi, rispetto al primo algoritmo, a quali debolezze va incontro il secondo? A quali mette una toppa?
Come può essere violato il secondo algoritmo analiticamente senza ricorrere alla forza bruta sulla chiave?
E quali migliorie sono possibili con altre operazioni sulla stringa usando sempre le informazioni date dalla chiave quali la lunghezza, numero di vocali, consonanti ecc.. per creare un algoritmo crittografico si amatoriale, ma anche non banale?
Ho cercato, forse invano se si conosce l'algoritmo, di rendere leggermente più complessa un'analisi statistica sulle occorrenze dell'algoritmo originale (perchè nell'algoritmo proposto i caratteri della stringa testo[] vengono cifrati diversamente in base alla posizione nell'array). Ad una prima occhiata al testo cifrato possono anche sembrare che non ce ne siano, ma non ne sono convinto visto che caratteri raggruppati 2 a 2 hanno lo stesso algoritmo di crittazione... ci vorrebbe un'informazione pseudocasuale derivabile dalla chiave immessa.
Inoltre riflettendo un attimo sulle tecniche di crittoanalisi differenziale, non credo che creare più relazioni tra testo cifrato e chiave costituisca un vantaggio, anzi, probabilmente più regole fisse ha un algoritmo crittografico e più è vulnerabile. Ma anche di questo non sono certo. Cosa ne pensate?
PS: non ho la presunzione di creare un algoritmo sicuro per i moderni metodi di crittoanalisi, è solo un esercizio, vorrei però conoscere a quali tecniche può essere vulnerabile una cosa del genere e quali aggiustamenti possono essere fatti con soluzioni semplici, usando gli elementi ricavabili dalla chiave.
#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX 100000 long long int maiuscole(long long int lunghezza, char chiave[]); long long int lettere(long long int lunghezza, char chiave[], long long int condizione); int main(){ char testo[MAX]; /*Testo in chiaro*/ char chiave[MAX]; /*Chiave per cifrare*/ char file[MAX]; /*File scrittura cifra*/ char r1[MAX]; /*Vettore cifrato in scrittura*/ char r2[MAX]; /*Vettore decifrato in lettura*/ char v1[MAX]; /*Vettore decifrato stampa*/ char r3[MAX]; /*tmp*/ long long int i, x; printf("\nInserisci il testo da cifrare: "); getchar(); fgets(testo, sizeof(testo), stdin); testo[strlen(testo) - 1] = '\0'; printf("\nInserisci la chiave di cifratura: "); fgets(chiave, sizeof(chiave), stdin); chiave[strlen(chiave) - 1] = '\0'; printf("\nInserisci il nome del file su cui salvare il testo cifrato: "); fgets(file, sizeof(file), stdin); file[strlen(file) - 1] = '\0'; //Cifratura for(i=0; i<strlen(testo); i++){ r1[i] = testo[i] + chiave[i%strlen(chiave)]; } for(i=0; i<strlen(r1); i++){ r1[i] = (r1[i] + lettere(strlen(chiave), chiave, i)) - maiuscole(strlen(chiave), chiave); } //Scrittura sul file specificato FILE *fp; fp = fopen(file, "w"); fprintf(fp, "%s", r1); fclose(fp); printf("\n\t***Crittazione avvenuta con successo***\a"); printf("\n\t\t***Scrittura su file***\n\n"); system("PAUSE"); printf("\n"); //Leggo il contenuto cifrato del file specificato prima FILE *pf; pf = fopen(file, "r"); i = 0; while(fscanf(pf, "%c", &r2[i]) == 1){ i++; } fclose(pf); //Decifratura for(i=0; i<strlen(r2); i++){ r3[i] = (r2[i] - lettere(strlen(chiave), chiave, i)) + maiuscole(strlen(chiave), chiave); } for(i=0; i<strlen(r3); i++){ v1[i] = r3[i] - chiave[i%strlen(chiave)]; } printf("\n\nIl testo decifrato e':\n\n%s\n", v1); printf("\n\t***Decrittazione completata con successo***\a\n"); system("PAUSE"); return 0; } //Definizioni delle funzioni long long int maiuscole(long long int lunghezza, char chiave[]){ long long int i, minuscola, maiuscola=0; for(i=0; i<=lunghezza; i++){ if(64<chiave[i]<91){ maiuscola++; } } minuscola = lunghezza - maiuscola; //In caso si voglia modificare l'algoritmo anche con questa variabile if(maiuscola == 0){ return maiuscola + 1; }else{ return maiuscola; } } long long int lettere(long long int lunghezza, char chiave[], long long int condizione){ long long int i, vocale=0, consonante=0; for(i=0; i<=lunghezza; i++){ if(96<chiave[i]<123 || 64<chiave[i]<91){ if(chiave[i]=='a' || chiave[i]=='A' || chiave[i]=='e' || chiave[i]=='E' || chiave[i]=='i' || chiave[i]=='I' || chiave[i]=='o' || chiave[i]=='O' || chiave[i]=='u' || chiave[i]=='U'){ vocale++; }else{ consonante++; } } } if(lunghezza%2 == 0){ if(condizione%2 == 0){ return (vocale + (lunghezza/2)); }else{ return consonante; } }else{ if(condizione%2 == 0){ return vocale; }else{ return consonante + lunghezza; } } }
La crittazione avviene sia nel main con i cicli for (che possono essere resi con uno unico, li ho separati per renderlo più leggibile, non più ottimizzato), sia nelle funzioni; infatti nel primo for si svolge quello che faceva anche il vecchio algoritmo, nel secondo la crittazione richiama le funzioni; nella funzione lettere(), che conta quante vocali e consonanti ci sono nella chiave, si decide alla fine anche quale valore ritornare in base alle caratteristiche della chiave inserita (lunghezza della chiave, parità o disparità della lunghezza).
Secondo voi, rispetto al primo algoritmo, a quali debolezze va incontro il secondo? A quali mette una toppa?
Come può essere violato il secondo algoritmo analiticamente senza ricorrere alla forza bruta sulla chiave?
E quali migliorie sono possibili con altre operazioni sulla stringa usando sempre le informazioni date dalla chiave quali la lunghezza, numero di vocali, consonanti ecc.. per creare un algoritmo crittografico si amatoriale, ma anche non banale?
Ho cercato, forse invano se si conosce l'algoritmo, di rendere leggermente più complessa un'analisi statistica sulle occorrenze dell'algoritmo originale (perchè nell'algoritmo proposto i caratteri della stringa testo[] vengono cifrati diversamente in base alla posizione nell'array). Ad una prima occhiata al testo cifrato possono anche sembrare che non ce ne siano, ma non ne sono convinto visto che caratteri raggruppati 2 a 2 hanno lo stesso algoritmo di crittazione... ci vorrebbe un'informazione pseudocasuale derivabile dalla chiave immessa.
Inoltre riflettendo un attimo sulle tecniche di crittoanalisi differenziale, non credo che creare più relazioni tra testo cifrato e chiave costituisca un vantaggio, anzi, probabilmente più regole fisse ha un algoritmo crittografico e più è vulnerabile. Ma anche di questo non sono certo. Cosa ne pensate?
PS: non ho la presunzione di creare un algoritmo sicuro per i moderni metodi di crittoanalisi, è solo un esercizio, vorrei però conoscere a quali tecniche può essere vulnerabile una cosa del genere e quali aggiustamenti possono essere fatti con soluzioni semplici, usando gli elementi ricavabili dalla chiave.
Risposte
Volevo inserire anche uno xor logico nelle elaborazioni ma ho capito solo di recente alcuni errori che commettevo che non facevano funzionare il programma, per esempio nell'uso della funzione strlen(), che con lo xor non va d'accordo. Intendo una cosa del genere:
Per la funzione strlen() chiesi anche in altri forum e dissero che probabilemente era quella che interpretava male gli zeri che generava lo xor, ma ora il problema è che quando prendo questo algoritmo e ne faccio qualcosa di più con letture e scritture su file tipo il precedente non funziona più. Come può essere reso? Di cosa non mi sto rendendo conto che mi porta fuori strada?
#include <stdio.h> #define MAX 10000 int lunghezza(char stringa[]); int main(){ int i; char input1[MAX]; /*Testo in chiaro*/ char input2[MAX]; /*Chiave di cifratura*/ char output1[MAX]; /*Stringa cifrata*/ char output2[MAX]; /*Stringa decifrata*/ printf("\nInserisci la frase: "); fgets(input1, sizeof(input1), stdin); input1[lunghezza(input1) - 1] = '\0'; printf("\nLa frase inserita e': %s\n", input1); printf("\nInserisci la chiave: "); fgets(input2, sizeof(input2), stdin); input2[lunghezza(input2) - 1] = '\0'; printf("\nLa chiave inserita e': %s", input2); for(i=0; i<lunghezza(input1); i++){ output1[i] = input1[i] ^ input2[i%lunghezza(input2)]; } output1[i] = '\0'; printf("\n\nLa stringa cifrata e': %s\n", output1); for(i=0; i<lunghezza(output1); i++){ output2[i] = output1[i] ^ input2[i%lunghezza(input2)]; } output2[i] = '\0'; printf("\n\nLa stringa decifrata e': %s\n\n", output2); system("PAUSE"); return 0; } //Definizioni int lunghezza(char stringa[]){ int i = 0; while(stringa[i] != '\0'){ i++; } return i; }
Per la funzione strlen() chiesi anche in altri forum e dissero che probabilemente era quella che interpretava male gli zeri che generava lo xor, ma ora il problema è che quando prendo questo algoritmo e ne faccio qualcosa di più con letture e scritture su file tipo il precedente non funziona più. Come può essere reso? Di cosa non mi sto rendendo conto che mi porta fuori strada?
Il tuo problema con strlen è quello segnalato negli altri forum, senza probabilmente. D'altra parte non hai alcun bisogno di ricalcolare tutte le volte strlen. Anche per ragioni di performance: ha complessità lineare e non costante! E la funzione con cui lo sostituisci è anche peggio di strlen, siccome la stringa non termina con EOF. Inoltre non risolve il problema; di fatto è impossibile risolvere il problema a meno di assicurarsi che il messaggio finale non contenga alcuno 0. Cosa che è possibile e in un certo senso anche preferibile.
Già, l'errore sta nel fare lo xor tra char e leggerli come char. Si potrebbe risolvere facendo una copia sia del testo da cifrare sia della chiave su array di int eseguendo la codifica xor su questi.
Comuque giustissima l'osservazione sull'EOF, correggo subito.
Per il primo algoritmo di cifratura? Qualche falla sfruttabile facilmente c'è?
Comuque giustissima l'osservazione sull'EOF, correggo subito.
Per il primo algoritmo di cifratura? Qualche falla sfruttabile facilmente c'è?
Nessuno?
Con questo output non vedo niente di strano se non che nella prima codifica il testo cifrato è più corto di quello in chiaro:
Posso notare che i testi cifrati cambiano tantissimo anche con cambiamenti lievi della chiave immessa e che non è possibile, almeno mi pare, risalire al testo in chiaro attraverso l'analisi delle frequenze.
L'unico dubbio è sulla lunghezza delle stringhe cifrate che non sempre sono della stessa lunghezza del testo in chiaro (ad un attaccante che non conosce niente sia del testo che della chiave non penso di avergli semplificato la vita con questa caratteristica, per uno che invece può fare analisi differenziali, cioè vedere come cambia un testo immettendo varie chiavi, potrebbe essere semplice perchè questo comportamento fa risalire ad una caratteristica della chiave e quindi alle altre, anche se ancora non ho ben capito quale).
Con questo output non vedo niente di strano se non che nella prima codifica il testo cifrato è più corto di quello in chiaro:
Testo: Questa è una prova per analizzare l'output della codifica. Cod: œéÏëгû‘عՊèÎÁãÒ‘Ó°æŠÙʳÙÚëݬæÏ˜ÈyÜæåÓÀèŠÜÁ¾ÙґƺØÓÞŵΟ Chiave: Prova Testo: Questa è una prova per analizzare l'output della codifica. Cod: žäÑæÒŒmùŒèÌŒmßÞâÔŒmßÑå~Œ»ÐØÜØ¥®áÑ“ÊR¼äàãÓŸmÓÑßÊŒmÒÛ×Ç‘¶ÒÍ¡ Chiave: Prova. Testo: Questa è una prova per analizzare l'output della codifica. Cod: ™åÀß®húhÂÙ®hຼá®hà¿‹®¶Ñ´¶åÇ©âm×t·å¼½àÁhÔ¹×®hÓ·±Ô³±Ó©{ Chiave: LoL Testo: Questa è una prova per analizzare l'output della codifica. Cod: ³ÚÅÞÖÆ€õ‚ÚÎÌ‚ÕÒÚØÆ€ÛÇ×€ÌÐÆÌÔÜßÁÝÇ…Ì’ÑÚÔÛ×Ù€ÏÇÑÌÌ‚ÈÏÏËËÉÎÓ Chiave: ciao
Posso notare che i testi cifrati cambiano tantissimo anche con cambiamenti lievi della chiave immessa e che non è possibile, almeno mi pare, risalire al testo in chiaro attraverso l'analisi delle frequenze.
L'unico dubbio è sulla lunghezza delle stringhe cifrate che non sempre sono della stessa lunghezza del testo in chiaro (ad un attaccante che non conosce niente sia del testo che della chiave non penso di avergli semplificato la vita con questa caratteristica, per uno che invece può fare analisi differenziali, cioè vedere come cambia un testo immettendo varie chiavi, potrebbe essere semplice perchè questo comportamento fa risalire ad una caratteristica della chiave e quindi alle altre, anche se ancora non ho ben capito quale).
Il metodo direi che è teoricamente sicuro se la chiave è lunga quanto il messaggio, e se la chiave non viene riutilizzata su più messaggi. Altrimenti penso che si usino metodi statistici basati sul dizionario. In pratica la conoscenza di informazioni sul messaggio o sulla chiave possono rendere la decriptazione più semplice. Per esempio il tuo messaggio è un testo in italiano scritto in ASCII (ovvero userai 80 dei 255 caratteri dell'ASCII e la loro distribuzioni è tutt'altro che uniforme), la tua chiave è più piccola del messaggio e si limita a lettere ASCII visualizzabili e che possono essere inserite con la tastiera (nel tuo caso addirittura una parola in italiano).
Ho riscritto l'ultimo codice che hai postato rendendolo così:
Questo codice risolve il problema con lunghezza (aggiunge anche una sorta di aggiunta di sicurezza che nel caso specifico è inutile. In ogni caso il testo cifrato va inteso come un array di caratteri e non come una stringa formattata.
Non mi dà il tuo stesso codice cifrato. Hai cambiato il modo in cui codifichi?
#include <stdio.h> #define MAX 10000 int lunghezza(char const stringa[], int const n); int main(void) { char testo[MAX] = { 0 }; /*Testo in chiaro */ printf("Inserisci la frase: "); fgets(testo, sizeof(testo), stdin); int const l1 = lunghezza(testo, sizeof(testo))-1; testo[l1] = '\0'; printf("La frase inserita e': %s\n\n", testo); char chiave[MAX] = { 0 }; /*Chiave di cifratura */ printf("Inserisci la chiave: "); fgets(chiave, sizeof(chiave), stdin); int const l2 = lunghezza(chiave, sizeof(chiave))-1; chiave[l2] = '\0'; printf("La chiave inserita e': %s\n\n", chiave); char cifrato[MAX] = { 0 }; for (int i = 0; i != l1; ++i) { cifrato[i] = testo[i] ^ chiave[i % l2]; } cifrato[l1] = '\0'; printf("\nLa stringa cifrata e': %s\n\n", cifrato); char decifr[MAX] = { 0 }; for (int i = 0; i != l1; ++i) { decifr[i] = cifrato[i] ^ chiave[i % l2]; } decifr[l1] = '\0'; printf("La stringa decifrata e': %s\n\n", decifr); } int lunghezza(char const stringa[], int const n) { int i = 0; for(; (i<n) && (stringa[i] != '\0'); ++i); return i; }
Questo codice risolve il problema con lunghezza (aggiunge anche una sorta di aggiunta di sicurezza che nel caso specifico è inutile. In ogni caso il testo cifrato va inteso come un array di caratteri e non come una stringa formattata.
Non mi dà il tuo stesso codice cifrato. Hai cambiato il modo in cui codifichi?
Per quanto riguarda la sicurezza teorica non ne sono sicuro che sia sufficientemente forte perchè l'analisi differenziale sui testi fa miracoli, però quando la lunghezza della chiave è uguale a quella del testo e non si sà nulla sulla chiave (come è giusto che sia) dovrebbe essere molto difficile se non impossibile riuscire a recuparare le informazioni in chiaro, anche se non ne ho una dimostrazione, soprattutto perchè, come dicevo, intuitivamente penso che più elementi ci siano che legano un testo cifrato alle caratteristiche della chiave e più ci ritroviamo un cifrario vulnerabile.
Il mio modello di sicurezza si rifà ai principi di Shannon, cioè algoritmo noto ma chiave e informazioni sul testo ignote ad un attaccante. Per le analisi statistiche non saprei, analizzando quegli output raramente ci sono coincidenze di caratteri uguali codificati nello stesso modo, cioè ho fatto caso che la lettera 'a' all'interno di un testo cifrato può essere codificata più di una volta con, per esempio il carattere '-', ma non avviene sempre (penso che il 50% delle volte avvenga per come ho scritto le funzioni, che prendono anche la condizione di parità del carattere da cifrare all'interno della stringa), quindi dovrebbe disorientare un attimo questa cosa.
Per quanto riguarda la difficoltà di decifrare una di quelle stringhe probabilmente è dovuta al fatto che ho fatto copia incolla da file, e se ci sono caratteri non printabili salvati sul file il copia incolla fa perdere informazioni (perchè può essere che non si abbiano sempre caratteri printabili operando, passatemi il termine, su un campo chiuso), quindi un'eventuale comunicazione con questa codifica dovrebbe avvenire attraverso lo scambio di file. Si potrebbe creare un'altra funzione che analizza i caratteri e se ne trova di non printabili gli somma qualcosa per buttarli nei printabili, però non saprei come codificare la cosa, dovrei pensarci un attimo.
Per quanto riguarda la tua versione della codifica con lo xor l'ho provato e vedo che funziona, il che è interessante, dopo mi metto ad analizzare cosa fa perchè non mi è tutto chiaro (come la dichiarazione di int const risolva il problema).
Il mio modello di sicurezza si rifà ai principi di Shannon, cioè algoritmo noto ma chiave e informazioni sul testo ignote ad un attaccante. Per le analisi statistiche non saprei, analizzando quegli output raramente ci sono coincidenze di caratteri uguali codificati nello stesso modo, cioè ho fatto caso che la lettera 'a' all'interno di un testo cifrato può essere codificata più di una volta con, per esempio il carattere '-', ma non avviene sempre (penso che il 50% delle volte avvenga per come ho scritto le funzioni, che prendono anche la condizione di parità del carattere da cifrare all'interno della stringa), quindi dovrebbe disorientare un attimo questa cosa.
Per quanto riguarda la difficoltà di decifrare una di quelle stringhe probabilmente è dovuta al fatto che ho fatto copia incolla da file, e se ci sono caratteri non printabili salvati sul file il copia incolla fa perdere informazioni (perchè può essere che non si abbiano sempre caratteri printabili operando, passatemi il termine, su un campo chiuso), quindi un'eventuale comunicazione con questa codifica dovrebbe avvenire attraverso lo scambio di file. Si potrebbe creare un'altra funzione che analizza i caratteri e se ne trova di non printabili gli somma qualcosa per buttarli nei printabili, però non saprei come codificare la cosa, dovrei pensarci un attimo.
Per quanto riguarda la tua versione della codifica con lo xor l'ho provato e vedo che funziona, il che è interessante, dopo mi metto ad analizzare cosa fa perchè non mi è tutto chiaro (come la dichiarazione di int const risolva il problema).
"vict85":
Ho riscritto l'ultimo codice che hai postato rendendolo così:
#include <stdio.h> #define MAX 10000 int lunghezza(char const stringa[], int const n); int main(void) { char testo[MAX] = { 0 }; /*Testo in chiaro */ printf("Inserisci la frase: "); fgets(testo, sizeof(testo), stdin); int const l1 = lunghezza(testo, sizeof(testo))-1; testo[l1] = '\0'; printf("La frase inserita e': %s\n\n", testo); char chiave[MAX] = { 0 }; /*Chiave di cifratura */ printf("Inserisci la chiave: "); fgets(chiave, sizeof(chiave), stdin); int const l2 = lunghezza(chiave, sizeof(chiave))-1; chiave[l2] = '\0'; printf("La chiave inserita e': %s\n\n", chiave); char cifrato[MAX] = { 0 }; for (int i = 0; i != l1; ++i) { cifrato[i] = testo[i] ^ chiave[i % l2]; } cifrato[l1] = '\0'; printf("\nLa stringa cifrata e': %s\n\n", cifrato); char decifr[MAX] = { 0 }; for (int i = 0; i != l1; ++i) { decifr[i] = cifrato[i] ^ chiave[i % l2]; } decifr[l1] = '\0'; printf("La stringa decifrata e': %s\n\n", decifr); } int lunghezza(char const stringa[], int const n) { int i = 0; for(; (i<n) && (stringa[i] != '\0'); ++i); return i; }
Questo codice risolve il problema con lunghezza (aggiunge anche una sorta di aggiunta di sicurezza che nel caso specifico è inutile. In ogni caso il testo cifrato va inteso come un array di caratteri e non come una stringa formattata.
Non mi dà il tuo stesso codice cifrato. Hai cambiato il modo in cui codifichi?
Cosa sbaglio anche qui?
#include <stdio.h> #define MAX 100000 int lunghezza(char const stringa[], int const n); int main(){ int i; char testo[MAX] = {0}; /*Testo in chiaro*/ char cifrato[MAX] = {0}; /*Testo cifrato*/ char decifr[MAX] = {0}; /*Testo decifrato*/ char stringa[MAX] = {0}; /*Lettura da file*/ printf("Inserisci la frase: "); fgets(testo, sizeof(testo), stdin); int const l1 = lunghezza(testo, sizeof(testo))-1; testo[l1] = '\0'; printf("La frase inserita e': %s\n\n", testo); char chiave[MAX] = { 0 }; printf("Inserisci la chiave: "); fgets(chiave, sizeof(chiave), stdin); int const l2 = lunghezza(chiave, sizeof(chiave))-1; chiave[l2] = '\0'; printf("La chiave inserita e': %s\n\n", chiave); for (i=0; i!=l1; ++i){ cifrato[i] = testo[i] ^ chiave[i%l2]; } cifrato[l1] = '\0'; printf("\nLa stringa cifrata e': %s\n\n", cifrato); char file[] = "XoR.txt"; //Scrittura FILE *fp; fp = fopen(file, "w"); fprintf(fp, "%s", cifrato); fclose(fp); //Lettura FILE *pf; i = 0; fp = fopen(file, "r"); while(fscanf(fp, "%c", stringa[i] == 1)){ i++; } fclose(fp); printf("\nStringa letta da file: %s\n", stringa); for (i = 0; i != l1; ++i){ decifr[i] = stringa[i] ^ chiave[i % l2]; } decifr[l1] = '\0'; printf("La stringa decifrata e': %s\n\n", decifr); system("PAUSE"); return 0; } int lunghezza(char const stringa[], int const n){ int i = 0; for(; (i<n) && (stringa[i] != '\0'); ++i); return i; }
Intendevo questo, cioè se provo a scrivere la stringa creata su file e poi a rileggerla o crasha o non termina
Non ho letto tutto, c'è qualche errore qua e là (a me non compila infatti). In ogni caso la stringa criptata non va intesa come un insieme di caratteri ma come un insieme di valori numerici (in particolar modo ha poco senso usare funzioni ideate per null-terminated strings). Inoltre devi tenere conto che '\0' = 0 (mi sembra che sia sempre vero, ma potrebbe essere implementation dependant ma molto comune) e lo xor di due caratteri fa 0 se sono uguali. Quindi è un evento non poi così raro. Se vuoi evitare problemi e usare funzioni sulle stringhe devi assicurarti che il risultato della criptazione sia sempre stampabile (esistono delle funzioni per questi test http://en.cppreference.com/w/cpp/string/byte/isprint ). Nota che per farlo devi fare una operazione che non sia un semplice xor. Immagino che possa convenirti scrivere e leggere il file in binario.
Ah giusto, il puntatore a FILE che ho visto al volo. Purtroppo a me compila ma poi crasha.
char file[] = "XoR.txt"; //Scrittura FILE *fp; fp = fopen(file, "w"); fprintf(fp, "%s", cifrato); fclose(fp); //Lettura FILE *pf; i = 0; fp = fopen(file, "r"); while(fscanf(pf, "%c", &stringa[i] == 1)){ i++; } fclose(pf);
Ho fatto delle correzioni
Questo è quello che intendevo quando dicevo di interpretare la stringa decifrata come una successione di numeri e sull'aprire il file come binario.
#include <stdio.h> #define MAX 100000 int lunghezza(char const stringa[], int const n); int main(void) { int i; char testo[MAX] = { 0 }; /*Testo in chiaro */ char cifrato[MAX] = { 0 }; /*Testo cifrato */ char decifr[MAX] = { 0 }; /*Testo decifrato */ char stringa[MAX] = { 0 }; /*Lettura da file */ printf("Inserisci la frase: "); fgets(testo, sizeof(testo), stdin); int const l1 = lunghezza(testo, sizeof(testo)) - 1; testo[l1] = '\0'; printf("La frase inserita e': %s\n\n", testo); char chiave[MAX] = { 0 }; printf("Inserisci la chiave: "); fgets(chiave, sizeof(chiave), stdin); int const l2 = lunghezza(chiave, sizeof(chiave)) - 1; chiave[l2] = '\0'; printf("La chiave inserita e': %s\n\n", chiave); for (i = 0; i != l1; ++i) { cifrato[i] = testo[i] ^ chiave[i % l2]; } cifrato[l1] = '\0'; printf("\nLa stringa cifrata e': "); for(i = 0; i != l1; ++i) { printf("%d ", (int) cifrato[i]); } puts("\n"); char file[] = "XoR.txt"; //Scrittura FILE *fp; fp = fopen(file, "wb"); for(i = 0; i != l1; ++i) { fputc(cifrato[i], fp); } fclose(fp); //Lettura i = 0; fp = fopen(file, "rb"); while ((stringa[i] = fgetc(fp)) != EOF) { ++i; } stringa[i] = '\0'; printf("\nLa stringa letta e': "); for(i = 0; i != l1; ++i) { printf("%d ", (int) stringa[i]); } puts("\n"); fclose(fp); for (i = 0; i != l1; ++i) { decifr[i] = stringa[i] ^ chiave[i % l2]; } decifr[l1] = '\0'; printf("La stringa decifrata e': %s\n\n", decifr); } int lunghezza(char const stringa[], int const n) { int i = 0; for (; (i < n) && (stringa[i] != '\0'); ++i) ; return i; }
Questo è quello che intendevo quando dicevo di interpretare la stringa decifrata come una successione di numeri e sull'aprire il file come binario.
"vict85":
Ho fatto delle correzioni
#include <stdio.h> #define MAX 100000 int lunghezza(char const stringa[], int const n); int main(void) { int i; char testo[MAX] = { 0 }; /*Testo in chiaro */ char cifrato[MAX] = { 0 }; /*Testo cifrato */ char decifr[MAX] = { 0 }; /*Testo decifrato */ char stringa[MAX] = { 0 }; /*Lettura da file */ printf("Inserisci la frase: "); fgets(testo, sizeof(testo), stdin); int const l1 = lunghezza(testo, sizeof(testo)) - 1; testo[l1] = '\0'; printf("La frase inserita e': %s\n\n", testo); char chiave[MAX] = { 0 }; printf("Inserisci la chiave: "); fgets(chiave, sizeof(chiave), stdin); int const l2 = lunghezza(chiave, sizeof(chiave)) - 1; chiave[l2] = '\0'; printf("La chiave inserita e': %s\n\n", chiave); for (i = 0; i != l1; ++i) { cifrato[i] = testo[i] ^ chiave[i % l2]; } cifrato[l1] = '\0'; printf("\nLa stringa cifrata e': "); for(i = 0; i != l1; ++i) { printf("%d ", (int) cifrato[i]); } puts("\n"); char file[] = "XoR.txt"; //Scrittura FILE *fp; fp = fopen(file, "wb"); for(i = 0; i != l1; ++i) { fputc(cifrato[i], fp); } fclose(fp); //Lettura i = 0; fp = fopen(file, "rb"); while ((stringa[i] = fgetc(fp)) != EOF) { ++i; } stringa[i] = '\0'; printf("\nLa stringa letta e': "); for(i = 0; i != l1; ++i) { printf("%d ", (int) stringa[i]); } puts("\n"); fclose(fp); for (i = 0; i != l1; ++i) { decifr[i] = stringa[i] ^ chiave[i % l2]; } decifr[l1] = '\0'; printf("La stringa decifrata e': %s\n\n", decifr); } int lunghezza(char const stringa[], int const n) { int i = 0; for (; (i < n) && (stringa[i] != '\0'); ++i) ; return i; }
Questo è quello che intendevo quando dicevo di interpretare la stringa decifrata come una successione di numeri e sull'aprire il file come binario.
Scusami non avevo capito io per scrivere in binario, ora è perfetto. Ti ringrazio tanto per le correzioni ed il tuo tempo.
Appena trovo il tempo aggiunto queste migliorie alla codifica che stavo facendo e lo posto.