From 8dc4f69e9428a9568daed857d5476712644894d3 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Tue, 21 Jan 2020 15:04:56 -0800 Subject: [PATCH] add aes-cfb example case --- crypto/aes/Makefile | 7 +- crypto/aes/aes-file-encrypt.c | 6 +- crypto/aes/aescfb-file-encrypt.c | 363 +++++++++++++++++++++++++++++++ 3 files changed, 372 insertions(+), 4 deletions(-) create mode 100644 crypto/aes/aescfb-file-encrypt.c diff --git a/crypto/aes/Makefile b/crypto/aes/Makefile index cef21864..31f92333 100644 --- a/crypto/aes/Makefile +++ b/crypto/aes/Makefile @@ -2,10 +2,15 @@ CC=gcc CFLAGS=-Wall LIBS= -lwolfssl +all: aes-file-encrypt aescfb-file-encrypt + aes-file-encrypt: aes-file-encrypt.o $(CC) -o $@ $^ $(CFLAGS) $(LIBS) +aescfb-file-encrypt: aescfb-file-encrypt.o + $(CC) -o $@ $^ $(CFLAGS) $(LIBS) + .PHONY: clean clean: - rm -f *.o aes-file-encrypt + rm -f *.o aes-file-encrypt aescfb-file-encrypt diff --git a/crypto/aes/aes-file-encrypt.c b/crypto/aes/aes-file-encrypt.c index b6deb805..6523a7c7 100644 --- a/crypto/aes/aes-file-encrypt.c +++ b/crypto/aes/aes-file-encrypt.c @@ -33,7 +33,7 @@ /* * Makes a cryptographically secure key by stretching a user entered key */ -int GenerateKey(RNG* rng, byte* key, int size, byte* salt, int pad) +int GenerateKey(WC_RNG* rng, byte* key, int size, byte* salt, int pad) { int ret; @@ -58,7 +58,7 @@ int GenerateKey(RNG* rng, byte* key, int size, byte* salt, int pad) */ int AesEncrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile) { - RNG rng; + WC_RNG rng; byte iv[AES_BLOCK_SIZE]; byte* input; byte* output; @@ -144,7 +144,7 @@ int AesEncrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile) */ int AesDecrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile) { - RNG rng; + WC_RNG rng; byte iv[AES_BLOCK_SIZE]; byte* input; byte* output; diff --git a/crypto/aes/aescfb-file-encrypt.c b/crypto/aes/aescfb-file-encrypt.c new file mode 100644 index 00000000..bfbba656 --- /dev/null +++ b/crypto/aes/aescfb-file-encrypt.c @@ -0,0 +1,363 @@ +/* aescfb-file-encrypt.c + * + * Copyright (C) 2006-2020 wolfSSL Inc. + * + * This file is part of wolfSSL. (formerly known as CyaSSL) + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WOLFSSL_AES_CFB +#define SALT_SIZE 8 + +/* + * Makes a cryptographically secure key by stretching a user entered key + */ +int GenerateKey(WC_RNG* rng, byte* key, int size, byte* salt, int pad) +{ + int ret; + + ret = wc_RNG_GenerateBlock(rng, salt, SALT_SIZE); + if (ret != 0) + return -1020; + + if (pad == 0) + salt[0] = 0; + + /* stretches key */ + ret = wc_PBKDF2(key, key, strlen((const char*)key), salt, SALT_SIZE, 4096, + size, WC_SHA256); + if (ret != 0) + return -1030; + + return 0; +} + +/* + * Encrypts a file using AES + */ +int AesEncrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile) +{ + WC_RNG rng; + byte iv[AES_BLOCK_SIZE]; + byte* input; + byte* output; + byte salt[SALT_SIZE] = {0}; + + int i = 0; + int ret = 0; + int inputLength; + int length; + int padCounter = 0; + + fseek(inFile, 0, SEEK_END); + inputLength = ftell(inFile); + fseek(inFile, 0, SEEK_SET); + + length = inputLength; + /* pads the length until it evenly matches a block / increases pad number*/ + while (length % AES_BLOCK_SIZE != 0) { + length++; + padCounter++; + } + + input = malloc(length); + output = malloc(length); + + ret = wc_InitRng(&rng); + if (ret != 0) { + printf("Failed to initialize random number generator\n"); + return -1030; + } + + /* reads from inFile and writes whatever is there to the input array */ + ret = fread(input, 1, inputLength, inFile); + if (ret == 0) { + printf("Input file does not exist.\n"); + return -1010; + } + for (i = inputLength; i < length; i++) { + /* pads the added characters with the number of pads */ + input[i] = padCounter; + } + + ret = wc_RNG_GenerateBlock(&rng, iv, AES_BLOCK_SIZE); + if (ret != 0) + return -1020; + + /* stretches key to fit size */ + ret = GenerateKey(&rng, key, size, salt, padCounter); + if (ret != 0) + return -1040; + + /* sets key */ + ret = wc_AesSetKey(aes, key, AES_BLOCK_SIZE, iv, AES_ENCRYPTION); + if (ret != 0) + return -1001; + + /* encrypts the message to the output based on input length + padding */ + ret = wc_AesCfbEncrypt(aes, output, input, length); + if (ret != 0) + return -1005; + + /* writes to outFile */ + fwrite(salt, 1, SALT_SIZE, outFile); + fwrite(iv, 1, AES_BLOCK_SIZE, outFile); + fwrite(output, 1, length, outFile); + + /* closes the opened files and frees the memory*/ + memset(input, 0, length); + memset(output, 0, length); + memset(key, 0, size); + free(input); + free(output); + free(key); + fclose(inFile); + fclose(outFile); + wc_FreeRng(&rng); + + return ret; +} + +/* + * Decrypts a file using AES + */ +int AesDecrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile) +{ + WC_RNG rng; + byte iv[AES_BLOCK_SIZE]; + byte* input; + byte* output; + byte salt[SALT_SIZE] = {0}; + + int i = 0; + int ret = 0; + int length; + int aSize; + + fseek(inFile, 0, SEEK_END); + length = ftell(inFile); + fseek(inFile, 0, SEEK_SET); + aSize = length; + + input = malloc(aSize); + output = malloc(aSize); + + wc_InitRng(&rng); + + /* reads from inFile and writes whatever is there to the input array */ + ret = fread(input, 1, length, inFile); + if (ret == 0) { + printf("Input file does not exist.\n"); + return -1010; + } + for (i = 0; i < SALT_SIZE; i++) { + /* finds salt from input message */ + salt[i] = input[i]; + } + for (i = SALT_SIZE; i < AES_BLOCK_SIZE + SALT_SIZE; i++) { + /* finds iv from input message */ + iv[i - SALT_SIZE] = input[i]; + } + + /* replicates old key if keys match */ + ret = wc_PBKDF2(key, key, strlen((const char*)key), salt, SALT_SIZE, 4096, + size, WC_SHA256); + if (ret != 0) + return -1050; + + /* sets key */ + ret = wc_AesSetKey(aes, key, AES_BLOCK_SIZE, iv, AES_ENCRYPTION); + if (ret != 0) + return -1002; + + /* change length to remove salt/iv block from being decrypted */ + length -= (AES_BLOCK_SIZE + SALT_SIZE); + for (i = 0; i < length; i++) { + /* shifts message: ignores salt/iv on message*/ + input[i] = input[i + (AES_BLOCK_SIZE + SALT_SIZE)]; + } + /* decrypts the message to output based on input length + padding*/ + ret = wc_AesCfbDecrypt(aes, output, input, length); + if (ret != 0) + return -1006; + + if (salt[0] != 0) { + /* reduces length based on number of padded elements */ + length -= output[length-1]; + } + /* writes output to the outFile based on shortened length */ + fwrite(output, 1, length, outFile); + + /* closes the opened files and frees the memory*/ + memset(input, 0, aSize); + memset(output, 0, aSize); + memset(key, 0, size); + free(input); + free(output); + free(key); + fclose(inFile); + fclose(outFile); + wc_FreeRng(&rng); + + return 0; +} + +/* + * help message + */ +void help() +{ + printf("\n~~~~~~~~~~~~~~~~~~~~|Help|~~~~~~~~~~~~~~~~~~~~~\n\n"); + printf("Usage: ./aes-file-encrypt <-option> <-i file.in> " + "<-o file.out>\n\n"); + printf("Options\n"); + printf("-d Decryption\n-e Encryption\n-h Help\n"); +} + +/* + * temporarily disables echoing in terminal for secure key input + */ +int NoEcho(char* key, int size) +{ + struct termios oflags, nflags; + + /* disabling echo */ + tcgetattr(fileno(stdin), &oflags); + nflags = oflags; + nflags.c_lflag &= ~ECHO; + nflags.c_lflag |= ECHONL; + + if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0) { + printf("Error: tcsetattr failed to disable terminal echo\n"); + return -1060; + } + + printf("Unique Password: "); + if (fgets(key, size, stdin) == NULL) { + printf("Error: fgets failed to retrieve secure key input\n"); + return -1070; + } + + key[strlen(key) - 1] = 0; + + /* restore terminal */ + if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0) { + printf("Error: tcsetattr failed to enable terminal echo\n"); + return -1080; + } + return 0; +} + +int SizeCheck(int size) +{ + int ret = 0; + + if (size != 128 && size != 192 && size != 256) { + /* if the entered size does not match acceptable size */ + printf("Invalid AES key size\n"); + ret = -1080; + } + + return ret; +} + +int main(int argc, char** argv) +{ + Aes aes; + byte* key; /* user entered key */ + FILE* inFile = NULL; + FILE* outFile = NULL; + + const char* in; + const char* out; + + int option; /* choice of how to run program */ + int ret = 0; /* return value */ + int size = 0; + int inCheck = 0; + int outCheck = 0; + char choice = 'n'; + + while ((option = getopt(argc, argv, "d:e:i:o:h")) != -1) { + switch (option) { + case 'd': /* if entered decrypt */ + size = atoi(optarg); + ret = SizeCheck(size); + choice = 'd'; + break; + case 'e': /* if entered encrypt */ + size = atoi(optarg); + ret = SizeCheck(size); + choice = 'e'; + break; + case 'h': /* if entered 'help' */ + help(); + break; + case 'i': /* input file */ + in = optarg; + inCheck = 1; + inFile = fopen(in, "r"); + break; + case 'o': /* output file */ + out = optarg; + outCheck = 1; + outFile = fopen(out, "w"); + break; + case '?': + if (optopt) { + printf("Ending Session\n"); + return -111; + } + default: + abort(); + } + } + if (inCheck == 0 || outCheck == 0) { + printf("Must have both input and output file"); + printf(": -i filename -o filename\n"); + } + else if (ret == 0 && choice != 'n' && inFile != NULL) { + key = malloc(size); /* sets size memory of key */ + ret = NoEcho((char*)key, size); + if (choice == 'e') + AesEncrypt(&aes, key, size, inFile, outFile); + else if (choice == 'd') + AesDecrypt(&aes, key, size, inFile, outFile); + } + else if (choice == 'n') { + printf("Must select either -e or -d for encryption and decryption\n"); + ret = -110; + } + + return ret; +} + +#else +int main() +{ + printf("AES-CFB not compiled in\n"); + return 0; +} +#endif