Skip to content

Commit

Permalink
file encryption/decryption support
Browse files Browse the repository at this point in the history
  • Loading branch information
an4tur0r committed Nov 11, 2022
1 parent 1d196b4 commit 3f2892b
Show file tree
Hide file tree
Showing 9 changed files with 297 additions and 1 deletion.
29 changes: 29 additions & 0 deletions applications/debug/unit_tests/storage/storage_test.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "../minunit.h"
#include <furi.h>
#include <storage/storage.h>
#include <toolbox/stream/file_stream.h>

#define STORAGE_LOCKED_FILE EXT_PATH("locked_file.test")
#define STORAGE_LOCKED_DIR STORAGE_INT_PATH_PREFIX
Expand Down Expand Up @@ -309,9 +310,37 @@ MU_TEST_SUITE(storage_rename) {
furi_record_close(RECORD_STORAGE);
}

MU_TEST(storage_encrypt_file) {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file;
const char* path = EXT_PATH("enc_file");
const uint8_t key_slot = 0;

file = storage_file_alloc(storage);
mu_check(storage_file_open(file, path, FSAM_READ_WRITE, FSOM_CREATE_ALWAYS));

const char* content = "Lorem ipsum dolor sit amet, cons";
mu_check(storage_file_write(file, content, 32) == 32);
storage_file_free(file);

mu_assert_int_eq(FSE_OK, storage_file_encrypt(storage, path, key_slot));
mu_check(storage_file_is_encrypted(storage, path));

furi_record_close(RECORD_STORAGE);
}

MU_TEST_SUITE(storage_encrypt_decrypt) {
MU_RUN_TEST(storage_encrypt_file);

Storage* storage = furi_record_open(RECORD_STORAGE);
storage_dir_remove(storage, EXT_PATH("enc_file"));
furi_record_close(RECORD_STORAGE);
}

int run_minunit_test_storage() {
MU_RUN_SUITE(storage_file);
MU_RUN_SUITE(storage_dir);
MU_RUN_SUITE(storage_rename);
MU_RUN_SUITE(storage_encrypt_decrypt);
return MU_EXIT_CODE;
}
3 changes: 3 additions & 0 deletions applications/services/storage/filesystem_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ const char* filesystem_api_error_get_desc(FS_Error error_id) {
case(FSE_ALREADY_OPEN):
result = "file is already open";
break;
case(FSE_NO_SPACE):
result = "no free space";
break;
}
return result;
}
1 change: 1 addition & 0 deletions applications/services/storage/filesystem_api_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ typedef enum {
FSE_INTERNAL, /**< Internal error */
FSE_NOT_IMPLEMENTED, /**< Functon not implemented */
FSE_ALREADY_OPEN, /**< File/Dir already opened */
FSE_NO_SPACE, /**< No free space available */
} FS_Error;

/** FileInfo flags */
Expand Down
23 changes: 23 additions & 0 deletions applications/services/storage/filesystem_api_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,27 @@
extern "C" {
#endif

#define ENCRYPTION_IV_SIZE 16
#define ENCRYPTION_EXT ".enc"

/** Magic bytes to detect if file is encrypted.
* Encrypted file bytes layout is as follows:
* --------------- ----------------- ---------------- -----------------------
* | 7 bytes magic | 1 byte key slot | 16 byte vector | actual encrypted data |
* --------------- ----------------- ---------------- -----------------------
*/
static const uint8_t encryption_magic_bytes[7] = {0x46, 0x45, 0x46, 0x2e, 0x41, 0x45, 0x53};
static const size_t encryption_magic_size =
sizeof(encryption_magic_bytes) / sizeof(encryption_magic_bytes[0]);
static const size_t encryption_header_size =
encryption_magic_size + sizeof(uint8_t) + ENCRYPTION_IV_SIZE;

/** Structure that holds file encryption info */
typedef struct FileEncryption {
bool decrypted; /**< Current encryption state */
uint8_t key_slot; /**< Slot number of encryption key */
} FileEncryption;

/** File type */
typedef enum {
FileTypeClosed, /**< Closed file */
Expand All @@ -17,9 +38,11 @@ typedef enum {
struct File {
uint32_t file_id; /**< File ID for internal references */
FileType type;
const char* path; /**< Actual path of opened file */
FS_Error error_id; /**< Standart API error from FS_Error enum */
int32_t internal_error_id; /**< Internal API error value */
void* storage;
FileEncryption* encryption;
};

/** File api structure
Expand Down
33 changes: 33 additions & 0 deletions applications/services/storage/storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,39 @@ bool storage_file_sync(File* file);
*/
bool storage_file_eof(File* file);

/** Checks that file at given path is encrypted
* @param storage
* @param path path to file.
* @return bool success flag
*/
bool storage_file_is_encrypted(Storage* storage, const char* path);

/** Checks that file is decrypted at the moment
* @param file pointer to file object.
* @return bool success flag
*/
bool storage_file_is_decrypted(File* file);

/** Reports if encryption is enabled for this file
* @param file pointer to file object.
* @return bool success flag
*/
bool storage_file_secured(File* file);

/** Decrypts previously encrypted file
* @param file pointer to file object.
* @return FS_Error operation result
*/
FS_Error storage_file_decrypt(File* file);

/** Encrypts file using key from given secure enclave slot
* @param storage
* @param path path to file.
* @param key_slot slot of key in secure enclave.
* @return FS_Error operation result
*/
FS_Error storage_file_encrypt(Storage* storage, const char* path, uint8_t key_slot);

/**
* @brief Check that file exists
*
Expand Down
44 changes: 44 additions & 0 deletions applications/services/storage/storage_external_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,29 @@ bool storage_file_exists(Storage* storage, const char* path) {
return exist;
}

FS_Error storage_file_decrypt(File* file) {
if(storage_file_is_decrypted(file)) {
return FSE_OK;
}

S_FILE_API_PROLOGUE;
S_API_PROLOGUE;
S_API_DATA_FILE;
S_API_MESSAGE(StorageCommandFileDecrypt);
S_API_EPILOGUE;
return S_RETURN_ERROR;
}

FS_Error storage_file_encrypt(Storage* storage, const char* path, uint8_t key_slot) {
S_API_PROLOGUE;

SAData data = {.encryption = {.path = path, .key_slot = key_slot}};

S_API_MESSAGE(StorageCommandFileEncrypt);
S_API_EPILOGUE;
return S_RETURN_ERROR;
}

/****************** DIR ******************/

static bool storage_dir_open_internal(File* file, const char* path) {
Expand Down Expand Up @@ -714,6 +737,26 @@ bool storage_file_is_dir(File* file) {
return (file->type == FileTypeOpenDir);
}

bool storage_file_is_encrypted(Storage* storage, const char* path) {
Stream* fstream = file_stream_alloc(storage);
if(!file_stream_open(fstream, path, FSAM_READ, FSOM_OPEN_EXISTING)) {
stream_free(fstream);
return false;
};
uint8_t magic_buf[encryption_magic_size];
stream_read(fstream, magic_buf, encryption_magic_size);
stream_free(fstream);
return memcmp(&encryption_magic_bytes, &magic_buf, encryption_magic_size) == 0;
}

bool storage_file_is_decrypted(File* file) {
return file->encryption && file->encryption->decrypted;
}

bool storage_file_secured(File* file) {
return file->encryption;
}

void storage_file_free(File* file) {
if(storage_file_is_open(file)) {
if(storage_file_is_dir(file)) {
Expand All @@ -724,6 +767,7 @@ void storage_file_free(File* file) {
}

FURI_LOG_T(TAG, "File/Dir %p free", (void*)((uint32_t)file - SRAM_BASE));
free(file->encryption);
free(file);
}

Expand Down
8 changes: 8 additions & 0 deletions applications/services/storage/storage_message.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ typedef struct {
File* file;
} SADataFile;

typedef struct {
const char* path;
const uint8_t key_slot;
} SADataEncryption;

typedef struct {
SDInfo* info;
} SAInfo;
Expand All @@ -91,6 +96,7 @@ typedef union {

SADataFile file;
SADataPath path;
SADataEncryption encryption;

SAInfo sdinfo;
} SAData;
Expand All @@ -114,6 +120,8 @@ typedef enum {
StorageCommandFileSize,
StorageCommandFileSync,
StorageCommandFileEof,
StorageCommandFileEncrypt,
StorageCommandFileDecrypt,
StorageCommandDirOpen,
StorageCommandDirClose,
StorageCommandDirRead,
Expand Down
Loading

0 comments on commit 3f2892b

Please sign in to comment.