M-am încurcat cu criptografia (pentru uz recreațional) și mi-am creat propriul script de criptare cu un singur pad în C. Acum, acestea fiind spuse, recunosc fără îndoială că nu sunt deloc un expert în criptografie. Știu că regula nr. 1 a criptografiei este să nu o faci singur. Cu toate acestea, sunt cu adevărat interesat dacă scriptul meu de criptare este (teoretic) sigur.
În primul rând, iată o prezentare de bază a ceea ce încerc să obțin cu metoda mea de criptare:
Scopul este de a realiza One Time Pad Encryption, în care sunt utilizate atât (1) un tabel hash, cât și (2) o cheie de criptare. Tabelul hash (în acest caz) este precodat, unde valorile sunt 01-98.
Cheia de criptare se calculează după cum urmează:
- Obține intrare aleatorie de utilizator (cel puțin aceeași lungime ca mesajul)
- Obțineți indexul corespunzător pentru char în validChars[] (codul sursă de mai jos)
- Obțineți numărul din defaultHashTable care corespunde indexului #2
Mesajul este criptat după cum urmează:
- Luați mesajul și convertiți-l în valorile defaultHashTable corespunzătoare
- Luați cheia generată anterior și adăugați-o la mesajul convertit
- Acum este criptat (presupunând că aceeași cheie nu este niciodată folosită din nou)
De exemplu:
- Mesaj: salut
- Convertiți în valorile defaultHashTable corespunzătoare: salut -> 0805121215
- Obțineți caractere aleatorii pentru cheia: abkdh
- Convertiți în valorile defaultHashTable corespunzătoare: abkdh -> 0102110408
- Adăugați cheia: 0805121215 + 0102110408 = 0907231623
- Mesaj criptat: 0907231623
Iată codul sursă (NOTĂ: Aceasta este o combinație de funcții care erau în fișiere de antet C separate, de aceea nu postez o funcție principală ()):
// Cheia (pentru mesaj) va fi maximum [50.000][3] (deci o matrice în care fiecare are 2 caractere):
typedef struct {
cheie char[MAX_SIZE][3];
} Cheie;
Cheie globalKey;
// Mesajul criptat va fi returnat în această structură (deoarece este doar o modalitate ușoară de a returna o matrice bidimensională dintr-o funcție în C):
typedef struct {
char encryptedMessage[MAX_SIZE][3];
} EncryptedMessage;
// Tabelul hash este o matrice bidimensională precodata (care este încărcată în initDefaultHashTable()), care va fi folosită împreună cu cheia pentru a cripta mesajele:
// NOTĂ: Există, de asemenea, un alt mod de criptare pe care nu îl includ (în încercarea de a face acest lucru concis) în care trebuie să tastați manual numere aleatorii cu două cifre (97 dintre ele) pentru tabelul hash
typedef struct {
char hashtable[HASHTABLE_CAPACITY][3];
} DefaultHashTable;
DefaultHashTable defaultHashTable; // Declarați un defaultHashTable global care va stoca acest hashtable
// Încărcați defaultHashTable cu 1-98, respectiv:
void initDefaultHashTable(){
pentru (int i = 0; i < HASHTABLE_CAPACITY; i++){
char s[3];
sprintf(s, "%d", (i+1));
dacă (i < 10){
char tmp = s[0];
s[0] = '0';
s[1] = tmp;
}
pentru (int j = 0; j < 2; j++){
defaultHashTable.hashtable[i][j] = s[j];
}
}
}
// Caractere valide pe care le poate conține mesajul (97 dintre ele):
char validChars[] = {'a','b','c','d','e','f','g','h','i','j','k', 'l','m','n','o','p','q','r','s','t','u','v','w','x ','y','z','A','B','C','D','E','F','G','H','I','J', "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W" ','X','Y','Z','!','@','#','$','%','^','&','*','(', ')','-','+',' ',',','.',':',';','\'','\"','[',']',' {','}','_','=','|','\','/','<','>','?',''','~','\ n','\t','0','1','2','3','4','5','6','7','8','9'};
// Pentru că returnarea caracterului eșuează (simt că există o modalitate mai bună de a face această parte):
char FAILED = (car)255;
// Găsiți indexul unui caracter valid (din validChars) sau FALSE dacă nu există:
int findChar(char c){
pentru (int i = 0; i < strlen(validChars); i++){
dacă (validChars[i] == c){
returnează i;
}
}
returnează FALSE;
}
// Returnează caracterul din indexul dat validChars:
char returnChar(index int){
returnează caractere valide[index];
}
// Obține indexul unei valori date de tabel hash (de la defaultHashTable) și apoi, dacă este cazul, caracterul corespunzător în validChars:
char findHashTableValue(char n[3], char hashtable[][3]){
pentru (int i = 0; i < HASHTABLE_CAPACITY; i++){
dacă (hashtable[i][0] == n[0] && hashtable[i][1] == n[1])
return returnChar(i);
}
return FAILED;
}
// Partea PRINCIPALĂ a codului (funcția principală c ar numi acest lucru): Criptează folosind o singură criptare cu pad, dar folosind un tabel hash implicit pentru a economisi timp:
void goThroughLightEnryptionProcess(char * str, char * write_to_file){
// Încărcați defaultHashTable:
initDefaultHashTable();
// Folosește funcția pentru a crea chei aleatorii (pe baza intrărilor aleatorii ale utilizatorului):
generateRandomKey(strlen(str), MAX_SIZE, FALSE);
// Scrieți mesajul:
EncryptedMessage encryptMsg = otpEncrypt(defaultHashTable.hashtable, str, globalKey.key);
// Circulați și imprimați conținutul (dacă nu scrieți în fișier):
dacă (scrie_în_fișier == NULL){
pentru (int i = 0; i < strlen(str); i++){
pentru (int j = 0; j < 2; j++){
printf("%c", encryptMsg.encryptedMessage[i][j]);
}
}
printf("\n");
} altfel {
// Scrieți mesajul criptat în fișier:
// NOTĂ: acesta este un alt parametru pe care îl puteți trece în programul actual (care este mult mai mare decât acesta) unde îl puteți scrie într-un fișier în loc să îl afișați în terminal:
// NOTĂ: Nu am inclus acest cod de matrice writeFileWithTwoDimensionalArray() aici, deoarece este irelevant, deoarece pur și simplu scrie într-un fișier.
writeFileWithTwoDimensionalArray(encryptMsg.encryptedMessage, HASHTABLE_CAPACITY, write_to_file);
}
}
// (Funcția de ajutor) Încărcați matricea cu două caractere în cheie:
void loadIntoKeyForRandoKey(int at, char n[3]){
pentru (int i = 0; i < 2; i++){
globalKey.key[at][i] = n[i];
}
}
// Generați o cheie pe baza intrărilor aleatorii ale utilizatorului:
void generateRandomKey(int password_length, int max_size, bool use_global){
// @Folosește globalHashTable | defaultHashTable
// @Folosește globalKey
răspuns char[max_size];
printf("Introduceți caractere aleatorii pentru cheie (a-z,A-Z,!@#$%%^&*()-+=, lungime minimă de %d): ", parola_lungime);
fgets(răspuns, max_size, stdin);
// Eliminați caracterul „\n” de la sfârșit:
char * p;
dacă ((p = strchr(răspuns, '\n')) != NULL){
*p = '\0';
} altfel {
scanf("%*[^\n]");
scanf("%*c");
}
// Asigurați-vă că introducerea utilizatorului este >= password_length:
if (strlen(răspuns) <parolă_lungime){
printf("\n[ EROARE ]: caracterele aleatoare trebuie să fie mai mari sau egale cu %d.\n", lungime_parolă);
return generateRandomKey(lungime_parolă, dimensiune_max, utilizare_global);
}
// Convertiți caracterele aleatoare în echivalența lor în tabelul hash, respectiv:
pentru (int i = 0; i < lungime_parolă; i++){
int getCharIndex = findChar(răspuns[i]);
// Asigurați-vă că a fost găsit cu succes:
dacă (getCharIndex == FALSE){
printf("\n[ EROARE ] Caracterul '%c' este nevalid. Încercaţi din nou.\n", răspuns[i]);
return generateRandomKey(lungime_parolă, dimensiune_max, utilizare_global); // Fă-o din nou
}
// Încărcați valoarea hashtable corespunzătoare în cheie:
dacă (use_global == TRUE){
loadIntoKeyForRandoKey(i, globalHashTable.hashtable[getCharIndex]);
} altfel {
loadIntoKeyForRandoKey(i, defaultHashTable.hashtable[getCharIndex]);
}
}
// Scrie cheia aleatorie într-un fișier:
createFileWithTwoDimensionalArray(globalKey.key, password_length, "key");
}
// (Funcția de ajutor) Pentru încărcare în structura EncryptedMessage:
void loadIntoEncryptedMessage(int at, char n[3], EncryptedMessage *encryptedMsg){
dacă (strlen(n) == 1){
// Adăugați un „0”:
char tmp = n[0];
n[0] = '0';
n[1] = tmp;
}
pentru (int i = 0; i < 2; i++){
encryptedMsg->encryptedMessage[at][i] = n[i];
}
}
/*
Criptează un mesaj având o cheie și un hashtable valide
*/
EncryptedMessage otpEncrypt(char hashtable[][3], char * msg, char key[MAX_SIZE][3]){
EncryptedMessage encryptedMsg;
pentru (int i = 0; i < strlen(msg); i++){
// Convertiți valoarea cheii în număr întreg:
int convertedKeyValueIntoInt = safelyConvertToInt(key[i]);
// Asigurați-vă că a fost convertit corect:
dacă (convertedKeyValueIntoInt == FALSE){
printf("[ EROARE ]: Cheia este coruptă la %d (valoare = %s).\n", i, cheia[i]);
ieșire(1);
}
// Convertiți mesajul utilizatorului în echivalența acestuia în tabelul hash:
int indexOfMsgChar = findChar(msg[i]);
// Asigurați-vă că findChar() a găsit valoarea corect:
dacă (indexOfMsgChar == FALSE){
printf("[ EROARE ]: parola (msg) este coruptă la %d (valoare = %s). Este posibil să fi avut loc deoarece caracterul „%c” nu este permis.\n", i, msg, msg[i ]);
ieșire(1);
}
char * correspondingEncryptMsgChars = hashtable[indexOfMsgChar];
// Convertiți caracterele encryptMsg corespunzătoare în int:
int convertedEncryptMsgCharsIntoInt = safelyConvertToInt(correspondingEncryptMsgChars);
// Asigurați-vă că a fost convertit corect:
dacă (convertedEncryptMsgCharsIntoInt == FALSE){
printf("[ EROARE ]: Tabelul Hash este corupt la %d (valoare = %s).\n", indexOfMsgChar, corespunzatorEncryptMsgChars);
ieșire(1);
}
// Faceți calculul:
int encryptedFrag = otpeAdd(convertedEncryptMsgCharsIntoInt, convertedKeyValueIntoInt);
// Convertiți-l într-un șir:
char encryptedFragStr[3];
sprintf(encryptedFragStr, "%d", encryptedFrag);
loadIntoEncryptedMessage(i, encryptedFragStr, &encryptedMsg);
}
return encryptedMsg;
}
Întrebarea mea imediată ar fi: dacă folosesc o tabelă hash pre-codificată (pe care oricine ar putea deduce), aceasta face criptarea nesigură (chiar dacă cheia care corespunde valorilor tabelului hash este complet aleatorie prin introducerea utilizatorului)? Este sigur doar dacă randomizez numerele tabelului hash (01-98) (și potențial randomizez validChars[])?
Sunt sincer interesat dacă logica mea este valabilă, așa că orice comentarii, sugestii sau critici ar fi foarte apreciate.