不能使用XOR C加密器加密长字符串

时间:2017-06-24 13:01:50

标签: c xor

我写了一个C程序来执行XOR加密, 我的问题是该程序无法加密超过24个字符的文件。

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define BUF_SIZE  2

char* xor(char*, char*);
char* gen_key(size_t);

int main(int argc, char **argv) {
    char *buffer = NULL,* encrypted_buffer = NULL;
    size_t file_size;
    char *key = gen_key(6);
    char tmp_buffer[BUF_SIZE];
    FILE *finput = NULL, *foutput = NULL;

    finput = fopen("file.txt", "rb");
    fseek(finput, 0, SEEK_END);
    file_size = ftell(finput);
    rewind(finput);
    printf("File size : %d\n", (int)file_size);
    buffer = (char*)malloc((file_size + 1) * sizeof(char));
    memset(buffer, 0, sizeof(buffer));
    while (!feof(finput)) {
        memset(tmp_buffer, 0, sizeof(tmp_buffer));
        fgets(tmp_buffer, sizeof(tmp_buffer), finput);
        strcat(buffer, tmp_buffer);
    }
    printf("%s", buffer);
    encrypted_buffer = xor(buffer, key);
    free(buffer);
    buffer = xor(encrypted_buffer, key);
    printf("Encrypted : %s\n", encrypted_buffer);
    printf("Decrypted : %s\n", buffer);
    printf("EOF\n");
    free(encrypted_buffer);
    fclose(finput);
    return 0;
}

char *gen_key(size_t length) {
    srand(time(NULL));
    const char charset[] = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz012345679";
    const size_t charset_size = (sizeof(charset) - 1);
    unsigned int i;
    char *key = NULL;
    key = (char*)malloc((length + 1) * sizeof(char));
    memset(key, 0, sizeof(key));
    for (i = 0; i < length; i++)
        key[i] = charset[rand() % charset_size];
    return key;
}

char *xor(char *file, char *key) {
    unsigned int i;
    char *xor = NULL;
    xor = (char*)malloc(sizeof(file));
    memset(xor, 0, sizeof(xor));
    for (i = 0; i < strlen(file); i++)
        *(xor + i) = *(file + i) ^ *(key + (i % strlen(key) - 1));
    return xor;
}

输出是:

File size : 55
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklimnopqrstuvwxyz

Encrypted : A2#G8-  M   >7S$1!

Decrypted : ABCDEFGHIJKLMNOPQRSTUVWX!:!e!

EOF

1 个答案:

答案 0 :(得分:2)

您的代码中存在多个问题:

  • 缓冲区大小非常小:#define BUF_SIZE 2。您应该为行缓冲区使用合理的大小,例如80或100。

  • memset(buffer, 0, sizeof(buffer));中,buffer是一个指针,因此sizeof(buffer)不是数组的大小,只是指针的大小。在这种情况下使用file_size + 1

  • 您在代码中的其他位置犯了同样的错误:传递缓冲区的大小而不是依赖sizeof()运算符。

  • while (!feof(f))总是错误的:您可以使用fread一步读取文件或逐行阅读:

    while (fgets(tmp_buffer, sizeof(tmp_buffer), finput)) {
        ...
    

请注意,您的方法存在一个主要问题:密钥由字母和数字组成,假定文件包含文本。如果文件在适当的位置包含密钥中的一个字符,则使用密钥字节对该字符进行删除将产生一个空字节,该字节将停止printf()中的输出,如果您要使用该字节也将停止解密将其存储在输出文件中。您正确地使用二进制模式("rb")作为文件流,但您也不应对文件内容做任何假设并透明地处理空字节。

以下是您的计划的修改版本:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

unsigned char *xor(unsigned char *file, size_t size, const char *key);
char *gen_key(size_t length);

void print_buffer(const char *msg, unsigned char *buf, size_t size) {
    printf("%s: ", msg);
    for (size_t i = 0; i < size; i++) {
        switch (buf[i]) {
        case '\n':
            printf("\\n");
            break;
        case '\\':
            printf("\\\\");
            break;
        default:
            if (buf[i] >= ' ' && buf[i] < 127)
                putchar(buf[i]);
            else
                printf("\\%02x", buf[i]);
            break;
        }
    }
    printf("\n");
}

int main(int argc, char **argv) {
    long file_size, nread, nwritten;
    unsigned char *buffer, *encrypted_buffer, *decrypted_buffer;
    char *key = gen_key(6);
    FILE *finput = fopen("file.txt", "rb");

    if (finput == NULL) {
        fprintf(stderr, "cannot open file.txt: %s\n", strerror(errno));
        return 1;
    }
    fseek(finput, 0, SEEK_END);
    file_size = ftell(finput);
    rewind(finput);
    printf("File size: %ld\n", file_size);

    buffer = calloc(file_size, sizeof(char));
    nread = fread(buffer, 1, file_size, finput);
    if (nread != file_size) {
        fprintf(stderr, "error reading file.txt: read %ld bytes, expected %ld\n",
                nread, file_size);
    }
    fclose(finput);

    FILE *foutput = fopen("output.bin", "wb");
    if (foutput == NULL) {
        fprintf(stderr, "cannot open output.bin: %s\n", strerror(errno));
        return 1;
    }
    encrypted_buffer = xor(buffer, nread, key);
    nwritten = fwrite(encrypted_buffer, 1, nread, foutput);
    if (nwritten != nread) {
        fprintf(stderr, "error writing output.bin: wrote %ld bytes, expected %ld\n",
                nwritten, nread);
    }
    fclose(foutput);

    decrypted_buffer = xor(encrypted_buffer, nread, key);

    printf("Key      : %s\n", key);
    print_buffer("Original ", buffer, nread);
    print_buffer("Encrypted", encrypted_buffer, nread);
    print_buffer("Decrypted", decrypted_buffer, nread);
    if (!memcmp(decrypted_buffer, buffer, nread))
        printf("OK\n");

    free(decrypted_buffer);
    free(encrypted_buffer);
    free(buffer);
    return 0;
}

char *gen_key(size_t length) {
    const char charset[] = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz012345679";
    const size_t charset_size = sizeof(charset) - 1;
    char *key = (char*)calloc(length + 1, sizeof(char));
    size_t i;

    srand(time(NULL));
    for (i = 0; i < length; i++)
        key[i] = charset[rand() % charset_size];
    return key;
}

unsigned char *xor(unsigned char *file, size_t size, const char *key) {
    size_t i, keylen = strlen(key);
    unsigned char *xor = calloc(size, sizeof(char));
    for (i = 0; i < size; i++)
        xor[i] = file[i] ^ key[i % keylen];
    return xor;
}