C 中的 fwrite 在文件末尾添加额外的二进制字符

时间:2021-04-20 06:34:29

标签: c encryption aes fwrite

要求:

我是一名开发人员,但直到一周前我对 C 的经验几乎为零。对于一个项目,我需要加密/解密源代码/文本文件,并且需要为此使用 C。

我做了什么?

我正在使用 Kokke/tony-AES-c 库,并按照 this Gist 中的说明使用 pkcs7 填充来实现它。我写的代码是:

ma​​in.c

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

#define CBC 1
#define DECRYPT 0
#define ENCRYPT 1

#include "aes.h"
#include "pkcs7_padding.h"

const void my_decrypt(char *report, char *output_file, long dlen) {
    FILE *op_file;

    //Initialization Vector
    uint8_t iv[]  = { 0x75, 0x52, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x21, 0x21 };

    uint8_t i;
    char* key = "thisIstheKey";
//    int dlen = strlen(report);
    int klen = strlen(key);

    printf("THE encrypted TEXT STRING = ");
    for (i=0; i<dlen;i++){
        printf("%c", report[i]);
    }
    printf("\n");

    //Proper Length of report
    int dlenu = dlen;
//    if (dlen % 16) {
//        dlenu += 16 - (dlen % 16);
//        printf("The original length of the STRING = %d and the length of the padded STRING = %d\n", dlen, dlenu);
//    }

    //Proper length of key
    int klenu = klen;
    if (klen % 16) {
        klenu += 16 - (klen % 16);
        printf("The original length of the KEY = %d and the length of the padded KEY = %d\n", klen, klenu);
    }

    // Make the uint8_t arrays
    uint8_t hexarray[dlenu];
    uint8_t kexarray[klenu];

    // Initialize them with zeros
    memset( hexarray, 0, dlenu );
    memset( kexarray, 0, klenu );

    // Fill the uint8_t arrays
    for (int i=0;i<dlen;i++) {
        hexarray[i] = (uint8_t)report[i];
    }
    for (int i=0;i<klen;i++) {
        kexarray[i] = (uint8_t)key[i];
    }

    int reportPad = pkcs7_padding_pad_buffer( hexarray, dlen, sizeof(hexarray), 16 );
    int keyPad = pkcs7_padding_pad_buffer( kexarray, klen, sizeof(kexarray), 16 );

    printf("The padded STRING in hex is = ");
    for (i=0; i<dlenu;i++){
        printf("%02x",hexarray[i]);
    }
    printf("\n");

    printf("The padded key in hex is = ");
    for (i=0; i<klenu;i++){
        printf("%02x",kexarray[i]);
    }
    printf("\n");

    // In case you want to check if the padding is valid
    int valid = pkcs7_padding_valid( hexarray, dlen, sizeof(hexarray), 16 );
    int valid2 = pkcs7_padding_valid( kexarray, klen, sizeof(kexarray), 16 );
    printf("Is the pkcs7 padding valid  report = %d  |  key = %d\n", valid, valid2);

    //start the decryption
    struct AES_ctx ctx;
    AES_init_ctx_iv(&ctx, kexarray, iv);

    // decrypt
    AES_CBC_decrypt_buffer(&ctx, hexarray, dlenu);

    // ks
    size_t actualDataLength = pkcs7_padding_data_length( hexarray, dlenu, 16);
    printf("The actual data length (without the padding) = %ld\n", actualDataLength);

    printf("the decrypted STRING in hex = ");
    for (i=0; i<actualDataLength;i++){
        printf("%02x",hexarray[i]);
    }
    printf("\n");

    printf("Printing message from variables1\n");
    char* decrypted_message = printf((char*) hexarray);
    printf("Printing message from variables2\n");
//    printf("Decrypted string (decrypted_message) = %s", decrypted_message);
    printf("Decrypted string (hexarray) = %s", (char*)hexarray);

    // Write file
    printf("Writing contents to %s\n", output_file);
    op_file = fopen(output_file, "wb");
    if (!output_file) {
        /* Unable to open temp file for writing */
        fprintf(stderr, "ERROR: fread error: %s\n", strerror(errno));
    }
    int out_len = sizeof (hexarray);
    fwrite(hexarray, sizeof(unsigned char), out_len, op_file);

    fclose(op_file);
}

const void my_encrypt(char *report, char *output_file, long dlen) {
    FILE *op_file;

    //Initialization Vector
    uint8_t iv[]  = { 0x75, 0x52, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x21, 0x21 };

    uint8_t i;
    char* key = "thisIstheKey";
//    int dlen = strlen(report);
    int klen = strlen(key);

    printf("THE PLAIN TEXT STRING = ");
    for (i=0; i<dlen;i++){
        printf("%c", report[i]);
    }
    printf("\n");

    //Proper Length of report
    int dlenu = dlen;
    if (dlen % 16) {
        dlenu += 16 - (dlen % 16);
        printf("The original length of the STRING = %l and the length of the padded STRING = %l\n", dlen, dlenu);
    }

    //Proper length of key
    int klenu = klen;
    if (klen % 16) {
        klenu += 16 - (klen % 16);
        printf("The original length of the KEY = %d and the length of the padded KEY = %d\n", klen, klenu);
    }

    // Make the uint8_t arrays
    uint8_t hexarray[dlenu];
    uint8_t kexarray[klenu];

    // Initialize them with zeros
    memset( hexarray, 0, dlenu );
    memset( kexarray, 0, klenu );

    // Fill the uint8_t arrays
    for (int i=0;i<dlen;i++) {
        hexarray[i] = (uint8_t)report[i];
    }
    for (int i=0;i<klen;i++) {
        kexarray[i] = (uint8_t)key[i];
    }

    int reportPad = pkcs7_padding_pad_buffer( hexarray, dlen, sizeof(hexarray), 16 );
    int keyPad = pkcs7_padding_pad_buffer( kexarray, klen, sizeof(kexarray), 16 );

    printf("The padded STRING in hex is = ");
    for (i=0; i<dlenu;i++){
        printf("%02x",hexarray[i]);
    }
    printf("\n");

    printf("The padded key in hex is = ");
    for (i=0; i<klenu;i++){
        printf("%02x",kexarray[i]);
    }
    printf("\n");

    // In case you want to check if the padding is valid
    int valid = pkcs7_padding_valid( hexarray, dlen, sizeof(hexarray), 16 );
    int valid2 = pkcs7_padding_valid( kexarray, klen, sizeof(kexarray), 16 );
    printf("Is the pkcs7 padding valid  report = %d  |  key = %d\n", valid, valid2);

    //start the encryption
    struct AES_ctx ctx;
    AES_init_ctx_iv(&ctx, kexarray, iv);

    // encrypt
    AES_CBC_encrypt_buffer(&ctx, hexarray, dlenu);

    printf("the encrypted STRING = ");
    for (i=0; i<dlenu;i++){
        printf("%02x",hexarray[i]);
    }
    printf("\n");

    // Write file
    printf("Writing contents to %s\n", output_file);
    op_file = fopen(output_file, "wb");
    if (!output_file) {
        /* Unable to open temp file for writing */
        fprintf(stderr, "ERROR: fread error: %s\n", strerror(errno));
    }
    int out_len = sizeof (hexarray);
    fwrite(hexarray, sizeof(unsigned char), out_len, op_file);
    fclose(op_file);
}

int main(int argc, char *argv[]) {
    // File pointer
    FILE *input_file, *output_file;

    int operation;

    char * input_file_buffer = 0, output_file_buffer = 0;
    long input_file_length;

    // ////////////////////////////////////////////////////////
    // Read command line arguments
    // ////////////////////////////////////////////////////////

    // Make sure proper command params are supplied
    if (argc != 3) {
        printf("Usage: %s encrypt/decrypt filename\n", argv[0]);
        return -1;
    }

    // Define operation type
    if (strcmp(argv[1], "encrypt") == 0) {
        operation = ENCRYPT;
    } else if (strcmp(argv[1], "decrypt") == 0) {
        operation = DECRYPT;
    }

    // ////////////////////////////////////////////////////////
    // Open File contents
    // ////////////////////////////////////////////////////////

    // Open input_file to encrypt/decrypt.
    input_file = fopen(argv[2], "rb");
    if (!input_file) {
        fprintf(stderr, "ERROR: '%s' file fopen error: %s\n", argv[2], strerror(errno));
        return errno;
    }

    // Read contents of file in buffer
    fseek(input_file, 0, SEEK_END);
    input_file_length = ftell (input_file);
    fseek(input_file, 0, SEEK_SET);
    input_file_buffer = malloc (input_file_length);
    if (input_file_buffer)
    {
        fread(input_file_buffer, 1, input_file_length, input_file);
    }

    // Close input_file
    fclose(input_file);

    // We have contents of file in input_file_buffer, let's print them.
    printf("File contents:\n-------\n%s\n", input_file_buffer);

    if (operation == ENCRYPT) {
        // Let's encrypt input_file_buffer
        my_encrypt(input_file_buffer, argv[2], input_file_length);
    } else if (operation == DECRYPT) {
        my_decrypt(input_file_buffer, argv[2], input_file_length);
    }

    return 0;
}

Makefile

# Compiler
CC       = gcc
CFLAGS   = -Wall

# Library options (Needed for OpenSSL)
LDLIBS   = -lcrypto

# Define input/output files
SOURCES  = aes.c pkcs7_padding.c main.c
OBJFILES = aes.o pkcs7_padding.o main.o
TARGET   = encdec

# Generated files
ENCFILE  = temp_encrypted_file
DECFILE  = temp_decrypted_file

# Start building
all: $(TARGET)

$(TARGET): $(OBJFILES)
    $(CC) $(CFLAGS) -o $(TARGET) $(OBJFILES) $(LDLIBS)

# Start clean up
clean:
    rm -f $(OBJFILES) $(TARGET) $(ENCFILE) $(DECFILE)

编译后执行的命令

编译(make all)后,我运行命令 ./encdec encrypt test.php,它加密 test.php 文件。

原始 test.php

<?php

// This is comment to check if comment can also be retrieved after decryption
echo "Hello world!";

// One empty lime after the end (Without closing ?> tag) to check if empty line is retrieved after decryption

运行命令后,一种可能的输出是:

加密的 test.php

cat test.php
��D�zt�5�W�L�QP�8B�n`-`����݇Eֶr��˘�`\��k
��pDZ��8NU��e�T�P|�W�{2�,]��=�'��i:���E��fϓQt�P"���_���,����?�M�����3b3��Al�����|q2������/��
���8�,�˦�VV��q�����a�]�]��#��i5]?����<a�Z����q�I0�?-S�9?%

解密./encdev decrypt test.php后,在test.php中得到如下内容

解密的test.php(在vim中检查)

<?php

// This is comment to check if comment can also be retrieved after decryption
echo "Hello world!";

// One empty lime after the end (Without closing ?> tag) to check if empty line is retrieved after decryption










问题

最后,我得到了 10 个空行,在原始文件中,只有一个。

有人可以帮助我理解我犯了什么错误以及如何摆脱解密文件中额外的 9 行中断吗?

1 个答案:

答案 0 :(得分:2)

my_decrypt() 中,当将解密数据写入文件时,不使用由 pkcs7_padding_data_length() 确定的长度:int out_len = sizeof(hexarray) 必须替换为 int out_len = actualDataLength。这使得解密在我的机器上工作。

此外,my_decrypt() 中密文的填充没有任何意义。它在这里也没有影响,因为 pkcs7_padding_pad_buffer() 由于 data_length + pad_byte > buffer_size 而不会填充(并且 pkcs7_padding_valid() 表示无效的填充)。

此外,不应填充键。如果密钥没有为 AES 定义的长度,最好显示错误消息。如果要使用密码代替密钥,则应使用可靠的密钥派生函数,如 PBKDF2。

最后,出于安全原因,不要应用静态 IV。

相关问题