aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/box.c294
-rw-r--r--src/box_aes.c72
-rw-r--r--src/error.c8
3 files changed, 374 insertions, 0 deletions
diff --git a/src/box.c b/src/box.c
index 6d0f5d2..75d471d 100644
--- a/src/box.c
+++ b/src/box.c
@@ -8,6 +8,8 @@
#include <aesni/all.h>
+#include <stdlib.h>
+
static const AesNI_BoxAlgorithmInterface* aesni_box_algorithms[] =
{
&aesni_box_algorithm_aes128,
@@ -253,3 +255,295 @@ AesNI_StatusCode aesni_box_decrypt_block(
{
return aesni_box_decrypt_block_in_mode[box->mode](box, input, output, err_details);
}
+
+static AesNI_StatusCode aesni_box_get_encrypted_buffer_size(
+ AesNI_Box* box,
+ size_t src_size,
+ size_t* dest_size,
+ size_t* padding_size,
+ AesNI_ErrorDetails* err_details)
+{
+ AesNI_StatusCode status = AESNI_SUCCESS;
+
+ switch (box->mode)
+ {
+ case AESNI_ECB:
+ case AESNI_CBC:
+ {
+ size_t block_size;
+
+ if (aesni_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 AESNI_CFB:
+ case AESNI_OFB:
+ case AESNI_CTR:
+ *dest_size = src_size;
+ *padding_size = 0;
+ return status;
+
+ default:
+ return aesni_error_not_implemented(err_details, "unsupported mode of operation");
+ }
+}
+
+static AesNI_StatusCode aesni_box_encrypt_buffer_block(
+ AesNI_Box* box,
+ const void* src,
+ void* dest,
+ AesNI_ErrorDetails* err_details)
+{
+ AesNI_StatusCode status = AESNI_SUCCESS;
+
+ AesNI_BoxBlock plaintext;
+
+ if (aesni_is_error(status = box->algorithm->load_block(
+ &plaintext, src, err_details)))
+ return status;
+
+ AesNI_BoxBlock ciphertext;
+
+ if (aesni_is_error(status = aesni_box_encrypt_block(
+ box, &plaintext, &ciphertext, err_details)))
+ return status;
+
+ if (aesni_is_error(status = box->algorithm->store_block(
+ dest, &ciphertext, err_details)))
+ return status;
+
+ return status;
+}
+
+AesNI_StatusCode aesni_box_encrypt_buffer(
+ AesNI_Box* box,
+ const void* src,
+ size_t src_size,
+ void* dest,
+ size_t* dest_size,
+ AesNI_ErrorDetails* err_details)
+{
+ if (box == NULL)
+ return aesni_error_null_argument(err_details, "box");
+ if (dest_size == NULL)
+ return aesni_error_null_argument(err_details, "dest_size");
+
+ AesNI_StatusCode status = AESNI_SUCCESS;
+ size_t padding_size = 0;
+
+ if (aesni_is_error(status = aesni_box_get_encrypted_buffer_size(
+ box, src_size, dest_size, &padding_size, err_details)))
+ return status;
+
+ if (dest == NULL)
+ return AESNI_SUCCESS;
+ if (src == NULL)
+ return aesni_error_null_argument(err_details, "src");
+
+ size_t block_size;
+
+ if (aesni_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, (char*) src += block_size, (char*) dest += block_size)
+ if (aesni_is_error(status = aesni_box_encrypt_buffer_block(
+ box, src, dest, err_details)))
+ return status;
+
+ if (padding_size == 0)
+ {
+ const size_t partial_block_size = src_size % block_size;
+
+ if (partial_block_size != 0)
+ {
+ AesNI_BoxBlock plaintext;
+
+ if (aesni_is_error(status = box->algorithm->load_partial_block(
+ &plaintext, src, partial_block_size, err_details)))
+ return status;
+
+ AesNI_BoxBlock ciphertext;
+
+ if (aesni_is_error(status = aesni_box_encrypt_block(
+ box, &plaintext, &ciphertext, err_details)))
+ return status;
+
+ if (aesni_is_error(status = box->algorithm->store_partial_block(
+ dest, &ciphertext, partial_block_size, err_details)))
+ return status;
+ }
+ }
+ else
+ {
+ AesNI_BoxBlock plaintext;
+
+ if (aesni_is_error(status = box->algorithm->load_block_with_padding(
+ &plaintext, src, src_size % block_size, err_details)))
+ return status;
+
+ AesNI_BoxBlock ciphertext;
+
+ if (aesni_is_error(status = aesni_box_encrypt_block(
+ box, &plaintext, &ciphertext, err_details)))
+ return status;
+
+ if (aesni_is_error(status = box->algorithm->store_block(
+ dest, &ciphertext, err_details)))
+ return status;
+ }
+
+ return status;
+}
+
+static AesNI_StatusCode aesni_box_get_decrypted_buffer_size(
+ AesNI_Box* box,
+ size_t src_size,
+ size_t* dest_size,
+ size_t* max_padding_size,
+ AesNI_ErrorDetails* err_details)
+{
+ AesNI_StatusCode status = AESNI_SUCCESS;
+
+ switch (box->mode)
+ {
+ case AESNI_ECB:
+ case AESNI_CBC:
+ {
+ size_t block_size;
+
+ if (aesni_is_error(status = box->algorithm->get_block_size(
+ &block_size, err_details)))
+ return status;
+
+ if (src_size % block_size != 0)
+ return aesni_error_invalid_plaintext_length(err_details);
+
+ *dest_size = src_size;
+ *max_padding_size = block_size;
+ return status;
+ }
+
+ case AESNI_CFB:
+ case AESNI_OFB:
+ case AESNI_CTR:
+ *dest_size = src_size;
+ *max_padding_size = 0;
+ return status;
+
+ default:
+ return aesni_error_not_implemented(err_details, "unsupported mode of operation");
+ }
+}
+
+static AesNI_StatusCode aesni_box_decrypt_buffer_block(
+ AesNI_Box* box,
+ const void* src,
+ void* dest,
+ AesNI_ErrorDetails* err_details)
+{
+ AesNI_StatusCode status = AESNI_SUCCESS;
+
+ AesNI_BoxBlock ciphertext;
+
+ if (aesni_is_error(status = box->algorithm->load_block(
+ &ciphertext, src, err_details)))
+ return status;
+
+ AesNI_BoxBlock plaintext;
+
+ if (aesni_is_error(status = aesni_box_decrypt_block(
+ box, &ciphertext, &plaintext, err_details)))
+ return status;
+
+ if (aesni_is_error(status = box->algorithm->store_block(
+ dest, &plaintext, err_details)))
+ return status;
+
+ return status;
+}
+
+AesNI_StatusCode aesni_box_decrypt_buffer(
+ AesNI_Box* box,
+ const void* src,
+ size_t src_size,
+ void* dest,
+ size_t* dest_size,
+ AesNI_ErrorDetails* err_details)
+{
+ if (box == NULL)
+ return aesni_error_null_argument(err_details, "box");
+ if (dest_size == NULL)
+ return aesni_error_null_argument(err_details, "dest_size");
+
+ AesNI_StatusCode status = AESNI_SUCCESS;
+ size_t padding_size = 0;
+
+ if (aesni_is_error(status = aesni_box_get_decrypted_buffer_size(
+ box, src_size, dest_size, &padding_size, err_details)))
+ return status;
+
+ if (dest == NULL)
+ return AESNI_SUCCESS;
+ if (src == NULL)
+ return aesni_error_null_argument(err_details, "src");
+
+ size_t block_size;
+
+ if (aesni_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, (char*) src += block_size, (char*) dest += block_size)
+ if (aesni_is_error(status = aesni_box_decrypt_buffer_block(
+ box, src, dest, err_details)))
+ return status;
+
+ if (padding_size == 0)
+ {
+ const size_t partial_block_size = src_size % block_size;
+
+ if (partial_block_size != 0)
+ {
+ AesNI_BoxBlock ciphertext;
+
+ if (aesni_is_error(status = box->algorithm->load_partial_block(
+ &ciphertext, src, partial_block_size, err_details)))
+ return status;
+
+ AesNI_BoxBlock plaintext;
+
+ if (aesni_is_error(status = aesni_box_decrypt_block(
+ box, &ciphertext, &plaintext, err_details)))
+ return status;
+
+ if (aesni_is_error(status = box->algorithm->store_partial_block(
+ dest, &plaintext, partial_block_size, err_details)))
+ return status;
+ }
+ }
+ else
+ {
+ padding_size = ((unsigned char*) dest)[-1];
+
+ if (padding_size > block_size)
+ return aesni_error_invalid_pkcs7_padding(err_details);
+
+ for (size_t i = 1; i < padding_size; ++i)
+ if (((unsigned char*) dest)[0 - i] != padding_size)
+ return aesni_error_invalid_pkcs7_padding(err_details);
+
+ *dest_size -= padding_size;
+ }
+
+ return status;
+}
diff --git a/src/box_aes.c b/src/box_aes.c
index 12f369d..49c5326 100644
--- a/src/box_aes.c
+++ b/src/box_aes.c
@@ -9,6 +9,7 @@
#include <aesni/all.h>
#include <stdlib.h>
+#include <string.h>
static AesNI_StatusCode aesni_box_derive_params_aes128(
const AesNI_BoxAlgorithmParams* algorithm_params,
@@ -82,6 +83,62 @@ static AesNI_StatusCode aesni_box_get_block_size_aes(
return AESNI_SUCCESS;
}
+static AesNI_StatusCode aesni_box_store_block_aes(
+ void* dest,
+ const AesNI_BoxBlock* src,
+ AesNI_ErrorDetails* err_details)
+{
+ aesni_store_block128(dest, src->aes_block);
+ return AESNI_SUCCESS;
+}
+
+static AesNI_StatusCode aesni_box_store_partial_block_aes(
+ void* dest,
+ const AesNI_BoxBlock* src,
+ size_t src_size,
+ AesNI_ErrorDetails* err_details)
+{
+ __declspec(align(16)) unsigned char buf[16];
+ aesni_store_block128(buf, src->aes_block);
+ memcpy(dest, buf, src_size);
+ return AESNI_SUCCESS;
+}
+
+static AesNI_StatusCode aesni_box_load_block_aes(
+ AesNI_BoxBlock* dest,
+ const void* src,
+ AesNI_ErrorDetails* err_details)
+{
+ dest->aes_block = aesni_load_block128(src);
+ return AESNI_SUCCESS;
+}
+
+static AesNI_StatusCode aesni_box_load_partial_block_aes(
+ AesNI_BoxBlock* dest,
+ const void* src,
+ size_t src_size,
+ AesNI_ErrorDetails* err_details)
+{
+ __declspec(align(16)) unsigned char buf[16];
+ memset(buf, 0x00, 16);
+ memcpy(buf, src, src_size);
+ dest->aes_block = aesni_load_block128_aligned(buf);
+ return AESNI_SUCCESS;
+}
+
+static AesNI_StatusCode aesni_box_load_block_with_padding_aes(
+ AesNI_BoxBlock* dest,
+ const void* src,
+ size_t src_size,
+ AesNI_ErrorDetails* err_details)
+{
+ __declspec(align(16)) unsigned char padding[16];
+ memset(padding + src_size, 16 - src_size, 16 - src_size);
+ memcpy(padding, src, src_size);
+ dest->aes_block = aesni_load_block128_aligned(padding);
+ return AESNI_SUCCESS;
+}
+
static AesNI_StatusCode aesni_box_encrypt_block_aes128(
const AesNI_BoxBlock* input,
const AesNI_BoxEncryptionParams* params,
@@ -162,6 +219,11 @@ AesNI_BoxAlgorithmInterface aesni_box_algorithm_aes128 =
&aesni_box_xor_block_aes,
&aesni_box_next_counter_aes,
&aesni_box_get_block_size_aes,
+ &aesni_box_store_block_aes,
+ &aesni_box_store_partial_block_aes,
+ &aesni_box_load_block_aes,
+ &aesni_box_load_partial_block_aes,
+ &aesni_box_load_block_with_padding_aes,
};
AesNI_BoxAlgorithmInterface aesni_box_algorithm_aes192 =
@@ -172,6 +234,11 @@ AesNI_BoxAlgorithmInterface aesni_box_algorithm_aes192 =
&aesni_box_xor_block_aes,
&aesni_box_next_counter_aes,
&aesni_box_get_block_size_aes,
+ &aesni_box_store_block_aes,
+ &aesni_box_store_partial_block_aes,
+ &aesni_box_load_block_aes,
+ &aesni_box_load_partial_block_aes,
+ &aesni_box_load_block_with_padding_aes,
};
AesNI_BoxAlgorithmInterface aesni_box_algorithm_aes256 =
@@ -182,4 +249,9 @@ AesNI_BoxAlgorithmInterface aesni_box_algorithm_aes256 =
&aesni_box_xor_block_aes,
&aesni_box_next_counter_aes,
&aesni_box_get_block_size_aes,
+ &aesni_box_store_block_aes,
+ &aesni_box_store_partial_block_aes,
+ &aesni_box_load_block_aes,
+ &aesni_box_load_partial_block_aes,
+ &aesni_box_load_block_with_padding_aes,
};
diff --git a/src/error.c b/src/error.c
index bf35668..fd9136a 100644
--- a/src/error.c
+++ b/src/error.c
@@ -26,6 +26,7 @@ static const char* aesni_strerror_messages[] =
"Couldn't parse",
"Invalid PKCS7 padding (wrong key?)",
"Not implemented",
+ "Invalid plaintext length",
};
const char* aesni_strerror(AesNI_StatusCode ec)
@@ -103,6 +104,7 @@ static AesNI_ErrorFormatter err_formatters[] =
&aesni_format_parse_error,
&aesni_format_error_strerror,
&aesni_format_not_implemented_error,
+ &aesni_format_error_strerror,
};
size_t aesni_format_error(
@@ -201,3 +203,9 @@ AesNI_StatusCode aesni_error_not_implemented(
return status;
}
+
+AesNI_StatusCode aesni_error_invalid_plaintext_length(
+ AesNI_ErrorDetails* err_details)
+{
+ return aesni_make_error(err_details, AESNI_INVALID_PLAINTEXT_LENGTH_ERROR);
+}