C 中的 fwrite 在文件末尾添加额外的二进制字符
fwrite in C add extra binary characters at the end of file
要求:
我是一名开发人员,但直到一周前我对 C 的经验几乎为零。对于一个项目,我需要 encrypt/decrypt source-code/text 个文件并且需要为此使用 C。
我做了什么?
我正在使用 Kokke/tony-AES-c library for it and implementing it with pkcs7 padding as explained in this Gist。我写的代码是:
main.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;
}
生成文件
# 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
在 运行ning 命令之后,一种可能的输出是:
加密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 换行符?
在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()
表示无效填充)。
另外,key不要被填充。如果密钥没有为 AES 定义的长度,最好显示一条错误消息。如果要使用密码而不是密钥,应该使用像PBKDF2这样可靠的密钥推导函数。
最后,出于安全原因,请勿应用静态 IV。
要求:
我是一名开发人员,但直到一周前我对 C 的经验几乎为零。对于一个项目,我需要 encrypt/decrypt source-code/text 个文件并且需要为此使用 C。
我做了什么?
我正在使用 Kokke/tony-AES-c library for it and implementing it with pkcs7 padding as explained in this Gist。我写的代码是:
main.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;
}
生成文件
# 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
在 运行ning 命令之后,一种可能的输出是:
加密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 换行符?
在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()
表示无效填充)。
另外,key不要被填充。如果密钥没有为 AES 定义的长度,最好显示一条错误消息。如果要使用密码而不是密钥,应该使用像PBKDF2这样可靠的密钥推导函数。
最后,出于安全原因,请勿应用静态 IV。