I am attempting to create an example that encrypts only the first 2K, 4K, or 8K of a file but my encryption → decryption always seems to be 52 bytes of (encryption always outputs 4148 bytes, for example and the decryption specifically 4096 with no final cipher update output). What am I missing?
#define _POSIX_C_SOURCE 200112L
#include “mbedtls/build_info.h”
#include “mbedtls/platform.h”
#include “mbedtls/cipher.h”
#include “mbedtls/md.h”
#include “mbedtls/platform.h”
#include “mbedtls/platform_util.h”
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <unistd.h>
#define MODE_ENCRYPT 1
#define MODE_DECRYPT 0
// File encryption helper function
int encryptFile(char *strFileName)
{
unsigned n;
int mode, i, ret = 1;
int exit_code = MBEDTLS_EXIT_FAILURE;
size_t keylen, ilen, olen;
FILE *fin = NULL, *fout = NULL;
char *p;
unsigned char IV[16];
unsigned char key[512];
unsigned char digest[MBEDTLS_MD_MAX_SIZE];
unsigned char buffer[1024];
unsigned char output[1024];
unsigned char diff;
const mbedtls_cipher_info_t *cipher_info;
const mbedtls_md_info_t *md_info;
off_t filesize, offset;
mbedtls_cipher_context_t cipher_ctx;
mbedtls_md_context_t md_ctx;
mbedtls_cipher_init(&cipher_ctx);
mbedtls_md_init(&md_ctx);
// Set to encrypt
mode = MODE_DECRYPT;
// Open source file
if ((fin = fopen(strFileName, "rb")) == NULL) {
mbedtls_fprintf(stderr, "fopen(%s,rb) failed\n",strFileName);
goto exit;
}
mbedtls_fprintf(stdout,"encryptFile() -> DEBUG: Done opening:%s\n", strFileName);
// Open destination file
char strOutputFileName[255] = "";
char suffix[] = ".enc";
strcpy(strOutputFileName, strFileName);
strcat(strOutputFileName, suffix);
// mbedtls_fprintf(stdout,"DEBUG: Output filename=%s\n", strOutputFileName);
if ((fout = fopen(strOutputFileName, "wb+")) == NULL) {
mbedtls_fprintf(stderr, "fopen(%s,wb+) failed\n",strOutputFileName);
goto exit;
}
/* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
mbedtls_setbuf(fin, NULL);
mbedtls_setbuf(fout, NULL);
/*
* Read the Cipher and MD from the command line
*/
cipher_info = mbedtls_cipher_info_from_string("AES-128-CBC");
if (cipher_info == NULL) {
mbedtls_fprintf(stderr, "Cipher 'AES-128-CBC' not found\n");
goto exit;
}
if ((ret = mbedtls_cipher_setup(&cipher_ctx, cipher_info)) != 0) {
mbedtls_fprintf(stderr, "mbedtls_cipher_setup failed\n");
goto exit;
}
md_info = mbedtls_md_info_from_string("SHA1");
if (md_info == NULL) {
mbedtls_fprintf(stderr, "Message Digest 'SHA1' not found\n");
goto exit;
}
if (mbedtls_md_setup(&md_ctx, md_info, 1) != 0) {
mbedtls_fprintf(stderr, "mbedtls_md_setup failed\n");
goto exit;
}
/*
* TODO: Read the secret key from file or command line
*/
const char secretKey[] = "E76B2413958B00E193";
keylen = strlen(secretKey);
// mbedtls_fprintf(stderr, "key1:%s\n",key);
// mbedtls_fprintf(stderr, "keylen1:%i\n",keylen);
// mbedtls_fprintf(stderr, "sizeof-keylen1:%i\n",(int) sizeof(key));
if (keylen > (int) sizeof(key)) {
keylen = (int) sizeof(key);
}
memcpy(key, secretKey, keylen);
// mbedtls_fprintf(stderr, "key:%s\n",key);
// mbedtls_fprintf(stderr, "keylen2:%i\n",keylen);
if ((filesize = lseek(fileno(fin), 0, SEEK_END)) < 0) {
perror("lseek");
goto exit;
}
if (fseek(fin, 0, SEEK_SET) < 0) {
mbedtls_fprintf(stderr, "fseek(0,SEEK_SET) failed\n");
goto exit;
}
/* ENCRYPT */
if (mode == MODE_ENCRYPT) {
mbedtls_fprintf(stdout, "DEBUG -> Mode: Encrypt.\n");
/*
* Generate the initialization vector as:
* IV = MD( filesize || filename )[0..15]
*/
for (i = 0; i < 8; i++) {
buffer[i] = (unsigned char) (filesize >> (i << 3));
}
p = strFileName;
if (mbedtls_md_starts(&md_ctx) != 0) {
mbedtls_fprintf(stderr, "mbedtls_md_starts() returned error\n");
goto exit;
}
if (mbedtls_md_update(&md_ctx, buffer, 8) != 0) {
mbedtls_fprintf(stderr, "mbedtls_md_update() returned error\n");
goto exit;
}
if (mbedtls_md_update(&md_ctx, (unsigned char *) p, strlen(p))
!= 0) {
mbedtls_fprintf(stderr, "mbedtls_md_update() returned error\n");
goto exit;
}
if (mbedtls_md_finish(&md_ctx, digest) != 0) {
mbedtls_fprintf(stderr, "mbedtls_md_finish() returned error\n");
goto exit;
}
memcpy(IV, digest, 16);
/*
* Append the IV at the beginning of the output.
*/
if (fwrite(IV, 1, 16, fout) != 16) {
mbedtls_fprintf(stderr, "fwrite(%d bytes) failed\n", 16);
goto exit;
}
// Allocate memory for mBuffer
unsigned char mBuffer[16000];
size_t totalBytesCopied = 0;
// Append to mBuffer
memcpy(mBuffer, IV, 16);
totalBytesCopied += 16;
// mbedtls_fprintf(stdout, "DEBUG: Length of mBuffer: %d bytes\n", strlen(mBuffer));
// mbedtls_fprintf(stdout, "DEBUG: Total bytes copied\n", strlen(mBuffer));
/*
* Hash the IV and the secret key together 8192 times
* using the result to setup the AES context and HMAC.
*/
memset(digest, 0, 32);
memcpy(digest, IV, 16);
for (i = 0; i < 8192; i++) {
if (mbedtls_md_starts(&md_ctx) != 0) {
mbedtls_fprintf(stderr,
"mbedtls_md_starts() returned error\n");
goto exit;
}
if (mbedtls_md_update(&md_ctx, digest, 32) != 0) {
mbedtls_fprintf(stderr,
"mbedtls_md_update() returned error\n");
goto exit;
}
if (mbedtls_md_update(&md_ctx, key, keylen) != 0) {
mbedtls_fprintf(stderr,
"mbedtls_md_update() returned error\n");
goto exit;
}
if (mbedtls_md_finish(&md_ctx, digest) != 0) {
mbedtls_fprintf(stderr,
"mbedtls_md_finish() returned error\n");
goto exit;
}
}
if (mbedtls_cipher_setkey(&cipher_ctx,
digest,
(int) mbedtls_cipher_info_get_key_bitlen(cipher_info),
MBEDTLS_ENCRYPT) != 0) {
mbedtls_fprintf(stderr, "mbedtls_cipher_setkey() returned error\n");
goto exit;
}
if (mbedtls_cipher_set_iv(&cipher_ctx, IV, 16) != 0) {
mbedtls_fprintf(stderr, "mbedtls_cipher_set_iv() returned error\n");
goto exit;
}
if (mbedtls_cipher_reset(&cipher_ctx) != 0) {
mbedtls_fprintf(stderr, "mbedtls_cipher_reset() returned error\n");
goto exit;
}
if (mbedtls_md_hmac_starts(&md_ctx, digest, 32) != 0) {
mbedtls_fprintf(stderr, "mbedtls_md_hmac_starts() returned error\n");
goto exit;
}
/*
* Encrypt and write the ciphertext.
*/
int bytesProcessed = 0;
for (offset = 0; offset < filesize; offset += mbedtls_cipher_get_block_size(&cipher_ctx)) {
ilen = ((unsigned int) filesize - offset > mbedtls_cipher_get_block_size(&cipher_ctx)) ?
mbedtls_cipher_get_block_size(&cipher_ctx) : (unsigned int) (filesize - offset);
if (fread(buffer, 1, ilen, fin) != ilen) {
mbedtls_fprintf(stderr, "fread(%ld bytes) failed\n", (long) ilen);
goto exit;
}
if (mbedtls_cipher_update(&cipher_ctx, buffer, ilen, output, &olen) != 0) {
mbedtls_fprintf(stderr, "mbedtls_cipher_update() returned error\n");
goto exit;
}
if (mbedtls_md_hmac_update(&md_ctx, output, olen) != 0) {
mbedtls_fprintf(stderr, "mbedtls_md_hmac_update() returned error\n");
goto exit;
}
if (fwrite(output, 1, olen, fout) != olen) {
mbedtls_fprintf(stderr, "fwrite(%ld bytes) failed\n", (long) olen);
goto exit;
}
// Append to mBuffer
memcpy(mBuffer + totalBytesCopied, output, olen);
totalBytesCopied += olen;
bytesProcessed += olen;
mbedtls_fprintf(stdout, "DEBUG2 FOR LOOP: Bytes processed : >>%ld<<\n", (int) bytesProcessed);
mbedtls_fprintf(stdout, "DEBUG2 FOR LOOP: Total bytes copied: >>%ld<<\n", (long) totalBytesCopied);
// Break if the 4KB limit is reached
if (bytesProcessed >= 4096) {
break;
}
}
if (mbedtls_cipher_finish(&cipher_ctx, output, &olen) != 0) {
mbedtls_fprintf(stderr, "mbedtls_cipher_finish() returned error\n");
goto exit;
}
if (mbedtls_md_hmac_update(&md_ctx, output, olen) != 0) {
mbedtls_fprintf(stderr, "mbedtls_md_hmac_update() returned error\n");
goto exit;
}
if (fwrite(output, 1, olen, fout) != olen) {
mbedtls_fprintf(stderr, "fwrite(%ld bytes) failed\n", (long) olen);
goto exit;
}
// Append to mBuffer
memcpy(mBuffer + totalBytesCopied, output, olen);
totalBytesCopied += olen;
mbedtls_fprintf(stdout, "DEBUG2.5 FOR LOOP: Bytes processed : >>%ld<<\n", (int) bytesProcessed);
mbedtls_fprintf(stdout, "DEBUG2.5 FOR LOOP: Total bytes copied: >>%ld<<\n", (long) totalBytesCopied);
/*
* Finally write the HMAC.
*/
if (mbedtls_md_hmac_finish(&md_ctx, digest) != 0) {
mbedtls_fprintf(stderr, "mbedtls_md_hmac_finish() returned error\n");
goto exit;
}
if (fwrite(digest, 1, mbedtls_md_get_size(md_info), fout) != mbedtls_md_get_size(md_info)) {
mbedtls_fprintf(stderr, "fwrite(%d bytes) failed\n", mbedtls_md_get_size(md_info));
goto exit;
} else {
mbedtls_fprintf(stdout, "fwrite(%d bytes) success\n", mbedtls_md_get_size(md_info));
}
mbedtls_fprintf(stdout, "DEBUG3 BEFORE HMAC: Total bytes copied : >>%ld<<\n", (long) totalBytesCopied);
mbedtls_fprintf(stdout, "DEBUG3 BEFORE mbedtls_md_get_size(md_info): >>%ld<<\n", mbedtls_md_get_size(md_info));
// Append HMAC to mBuffer
memcpy(mBuffer + totalBytesCopied, digest, mbedtls_md_get_size(md_info));
totalBytesCopied += mbedtls_md_get_size(md_info);
mbedtls_fprintf(stdout, "DEBUG3 HMAC: Total bytes copied : >>%ld<<\n", (long) totalBytesCopied);
mbedtls_fprintf(stdout, "DEBUG3 mbedtls_md_get_size(md_info): >>%ld<<\n", mbedtls_md_get_size(md_info));
// FILE* pFile;
// pFile = fopen(“/tmp/files/example.txt.enc.2”,“wb”);
// if (pFile) {
// fwrite(mBuffer, 1, totalBytesCopied, pFile);
// }
// fclose(pFile);
// Overwrite the original file
if (fin) {
fclose(fin);
}
FILE* oFile;
oFile = fopen(strFileName,"rb+");
if (oFile) {
fseek(oFile, 0, SEEK_SET);
fwrite(mBuffer, 1, totalBytesCopied, oFile);
mbedtls_fprintf(stdout, "DEBUG: Sucessfully wrote to %s %d bytes\n",strFileName,totalBytesCopied);
} else {
mbedtls_fprintf(stdout, "DEBUG: Unable to open original file for overwriting!\n");
}
fclose(oFile);
}
/* DECRYPT */
if (mode == MODE_DECRYPT) {
mbedtls_fprintf(stdout, "DEBUG -> Mode: Decrypt.\n");
/*
* The encrypted file must be structured as follows:
*
* 00 .. 15 Initialization Vector
* 16 .. 31 Encrypted Block #1
* ..
* N*16 .. (N+1)*16 - 1 Encrypted Block #N
* (N+1)*16 .. (N+1)*16 + n Hash(ciphertext)
*/
if (filesize < 16 + mbedtls_md_get_size(md_info)) {
mbedtls_fprintf(stderr, "File too short to be decrypted.\n");
goto exit;
}
if (mbedtls_cipher_get_block_size(&cipher_ctx) == 0) {
mbedtls_fprintf(stderr, "Invalid cipher block size: 0. \n");
goto exit;
}
/*
* Check the file size.
*/
if (mbedtls_cipher_info_get_mode(cipher_info) != MBEDTLS_MODE_GCM &&
((filesize - mbedtls_md_get_size(md_info)) %
mbedtls_cipher_get_block_size(&cipher_ctx)) != 0) {
mbedtls_fprintf(stderr, "File content not a multiple of the block size (%u).\n",
mbedtls_cipher_get_block_size(&cipher_ctx));
// TODO: 4KB goto exit;
}
/*
* Subtract the IV + HMAC length.
*/
filesize -= (16 + mbedtls_md_get_size(md_info));
/*
* Read the IV and original filesize modulo 16.
*/
if (fread(buffer, 1, 16, fin) != 16) {
mbedtls_fprintf(stderr, "fread(%d bytes) failed\n", 16);
goto exit;
}
memcpy(IV, buffer, 16);
/*
* Hash the IV and the secret key together 8192 times
* using the result to setup the AES context and HMAC.
*/
memset(digest, 0, 32);
memcpy(digest, IV, 16);
for (i = 0; i < 8192; i++) {
if (mbedtls_md_starts(&md_ctx) != 0) {
mbedtls_fprintf(stderr, "mbedtls_md_starts() returned error\n");
goto exit;
}
if (mbedtls_md_update(&md_ctx, digest, 32) != 0) {
mbedtls_fprintf(stderr, "mbedtls_md_update() returned error\n");
goto exit;
}
if (mbedtls_md_update(&md_ctx, key, keylen) != 0) {
mbedtls_fprintf(stderr, "mbedtls_md_update() returned error\n");
goto exit;
}
if (mbedtls_md_finish(&md_ctx, digest) != 0) {
mbedtls_fprintf(stderr, "mbedtls_md_finish() returned error\n");
goto exit;
}
}
if (mbedtls_cipher_setkey(&cipher_ctx,
digest,
(int) mbedtls_cipher_info_get_key_bitlen(cipher_info),
MBEDTLS_DECRYPT) != 0) {
mbedtls_fprintf(stderr, "mbedtls_cipher_setkey() returned error\n");
goto exit;
}
if (mbedtls_cipher_set_iv(&cipher_ctx, IV, 16) != 0) {
mbedtls_fprintf(stderr, "mbedtls_cipher_set_iv() returned error\n");
goto exit;
}
if (mbedtls_cipher_reset(&cipher_ctx) != 0) {
mbedtls_fprintf(stderr, "mbedtls_cipher_reset() returned error\n");
goto exit;
}
if (mbedtls_md_hmac_starts(&md_ctx, digest, 32) != 0) {
mbedtls_fprintf(stderr, "mbedtls_md_hmac_starts() returned error\n");
goto exit;
}
// Allocate memory for dBuffer
unsigned char dBuffer[16000];
size_t totalBytesDecrypted = 0;
/*
* Decrypt and write the plaintext.
*/
int bytesProcessed = 0;
for (offset = 0; offset < filesize; offset += mbedtls_cipher_get_block_size(&cipher_ctx)) {
ilen = ((unsigned int) filesize - offset > mbedtls_cipher_get_block_size(&cipher_ctx)) ?
mbedtls_cipher_get_block_size(&cipher_ctx) : (unsigned int) (filesize - offset);
if (fread(buffer, 1, ilen, fin) != ilen) {
mbedtls_fprintf(stderr, "fread(%u bytes) failed\n",
mbedtls_cipher_get_block_size(&cipher_ctx));
goto exit;
}
if (mbedtls_md_hmac_update(&md_ctx, buffer, ilen) != 0) {
mbedtls_fprintf(stderr, "mbedtls_md_hmac_update() returned error\n");
goto exit;
}
if (mbedtls_cipher_update(&cipher_ctx, buffer, ilen, output,
&olen) != 0) {
mbedtls_fprintf(stderr, "mbedtls_cipher_update() returned error\n");
goto exit;
}
// if (fwrite(output, 1, olen, fout) != olen) {
// mbedtls_fprintf(stderr, "fwrite(%ld bytes) failed\n", (long) olen);
// goto exit;
// }
// Append to mBuffer
memcpy(dBuffer + totalBytesDecrypted, output, olen);
totalBytesDecrypted += olen;
bytesProcessed += olen;
mbedtls_fprintf(stdout, "DEBUG2 FOR LOOP: Bytes processed : >>%ld<<\n", (int) bytesProcessed);
mbedtls_fprintf(stdout, "DEBUG2 FOR LOOP: Bytes decrypted : >>%ld<<\n", (int) totalBytesDecrypted);
// Break if the 4KB limit is reached
if (bytesProcessed >= 4096) {
break;
}
}
/*
* Verify the message authentication code.
*/
if (mbedtls_md_hmac_finish(&md_ctx, digest) != 0) {
mbedtls_fprintf(stderr, "mbedtls_md_hmac_finish() returned error\n");
// goto exit;
}
if (fread(buffer, 1, mbedtls_md_get_size(md_info), fin) != mbedtls_md_get_size(md_info)) {
mbedtls_fprintf(stderr, "fread(%d bytes) failed\n", mbedtls_md_get_size(md_info));
// goto exit;
}
/* Use constant-time buffer comparison */
diff = 0;
for (i = 0; i < mbedtls_md_get_size(md_info); i++) {
diff |= digest[i] ^ buffer[i];
}
if (diff != 0) {
mbedtls_fprintf(stderr, "HMAC check failed: wrong key, or file corrupted.\n");
// TODO: 4KB goto exit;
}
// Write the final block of data
if (mbedtls_cipher_finish(&cipher_ctx, output, &olen) != 0) {
mbedtls_fprintf(stderr, "mbedtls_cipher_finish() returned error\n");
// TODO: 4KB goto exit;
}
// if (fwrite(output, 1, olen, fout) != olen) {
// mbedtls_fprintf(stderr, "fwrite(%ld bytes) failed\n", (long) olen);
// // TODO: 4KB goto exit;
// }
// Append to mBuffer
memcpy(dBuffer + totalBytesDecrypted, output, olen);
totalBytesDecrypted += olen;
mbedtls_fprintf(stderr, "mbedtls_cipher_finish() Writing final block: (%ld bytes)\n", (long) olen);
mbedtls_fprintf(stdout, "DEBUG2 FOR LOOP: Bytes processed : >>%ld<<\n", (int) bytesProcessed);
mbedtls_fprintf(stdout, "DEBUG2 FOR LOOP: Bytes decrypted : >>%ld<<\n", (int) totalBytesDecrypted);
// Overwrite the original file
if (fin) {
fclose(fin);
}
if (fout) {
fclose(fout);
}
FILE* oFile;
oFile = fopen(strFileName,"rb+");
if (oFile) {
fseek(oFile, 0, SEEK_SET);
fwrite(dBuffer, 1, totalBytesDecrypted, oFile);
mbedtls_fprintf(stdout,"Successfully wrote to oFile: %d bytes\n",totalBytesDecrypted);
} else {
mbedtls_fprintf(stderr, "DEBUG2: Unable to open original file for overwriting!\n");
}
fclose(oFile);
}
exit_code = MBEDTLS_EXIT_SUCCESS;
return 0;
exit:
if (fin) {
fclose(fin);
}
if (fout) {
fclose(fout);
}
mbedtls_platform_zeroize(IV, sizeof(IV));
mbedtls_platform_zeroize(key, sizeof(key));
mbedtls_platform_zeroize(buffer, sizeof(buffer));
mbedtls_platform_zeroize(output, sizeof(output));
mbedtls_platform_zeroize(digest, sizeof(digest));
mbedtls_cipher_free(&cipher_ctx);
mbedtls_md_free(&md_ctx);
mbedtls_exit(exit_code);
return -1;
}
/* Main */
int main() {
char *fileName = "/tmp/files/example.txt";
encryptFile(fileName);
return 0;
}