Я кодирую эту программу, которая позволяет вам шифровать файлы с помощью шифра Vernam на языке C. Я был бы рад, если бы вы проверили мой код и сказали, могу ли я внести в него какие-то улучшения или есть ли какие-либо ошибки.
Запрос, который они мне дали:
Цель состоит в том, чтобы разработать простое приложение, которое позволяет шифровать файлы с помощью варианта шифра Вернама, называемого здесь bvernan. Предлагаемый алгоритм использует простое свойство бинарного оператора XOR: (A XOR B) XOR B = A Для заданной последовательности k байтов b0 … bk-1 (называемой ключом) функция кодирования последовательности байтов d0 … dN, функция кодирования / декодирования следует следующей простой процедуре. Последовательность d0 … dN сначала делится на N / k блоков (целочисленное деление), D0, …, D [(N / k) -1] каждый из которых состоит ровно из k байтов (кроме последней последовательности, которая, очевидно, может содержать меньшее количество байтов). Впоследствии каждая последовательность Dj = dj, 0 … dj, k-1 преобразуется в последовательность D’j = d’j, 0 … d’j, k-1 такую, что для каждого i: dj, i = b (j + i) mod k XOR dj, i То есть байт в позиции i блока j помещается в XOR с байтом (j + i) mod k ключа. Выходная последовательность будет тогда получена из сопоставления последовательностей D’0, …, D ‘[(N / k) -1].
Это код:
файл main.c
#include "encode.h"
int main (int argc ,char** argv){
if(argc!=4){
printf("Usage: bvernan keyfile inputfile outputfile n");
return 1;
}
Key_t* key=openKey(argv[1]);
Register_t* file=openFile(argv[2],argv[3],key->lenght);
encode(file,key);
closeRegister(file);
freeKey(key);
printf("Success!n");
}
файл encode.c
#include "encode.h"
int encode (Register_t* file, Key_t* key ){
while(readF(file)>0){
encodeDivision(file->buffer,file->bufferLenght,key);
writeF(file);
}
}
void encodeDivision (unsigned char* block,long lenght,Key_t*key){
for(int i=0;i<lenght;i++){
block[i]=block[i]^key->buffer[i];
}
}
файл encode.h
#include "key.h"
#include "register.h"
int encode (Register_t* file, Key_t* key );
void encodeDivision (unsigned char* block,long lenght,Key_t*key);
файл key.c
#include "key.h"
#include <stdio.h>
#include <stdlib.h>
long keySize (FILE* file){
fseek (file,0,SEEK_END);
long size=ftell(file);
rewind (file);
return size;
}
Key_t* openKey(char* path){
Key_t* kFile= malloc (sizeof(Key_t));
FILE*file= fopen(path,"rb");
kFile->lenght=keySize(file);
kFile->buffer= malloc(kFile->lenght);
fread(kFile->buffer,1,kFile->lenght,file);
fclose(file);
return kFile;
}
void freeKey (Key_t* key ){
free (key->buffer);
free (key);
}
файл key.h
typedef struct Key
{
unsigned char* buffer;
long lenght;
} Key_t;
Key_t* openKey(char* path);
void freeKey (Key_t*);
файл register.c
#include <stdio.h>
#include <stdlib.h>
#include "register.h"
Register_t* openFile (char* inPath,char* outPath,long bufferLenght){
Register_t* file = malloc (sizeof(Register_t));
file->buffer= malloc(bufferLenght);
file->bufferLenght=bufferLenght;
file->fdIn= fopen(inPath,"rb");
file->fdOut= fopen(outPath,"wb");
if(file->fdOut==NULL || file->fdIn==NULL){
return NULL;
}
return file;
}
int readF (Register_t* file){
int readbyte = fread(file->buffer,1,file->bufferLenght,file->fdIn);
file->bufferLenght=readbyte;
return readbyte;
}
int writeF (Register_t* file){
int writebyte = fwrite(file->buffer,1,file->bufferLenght,file->fdOut);
return writebyte;
}
void closeRegister (Register_t* file){
free(file->buffer);
fclose(file->fdIn);
fclose(file->fdOut);
free(file);
}
файл register.h
#include <stdio.h>
#include <stdlib.h>
typedef struct Register
{
unsigned char *buffer;
FILE *fdIn;
FILE *fdOut;
long bufferLenght;
} Register_t;
Register_t *openFile(char *inPath, char *outPath, long bufferLenght);
int readF(Register_t *);
int writeF(Register_t *);
void closeRegister(Register_t *);
файл Makefile
all: bvernan
bvernan: encode.o key.o main.o register.o
gcc -o bvernan $^
%.o: %.c
gcc -c $<
clean:
rm *.o bvernan
1 ответ
Могу ли я внести в него какие-то улучшения или есть какие-либо ошибки.
Отсутствие проверки ошибок
fopen(), malloc(), ftell(), fread()
, (все функции ввода-вывода) и т. д. заслуживают того, чтобы их возвращаемые значения проверялись на наличие ошибок.
В частности, когда файл может не открываться или не удается выделить память, обрабатывайте такие случаи, чтобы не забыть о другом. например: не забудьте fclose()
, или же fclose()
дважды, когда не удалось выделить память.
Изящно обрабатывать ошибки и при этом поддерживать хороший поток кода — непростая задача.
Отсутствие комментариев
некоторый комментарии могут помочь, особенно в файлах .h. Иногда файлы заголовков — это все, что пользователь видит (или хочет видеть).
.h файлы
Отсутствует код охранников.
Уменьшите разброс пространства имен. Рекомендовать общий префикс для объектов в файле .h
Типы
long
ОК для большинства размеров файлов. size_t
лучше для определения размера и индексации массива.
long lenght ... for(int i=0;i<lenght;i++)
-> i
а также length
должен быть одного типа: size_t
.
Стиль
Используйте автоматический форматировщик, чтобы улучшить внешний вид кода с меньшими затратами времени.
Толерантный свободный
Обратите внимание, что free(NULL)
хорошо определено. Сделайте то же самое для freeKey(NULL);
Написание
lenght
-> length
.
Пространства
Стиль очень плотный, левый = правый = правый. Некоторые пробелы помогут.
// block[i]=block[i]^key->buffer[i];
block[i] = block[i] ^ key->buffer[i];
Включить заказ
Для xxx.c я рекомендую сначала включить xxx.h, чтобы проверить его автономность.
// file register.c
#include "register.h" // Put first
#include <stdio.h>
#include <stdlib.h>
Непонятно почему register.h
имеет #include <stdlib.h>
. Излишний #include
файлы в файле .c имеют свое место и не вызывают особого беспокойства. (Некоторые среды программирования предлагают проверку.)
.h файл должен использовать минимальный набор.
Именование
Подумайте об использовании того же дело и заказывать имена key.c, Key_t
-> key.c, key_t
. keySize(), openKey()
-> keySize(), keyOpen()
.