file/file_encrypt/decrypt.c

/*******************************************************************************
* # License
* Copyright 2019 Silicon Laboratories Inc. www.silabs.com
*******************************************************************************
*
* The licensor of this software is Silicon Laboratories Inc. Your use of this
* software is governed by the terms of Silicon Labs Master Software License
* Agreement (MSLA) available at
* www.silabs.com/about-us/legal/master-software-license-agreement. This
* software is distributed to you in Source Code format and is governed by the
* sections of the MSLA applicable to Source Code.
*
******************************************************************************/
#include "crypto.h"
/*************************************************************************************************/
gos_result_t decrypt_file_to_buffer(const uint8_t *key, const char *filename, uint8_t *buffer, uint32_t buffer_length)
{
gos_handle_t handle;
gos_result_t result;
uint8_t mac[MAC_SIZE], calculated_mac[MAC_SIZE];
gos_file_t file_info;
crypt_context_t context;
int32_t remaining_bytes;
// Open the encrypted file
if (GOS_FAILED(result, gos_file_open(filename, GOS_FILE_LOCATION_ANY, false, &handle)))
{
GOS_LOG("Failed to open encrypted file: %s", filename);
goto exit;
}
// Retrieve the file's info
else if (GOS_FAILED(result, gos_file_stat(filename, GOS_FILE_LOCATION_ANY, &file_info, NULL)))
{
GOS_LOG("Failed to get file info: %d", result);
goto exit;
}
else if (file_info.size <= AES128_BLOCK_SIZE*2)
{
GOS_LOG("Encrypted file not long enough, must be at least 33 bytes: %d", result);
goto exit;
}
else if (buffer_length < (file_info.size - AES128_BLOCK_SIZE*2))
{
GOS_LOG("Supplied buffer not large enough to hold decrypted data", result);
goto exit;
}
// Initialize the AES context with the supplied key
gos_aes_setkey_enc(&context.aes, key, AES128_BLOCK_BITS);
// Read the IV
if (GOS_FAILED(result, gos_file_read(handle, context.iv.buf, IV_SIZE, NULL)))
{
GOS_LOG("Failed to read IV: %d", result);
goto exit;
}
gos_dump_buffer(context.iv.buf, IV_SIZE, "IV", GOS_DUMP_FLAGS(16, 1, LITTLE, ADD_SPACE, NO_ADDRESSES, NO_ASCII ));
// The next 16 bytes of the file is the MAC
// Read the encrypted MAC into the buffer
if (GOS_FAILED(result, gos_file_read(handle, mac, MAC_SIZE, NULL)))
{
GOS_LOG("Failed to read encrypted MAC: %d", result);
goto exit;
}
// Decrypt the MAC
decrypt_block(&context, mac);
gos_dump_buffer(mac, MAC_SIZE, "MAC", GOS_DUMP_FLAGS(16, 1, LITTLE, ADD_SPACE, NO_ADDRESSES, NO_ASCII ));
// Read the rest of the file into the buffer
if (GOS_FAILED(result, gos_file_read(handle, buffer, file_info.size, NULL)))
{
GOS_LOG("Failed to read encrypted file data into buffer: %d", result);
goto exit;
}
// Decrypt the buffer AES128_BLOCK_SIZE bytes at a time
uint8_t *buffer_ptr = buffer;
// Start with entire file
remaining_bytes = file_info.size;
while (remaining_bytes > 0)
{
// NOTE: We don't want to overflow the decryption buffer as this will make the final MAC calculation incorrect
if (remaining_bytes >= AES128_BLOCK_SIZE)
{
decrypt_block(&context, buffer_ptr);
}
else
{
decrypt_buffer(&context, buffer_ptr, remaining_bytes);
}
remaining_bytes -= AES128_BLOCK_SIZE;
buffer_ptr += AES128_BLOCK_SIZE;
}
// Calculate the MAC of the *decrypted* data
calculate_mac(key, buffer, buffer_length, calculated_mac);
if (memcmp(mac, calculated_mac, AES128_BLOCK_SIZE) != 0)
{
GOS_LOG("Failed to verify MAC");
gos_dump_buffer(calculated_mac, AES128_BLOCK_SIZE, "Calculated MAC", GOS_DUMP_FLAGS(16, 1, LITTLE, ADD_SPACE, NO_ADDRESSES, NO_ASCII ));
result = GOS_DECRYPT_ERR;
}
exit:
return result;
}