Skip to content

Instantly share code, notes, and snippets.

@ignatk
Created December 19, 2013 17:27
Show Gist options
  • Save ignatk/8043020 to your computer and use it in GitHub Desktop.
Save ignatk/8043020 to your computer and use it in GitHub Desktop.
File encryption utility
/*
============================================================================
Name : filecrypt.c
Author : Ignat
Version :
Copyright : Public domain
Description : File cryptor in C, Ansi-style
============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 1024
#define DEFAULT_CIPHER "aes-128-cbc"
#include <openssl/evp.h>
#include <openssl/bn.h>
static void usage(FILE* file, char* progname)
{
/* For Unix */
char* shortname = strrchr(progname, '/');
/* For Windows */
if (!shortname)
shortname = strrchr(progname, '\\');
if (shortname)
shortname++;
else
shortname = progname;
fprintf(file, "\tUsage: %s { -e | -d } { -k <hexkey> | -p <passowrd> } -iv <initvector> [-c <cipher>] -i <input file> -o <output file>\n", shortname);
fprintf(file, "\t-e - encrypt mode\n");
fprintf(file, "\t-d - decrypt mode\n");
fprintf(file, "\t-k <hexkey> - key in hex format\n");
fprintf(file, "\t-p <password> - password\n");
fprintf(file, "\t-iv <initvector> - initial vector\n");
fprintf(file, "\t-c <cipher> - cipher to use (for names see \"openssl cipher\" command)\n");
}
static unsigned char parse_char(char c)
{
if ((c >= '0') && (c <= '9'))
return c - 48;
else if ((c >= 'A') && (c <= 'F'))
return c - ('A' - 0xa);
else if ((c >= 'a') && (c <= 'f'))
return c - ('a' - 0xa);
else
return 0xff;
}
static int hex_to_bytes(const char *hexstr, unsigned char *bytes, size_t len)
{
size_t hexlen = strlen(hexstr), i = 0;
if ((hexlen & 1) || (hexlen > (2 * len)))
return 0;
for (i = 0; i < (hexlen / 2); i++)
{
unsigned char c = parse_char(hexstr[2 * i]);
if (0xff == c)
return 0;
bytes[i] = c << 4;
c = parse_char(hexstr[(2 * i) + 1]);
if (0xff == c)
return 0;
bytes[i] |= c;
}
return hexlen / 2;
}
static int process_file(FILE *input, FILE *output, const char *password, const char *key, const char *iv, const EVP_CIPHER *cipher, int encrypt)
{
unsigned char buffer[BUFFER_SIZE], k[EVP_MAX_KEY_LENGTH], i[EVP_MAX_IV_LENGTH];
size_t bytes_read = 0;
EVP_CIPHER_CTX *cipher_ctx = NULL;
if (password)
{
if (!PKCS5_PBKDF2_HMAC_SHA1(password, strlen(password), NULL, 0, 1024, EVP_CIPHER_key_length(cipher), k))
{
fprintf(stderr, "Error generating key from password\n");
return 1;
}
}
else
{
if (EVP_CIPHER_key_length(cipher) != hex_to_bytes(key, k, sizeof(k)))
{
fprintf(stderr, "Invalid key\n");
return 1;
}
}
if (iv)
{
if (EVP_CIPHER_iv_length(cipher) != hex_to_bytes(iv, i, sizeof(i)))
{
fprintf(stderr, "Invalid iv\n");
return 1;
}
}
else
memset(i, 0, sizeof(i));
cipher_ctx = EVP_CIPHER_CTX_new();
if (!cipher_ctx)
{
fprintf(stderr, "Out of memory\n");
return 1;
}
if (!EVP_CipherInit(cipher_ctx, cipher, k, i, encrypt))
{
fprintf(stderr, "Internal error\n");
EVP_CIPHER_CTX_free(cipher_ctx);
return 1;
}
bytes_read = fread(buffer, 1, sizeof(buffer), input);
while (bytes_read > 0)
{
int bytes_encrypted = sizeof(buffer);
if (!EVP_CipherUpdate(cipher_ctx, buffer, &bytes_encrypted, buffer, bytes_read))
{
fprintf(stderr, "Internal error\n");
EVP_CIPHER_CTX_free(cipher_ctx);
return 1;
}
if (bytes_encrypted != fwrite(buffer, 1, bytes_encrypted, output))
{
fprintf(stderr, "Write error\n");
EVP_CIPHER_CTX_free(cipher_ctx);
return 1;
}
bytes_read = fread(buffer, 1, sizeof(buffer), input);
}
if (feof(input))
{
int bytes_encrypted = sizeof(buffer);
if (!EVP_CipherFinal(cipher_ctx, buffer, &bytes_encrypted))
{
fprintf(stderr, "Internal error\n");
EVP_CIPHER_CTX_free(cipher_ctx);
return 1;
}
if (bytes_encrypted != fwrite(buffer, 1, bytes_encrypted, output))
{
fprintf(stderr, "Write error\n");
EVP_CIPHER_CTX_free(cipher_ctx);
return 1;
}
}
else
{
fprintf(stderr, "Read error\n");
EVP_CIPHER_CTX_free(cipher_ctx);
return 1;
}
EVP_CIPHER_CTX_free(cipher_ctx);
return 0;
}
int main(int argc, char* argv[])
{
int enc = -1, res = 1;
char *password = NULL, *input = NULL, *output = NULL;
char *key = NULL, *iv = NULL;
const EVP_CIPHER *cipher = NULL;
FILE *in = NULL, *out = NULL;
int i;
if (8 > argc)
{
fprintf(stderr, "Not enough arguments\n");
usage(stderr, argv[0]);
return 1;
}
OpenSSL_add_all_ciphers();
for (i = 1; i < argc; i++)
{
if (!strcmp(argv[i], "-e"))
{
if (-1 == enc)
enc = 1;
else
{
fprintf(stderr, "Invalid arguments\n");
usage(stderr, argv[0]);
return 1;
}
}
if (!strcmp(argv[i], "-d"))
{
if (-1 == enc)
enc = 0;
else
{
fprintf(stderr, "Invalid arguments\n");
usage(stderr, argv[0]);
return 1;
}
}
if (!strcmp(argv[i], "-c"))
{
if (argc > (i + 1))
{
if (argv[i + 1])
{
cipher = EVP_get_cipherbyname(argv[i + 1]);
if (!cipher)
{
fprintf(stderr, "Invalid arguments\n");
usage(stderr, argv[0]);
return 1;
}
}
}
}
if (!strcmp(argv[i], "-p"))
{
if (key)
{
fprintf(stderr, "Invalid arguments\n");
usage(stderr, argv[0]);
return 1;
}
if (argc > (i + 1))
{
if (argv[i + 1])
password = argv[i + 1];
}
}
if (!strcmp(argv[i], "-i"))
{
if (argc > (i + 1))
{
if (argv[i + 1])
input = argv[i + 1];
}
}
if (!strcmp(argv[i], "-o"))
{
if (argc > (i + 1))
{
if (argv[i + 1])
output = argv[i + 1];
}
}
if (!strcmp(argv[i], "-k"))
{
if (password)
{
fprintf(stderr, "Invalid arguments\n");
usage(stderr, argv[0]);
return 1;
}
if (argc > (i + 1))
{
if (argv[i + 1])
key = argv[i + 1];
}
}
if (!strcmp(argv[i], "-iv"))
{
if (argc > (i + 1))
{
if (argv[i + 1])
iv = argv[i + 1];
}
}
}
if ((-1 == enc) || (!input) || (!output) || ((!key) && (!password)))
{
fprintf(stderr, "Invalid arguments: %d %p %p %p %p\n", enc, input, output, key, password);
usage(stderr, argv[0]);
return 1;
}
if (!cipher)
{
cipher = EVP_get_cipherbyname(DEFAULT_CIPHER);
if (!cipher)
{
fprintf(stderr, "Default cipher not supported\n");
fprintf(stderr, "Try to use -c option\n");
return 1;
}
}
in = fopen(input, "rb");
if (!in)
{
fprintf(stderr, "Cannot open input file\n");
return 1;
}
out = fopen(output, "wb");
if (!out)
{
fprintf(stderr, "Cannot open output file\n");
fclose(in);
return 1;
}
res = process_file(in, out, password, key, iv, cipher, enc);
fclose(out);
fclose(in);
return res;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment