aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/aes/src/box.c
diff options
context:
space:
mode:
Diffstat (limited to 'aes/src/box.c')
-rw-r--r--aes/src/box.c683
1 files changed, 683 insertions, 0 deletions
diff --git a/aes/src/box.c b/aes/src/box.c
new file mode 100644
index 0000000..c7e1e90
--- /dev/null
+++ b/aes/src/box.c
@@ -0,0 +1,683 @@
+/*
+ * Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+ * This file is part of the "AES tools" project.
+ * For details, see https://github.com/egor-tensin/aes-tools.
+ * Distributed under the MIT License.
+ */
+
+#include <aes/all.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+static const AES_BoxAlgorithmInterface* aes_box_algorithms[] =
+{
+ &aes_box_algorithm_aes128,
+ &aes_box_algorithm_aes192,
+ &aes_box_algorithm_aes256,
+};
+
+AES_StatusCode aes_box_init(
+ AES_Box* box,
+ AES_Algorithm algorithm,
+ const AES_BoxKey* box_key,
+ AES_Mode mode,
+ const AES_BoxBlock* iv,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ box->algorithm = aes_box_algorithms[algorithm];
+
+ if (aes_is_error(status = box->algorithm->calc_round_keys(
+ box_key,
+ &box->encryption_keys,
+ &box->decryption_keys,
+ err_details)))
+ return status;
+
+ box->mode = mode;
+ if (iv != NULL)
+ box->iv = *iv;
+
+ return status;
+}
+
+static AES_StatusCode aes_box_encrypt_block_ecb(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ return box->algorithm->encrypt_block(
+ input, &box->encryption_keys, output, err_details);
+}
+
+static AES_StatusCode aes_box_encrypt_block_cbc(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+ AES_BoxBlock xored_input = *input;
+
+ if (aes_is_error(status = box->algorithm->xor_block(
+ &xored_input, &box->iv, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->encrypt_block(
+ &xored_input, &box->encryption_keys, output, err_details)))
+ return status;
+
+ box->iv = *output;
+ return status;
+}
+
+static AES_StatusCode aes_box_encrypt_block_cfb(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (aes_is_error(status = box->algorithm->encrypt_block(
+ &box->iv, &box->encryption_keys, output, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->xor_block(
+ output, input, err_details)))
+ return status;
+
+ box->iv = *output;
+ return status;
+}
+
+static AES_StatusCode aes_box_encrypt_block_ofb(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (aes_is_error(status = box->algorithm->encrypt_block(
+ &box->iv, &box->encryption_keys, &box->iv, err_details)))
+ return status;
+
+ *output = box->iv;
+
+ if (aes_is_error(status = box->algorithm->xor_block(
+ output, input, err_details)))
+ return status;
+
+ return status;
+}
+
+static AES_StatusCode aes_box_encrypt_block_ctr(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (aes_is_error(status = box->algorithm->encrypt_block(
+ &box->iv, &box->encryption_keys, output, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->xor_block(
+ output, input, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->inc_block(
+ &box->iv, err_details)))
+ return status;
+
+ return status;
+}
+
+typedef AES_StatusCode (*AES_BoxEncryptBlockInMode)(
+ AES_Box*,
+ const AES_BoxBlock*,
+ AES_BoxBlock*,
+ AES_ErrorDetails*);
+
+static AES_BoxEncryptBlockInMode aes_box_encrypt_block_in_mode[] =
+{
+ &aes_box_encrypt_block_ecb,
+ &aes_box_encrypt_block_cbc,
+ &aes_box_encrypt_block_cfb,
+ &aes_box_encrypt_block_ofb,
+ &aes_box_encrypt_block_ctr,
+};
+
+AES_StatusCode aes_box_encrypt_block(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ return aes_box_encrypt_block_in_mode[box->mode](
+ box, input, output, err_details);
+}
+
+static AES_StatusCode aes_box_decrypt_block_ecb(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ return box->algorithm->decrypt_block(
+ input, &box->decryption_keys, output, err_details);
+}
+
+static AES_StatusCode aes_box_decrypt_block_cbc(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (aes_is_error(status = box->algorithm->decrypt_block(
+ input, &box->decryption_keys, output, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->xor_block(
+ output, &box->iv, err_details)))
+ return status;
+
+ box->iv = *input;
+ return status;
+}
+
+static AES_StatusCode aes_box_decrypt_block_cfb(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (aes_is_error(status = box->algorithm->encrypt_block(
+ &box->iv, &box->encryption_keys, output, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->xor_block(
+ output, input, err_details)))
+ return status;
+
+ box->iv = *input;
+ return status;
+}
+
+typedef AES_BoxEncryptBlockInMode AES_BoxDecryptBlockInMode;
+
+static AES_BoxDecryptBlockInMode aes_box_decrypt_block_in_mode[] =
+{
+ &aes_box_decrypt_block_ecb,
+ &aes_box_decrypt_block_cbc,
+ &aes_box_decrypt_block_cfb,
+ &aes_box_encrypt_block_ofb,
+ &aes_box_encrypt_block_ctr,
+};
+
+AES_StatusCode aes_box_decrypt_block(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ return aes_box_decrypt_block_in_mode[box->mode](
+ box, input, output, err_details);
+}
+
+static AES_StatusCode aes_box_get_encrypted_buffer_size(
+ AES_Box* box,
+ size_t src_size,
+ size_t* dest_size,
+ size_t* padding_size,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ switch (box->mode)
+ {
+ case AES_ECB:
+ case AES_CBC:
+ {
+ size_t block_size;
+
+ if (aes_is_error(status = box->algorithm->get_block_size(
+ &block_size, err_details)))
+ return status;
+
+ *padding_size = block_size - src_size % block_size;
+ *dest_size = src_size + *padding_size;
+ return status;
+ }
+
+ case AES_CFB:
+ case AES_OFB:
+ case AES_CTR:
+ *dest_size = src_size;
+ *padding_size = 0;
+ return status;
+
+ default:
+ return aes_error_not_implemented(
+ err_details, "unsupported mode of operation");
+ }
+}
+
+static AES_StatusCode aes_box_encrypt_buffer_block(
+ AES_Box* box,
+ const void* src,
+ void* dest,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ AES_BoxBlock plaintext;
+
+ if (aes_is_error(status = box->algorithm->load_block(
+ &plaintext, src, err_details)))
+ return status;
+
+ AES_BoxBlock ciphertext;
+
+ if (aes_is_error(status = aes_box_encrypt_block(
+ box, &plaintext, &ciphertext, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->store_block(
+ dest, &ciphertext, err_details)))
+ return status;
+
+ return status;
+}
+
+static AES_StatusCode aes_box_encrypt_buffer_partial_block_with_padding(
+ AES_Box* box,
+ const void* src,
+ size_t src_size,
+ void* dest,
+ size_t padding_size,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ size_t block_size;
+
+ if (aes_is_error(status = box->algorithm->get_block_size(
+ &block_size, err_details)))
+ return status;
+
+ void* plaintext_buf = malloc(block_size);
+
+ if (plaintext_buf == NULL)
+ return status = aes_error_memory_allocation(err_details);
+
+ memcpy(plaintext_buf, src, src_size);
+
+ if (aes_is_error(status = aes_fill_with_padding(
+ AES_PADDING_PKCS7,
+ (char*) plaintext_buf + src_size,
+ padding_size,
+ err_details)))
+ goto FREE_PLAINTEXT_BUF;
+
+ if (aes_is_error(status = aes_box_encrypt_buffer_block(
+ box, plaintext_buf, dest, err_details)))
+ goto FREE_PLAINTEXT_BUF;
+
+FREE_PLAINTEXT_BUF:
+ free(plaintext_buf);
+
+ return status;
+}
+
+static AES_StatusCode aes_box_encrypt_buffer_partial_block(
+ AES_Box* box,
+ const void* src,
+ size_t src_size,
+ void* dest,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (src_size == 0)
+ return status;
+
+ size_t block_size;
+
+ if (aes_is_error(status = box->algorithm->get_block_size(
+ &block_size, err_details)))
+ return status;
+
+ void* plaintext_buf = malloc(block_size);
+
+ if (plaintext_buf == NULL)
+ return status = aes_error_memory_allocation(err_details);
+
+ memset(plaintext_buf, 0x00, block_size);
+ memcpy(plaintext_buf, src, src_size);
+
+ void* ciphertext_buf = malloc(block_size);
+
+ if (ciphertext_buf == NULL)
+ {
+ status = aes_error_memory_allocation(err_details);
+ goto FREE_PLAINTEXT_BUF;
+ }
+
+ if (aes_is_error(status = aes_box_encrypt_buffer_block(
+ box, plaintext_buf, ciphertext_buf, err_details)))
+ goto FREE_CIPHERTEXT_BUF;
+
+ memcpy(dest, ciphertext_buf, src_size);
+
+FREE_CIPHERTEXT_BUF:
+ free(ciphertext_buf);
+
+FREE_PLAINTEXT_BUF:
+ free(plaintext_buf);
+
+ return status;
+}
+
+AES_StatusCode aes_box_encrypt_buffer(
+ AES_Box* box,
+ const void* src,
+ size_t src_size,
+ void* dest,
+ size_t* dest_size,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (box == NULL)
+ return aes_error_null_argument(err_details, "box");
+ if (dest_size == NULL)
+ return aes_error_null_argument(err_details, "dest_size");
+
+ size_t padding_size = 0;
+
+ if (aes_is_error(status = aes_box_get_encrypted_buffer_size(
+ box, src_size, dest_size, &padding_size, err_details)))
+ return status;
+
+ if (dest == NULL)
+ return AES_SUCCESS;
+ if (src == NULL && src_size != 0)
+ return aes_error_null_argument(err_details, "src");
+
+ size_t block_size;
+
+ if (aes_is_error(status = box->algorithm->get_block_size(
+ &block_size, err_details)))
+ return status;
+
+ const size_t src_len = src_size / block_size;
+
+ for (size_t i = 0; i < src_len; ++i)
+ {
+ if (aes_is_error(status = aes_box_encrypt_buffer_block(
+ box, src, dest, err_details)))
+ return status;
+
+ src = (char*) src + block_size;
+ dest = (char*) dest + block_size;
+ }
+
+ if (padding_size == 0)
+ return aes_box_encrypt_buffer_partial_block(
+ box, src, src_size % block_size, dest, err_details);
+ else
+ return aes_box_encrypt_buffer_partial_block_with_padding(
+ box, src, src_size % block_size, dest, padding_size, err_details);
+}
+
+static AES_StatusCode aes_box_get_decrypted_buffer_size(
+ AES_Box* box,
+ size_t src_size,
+ size_t* dest_size,
+ size_t* max_padding_size,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ switch (box->mode)
+ {
+ case AES_ECB:
+ case AES_CBC:
+ {
+ size_t block_size;
+
+ if (aes_is_error(status = box->algorithm->get_block_size(
+ &block_size, err_details)))
+ return status;
+
+ if (src_size == 0 || src_size % block_size != 0)
+ return aes_error_missing_padding(err_details);
+
+ *dest_size = src_size;
+ *max_padding_size = block_size;
+ return status;
+ }
+
+ case AES_CFB:
+ case AES_OFB:
+ case AES_CTR:
+ *dest_size = src_size;
+ *max_padding_size = 0;
+ return status;
+
+ default:
+ return aes_error_not_implemented(
+ err_details, "unsupported mode of operation");
+ }
+}
+
+static AES_StatusCode aes_box_decrypt_buffer_block(
+ AES_Box* box,
+ const void* src,
+ void* dest,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ AES_BoxBlock ciphertext;
+
+ if (aes_is_error(status = box->algorithm->load_block(
+ &ciphertext, src, err_details)))
+ return status;
+
+ AES_BoxBlock plaintext;
+
+ if (aes_is_error(status = aes_box_decrypt_block(
+ box, &ciphertext, &plaintext, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->store_block(
+ dest, &plaintext, err_details)))
+ return status;
+
+ return status;
+}
+
+static AES_StatusCode aes_box_decrypt_buffer_partial_block(
+ AES_Box* box,
+ const void* src,
+ size_t src_size,
+ void* dest,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (src_size == 0)
+ return status;
+
+ size_t block_size;
+
+ if (aes_is_error(status = box->algorithm->get_block_size(
+ &block_size, err_details)))
+ return status;
+
+ void* ciphertext_buf = malloc(block_size);
+
+ if (ciphertext_buf == NULL)
+ return status = aes_error_memory_allocation(err_details);
+
+ memset(ciphertext_buf, 0x00, block_size);
+ memcpy(ciphertext_buf, src, src_size);
+
+ void* plaintext_buf = malloc(block_size);
+
+ if (plaintext_buf == NULL)
+ {
+ status = aes_error_memory_allocation(err_details);
+ goto FREE_CIPHERTEXT_BUF;
+ }
+
+ if (aes_is_error(status = aes_box_decrypt_buffer_block(
+ box, ciphertext_buf, plaintext_buf, err_details)))
+ goto FREE_PLAINTEXT_BUF;
+
+ memcpy(dest, plaintext_buf, src_size);
+
+FREE_PLAINTEXT_BUF:
+ free(plaintext_buf);
+
+FREE_CIPHERTEXT_BUF:
+ free(ciphertext_buf);
+
+ return status;
+}
+
+AES_StatusCode aes_box_decrypt_buffer(
+ AES_Box* box,
+ const void* src,
+ size_t src_size,
+ void* dest,
+ size_t* dest_size,
+ AES_ErrorDetails* err_details)
+{
+ if (box == NULL)
+ return aes_error_null_argument(err_details, "box");
+ if (dest_size == NULL)
+ return aes_error_null_argument(err_details, "dest_size");
+
+ AES_StatusCode status = AES_SUCCESS;
+ size_t max_padding_size = 0;
+
+ if (aes_is_error(status = aes_box_get_decrypted_buffer_size(
+ box, src_size, dest_size, &max_padding_size, err_details)))
+ return status;
+
+ if (dest == NULL)
+ return AES_SUCCESS;
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ size_t block_size;
+
+ if (aes_is_error(status = box->algorithm->get_block_size(
+ &block_size, err_details)))
+ return status;
+
+ const size_t src_len = src_size / block_size;
+
+ for (size_t i = 0; i < src_len; ++i)
+ {
+ if (aes_is_error(status = aes_box_decrypt_buffer_block(
+ box, src, dest, err_details)))
+ return status;
+
+ src = (char*) src + block_size;
+ dest = (char*) dest + block_size;
+ }
+
+ if (max_padding_size == 0)
+ {
+ return aes_box_decrypt_buffer_partial_block(
+ box, src, src_size % block_size, dest, err_details);
+ }
+ else
+ {
+ size_t padding_size;
+
+ if (aes_is_error(status = aes_extract_padding_size(
+ AES_PADDING_PKCS7,
+ (char*) dest - block_size,
+ block_size,
+ &padding_size,
+ err_details)))
+ return status;
+
+ *dest_size -= padding_size;
+ return status;
+ }
+}
+
+AES_StatusCode aes_box_parse_block(
+ AES_BoxBlock* dest,
+ AES_Algorithm algorithm,
+ const char* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ return aes_box_algorithms[algorithm]->parse_block(
+ dest, src, err_details);
+}
+
+AES_StatusCode aes_box_parse_key(
+ AES_BoxKey* dest,
+ AES_Algorithm algorithm,
+ const char* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ return aes_box_algorithms[algorithm]->parse_key(
+ dest, src, err_details);
+}
+
+AES_StatusCode aes_box_format_block(
+ AES_BoxBlockString* dest,
+ AES_Algorithm algorithm,
+ const AES_BoxBlock* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ return aes_box_algorithms[algorithm]->format_block(
+ dest, src, err_details);
+}
+
+AES_StatusCode aes_box_format_key(
+ AES_BoxKeyString* dest,
+ AES_Algorithm algorithm,
+ const AES_BoxKey* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ return aes_box_algorithms[algorithm]->format_key(
+ dest, src, err_details);
+}