From fdc39509763f7d60429b903474916684da6653eb Mon Sep 17 00:00:00 2001 From: Mike Gabriel Date: Sun, 2 Nov 2014 20:44:45 +0100 Subject: Imported Upstream version 1.0.0 --- src/crypt.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 src/crypt.c (limited to 'src/crypt.c') diff --git a/src/crypt.c b/src/crypt.c new file mode 100644 index 0000000..21355d4 --- /dev/null +++ b/src/crypt.c @@ -0,0 +1,153 @@ +/* + * Copyright © 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + * + */ + +#include + +#include +#include + +#include "crypt.h" + +static gcry_cipher_hd_t +setup_cipher (const gchar * password) +{ + gcry_error_t gcryError; + gcry_cipher_hd_t gcryHandle; + + const size_t keyLength = gcry_cipher_get_algo_keylen(GCRY_CIPHER_AES); + const size_t blkLength = gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES); + + // We are assuming keyLength and blkLength are the same, check it + if (keyLength != blkLength) + return NULL; + + char * aesSymKey = malloc(blkLength); + const size_t passwordLength = strlen(password); + strncpy(aesSymKey, password, blkLength); + size_t i; + for (i = passwordLength; i < blkLength; ++i) + aesSymKey[i] = 0; + + gcryError = gcry_cipher_open(&gcryHandle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0); + if (gcryError) { + g_warning("gcry_cipher_open failed: %s/%s\n", gcry_strsource(gcryError), gcry_strerror(gcryError)); + return NULL; + } + + gcryError = gcry_cipher_setkey(gcryHandle, aesSymKey, keyLength); + if (gcryError) { + g_warning("gcry_cipher_setkey failed: %s/%s\n", gcry_strsource(gcryError), gcry_strerror(gcryError)); + gcry_cipher_close(gcryHandle); + return NULL; + } + + // Use the key as IV too + gcryError = gcry_cipher_setiv(gcryHandle, aesSymKey, blkLength); + if (gcryError) { + g_warning("gcry_cipher_setiv failed: %s/%s\n", gcry_strsource(gcryError), gcry_strerror(gcryError)); + gcry_cipher_close(gcryHandle); + return NULL; + } + + return gcryHandle; +} + +/** + * do_aes_encrypt: + * @origBuffer: text to encrypt. Needs to be null terminated + * @password: password to use. Will be cut/padded with 0 if it exceeds/does not reach the needed length + * @outBufferLength: (out) On success contains the length of the returned buffer + * + * Returns the AES encrypted version of the text. It is responsability of the caller to free it + */ +gchar * +do_aes_encrypt(const gchar *origBuffer, const gchar * password, size_t *outBufferLength) +{ + gcry_error_t gcryError; + gcry_cipher_hd_t gcryHandle; + + gcryHandle = setup_cipher (password); + if (gcryHandle == NULL) { + return NULL; + } + + const size_t blkLength = gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES); + const size_t origBufferLength = strlen(origBuffer); + const size_t bufferLength = ceil((double)origBufferLength / blkLength) * blkLength; + gchar *buffer = malloc(bufferLength); + memcpy(buffer, origBuffer, origBufferLength); + int i; + for (i = origBufferLength; i < bufferLength; ++i) + buffer[i] = 0; + + char * encBuffer = malloc(bufferLength); + size_t lengthDone = 0; + while (lengthDone < bufferLength) { + gcryError = gcry_cipher_encrypt(gcryHandle, &encBuffer[lengthDone], blkLength, &buffer[lengthDone], blkLength); + if (gcryError) { + g_warning("gcry_cipher_encrypt failed: %s/%s\n", gcry_strsource(gcryError), gcry_strerror(gcryError)); + gcry_cipher_close(gcryHandle); + free(encBuffer); + return NULL; + } + lengthDone += blkLength; + } + + gcry_cipher_close(gcryHandle); + + *outBufferLength = bufferLength; + return encBuffer; +} + +/** + * do_aes_encrypt: + * @encBuffer: encrypted data + * @password: password to use. Will be cut/padded with 0 if it exceeds/does not reach the needed length + * @encBufferLength: Length of encBuffer + * + * Returns the AES decrypted version of the data. It is null terminated. It is responsability of the caller to free it + */ +gchar * +do_aes_decrypt(const gchar *encBuffer, const gchar * password, const size_t encBufferLength) +{ + gcry_error_t gcryError; + gcry_cipher_hd_t gcryHandle; + + gcryHandle = setup_cipher (password); + if (gcryHandle == NULL) { + return NULL; + } + + const size_t blkLength = gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES128); + const size_t bufferLength = encBufferLength; + char * outBuffer = malloc(bufferLength); + size_t lengthDone = 0; + while (lengthDone < bufferLength) { + gcryError = gcry_cipher_decrypt(gcryHandle, &outBuffer[lengthDone], 16, &encBuffer[lengthDone], 16); + if (gcryError) + { + g_warning("gcry_cipher_decrypt failed: %s/%s\n", gcry_strsource(gcryError), gcry_strerror(gcryError)); + return NULL; + } + lengthDone += blkLength; + } + + gcry_cipher_close(gcryHandle); + char *result = g_strndup(outBuffer, bufferLength); + free(outBuffer); + return result; +} -- cgit v1.2.3