Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Library: file encryption/decryption support #163

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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