Skip to content

Commit ea0a922

Browse files
committed
file encryption/decryption support
1 parent 5989651 commit ea0a922

File tree

9 files changed

+297
-1
lines changed

9 files changed

+297
-1
lines changed

applications/debug/unit_tests/storage/storage_test.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "../minunit.h"
22
#include <furi.h>
33
#include <storage/storage.h>
4+
#include <toolbox/stream/file_stream.h>
45

56
#define STORAGE_LOCKED_FILE EXT_PATH("locked_file.test")
67
#define STORAGE_LOCKED_DIR STORAGE_INT_PATH_PREFIX
@@ -309,9 +310,37 @@ MU_TEST_SUITE(storage_rename) {
309310
furi_record_close(RECORD_STORAGE);
310311
}
311312

313+
MU_TEST(storage_encrypt_file) {
314+
Storage* storage = furi_record_open(RECORD_STORAGE);
315+
File* file;
316+
const char* path = EXT_PATH("enc_file");
317+
const uint8_t key_slot = 0;
318+
319+
file = storage_file_alloc(storage);
320+
mu_check(storage_file_open(file, path, FSAM_READ_WRITE, FSOM_CREATE_ALWAYS));
321+
322+
const char* content = "Lorem ipsum dolor sit amet, cons";
323+
mu_check(storage_file_write(file, content, 32) == 32);
324+
storage_file_free(file);
325+
326+
mu_assert_int_eq(FSE_OK, storage_file_encrypt(storage, path, key_slot));
327+
mu_check(storage_file_is_encrypted(storage, path));
328+
329+
furi_record_close(RECORD_STORAGE);
330+
}
331+
332+
MU_TEST_SUITE(storage_encrypt_decrypt) {
333+
MU_RUN_TEST(storage_encrypt_file);
334+
335+
Storage* storage = furi_record_open(RECORD_STORAGE);
336+
storage_dir_remove(storage, EXT_PATH("enc_file"));
337+
furi_record_close(RECORD_STORAGE);
338+
}
339+
312340
int run_minunit_test_storage() {
313341
MU_RUN_SUITE(storage_file);
314342
MU_RUN_SUITE(storage_dir);
315343
MU_RUN_SUITE(storage_rename);
344+
MU_RUN_SUITE(storage_encrypt_decrypt);
316345
return MU_EXIT_CODE;
317346
}

applications/services/storage/filesystem_api.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ const char* filesystem_api_error_get_desc(FS_Error error_id) {
3333
case(FSE_ALREADY_OPEN):
3434
result = "file is already open";
3535
break;
36+
case(FSE_NO_SPACE):
37+
result = "no free space";
38+
break;
3639
}
3740
return result;
3841
}

applications/services/storage/filesystem_api_defines.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ typedef enum {
3333
FSE_INTERNAL, /**< Internal error */
3434
FSE_NOT_IMPLEMENTED, /**< Functon not implemented */
3535
FSE_ALREADY_OPEN, /**< File/Dir already opened */
36+
FSE_NO_SPACE, /**< No free space available */
3637
} FS_Error;
3738

3839
/** FileInfo flags */

applications/services/storage/filesystem_api_internal.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,27 @@
66
extern "C" {
77
#endif
88

9+
#define ENCRYPTION_IV_SIZE 16
10+
#define ENCRYPTION_EXT ".enc"
11+
12+
/** Magic bytes to detect if file is encrypted.
13+
* Encrypted file bytes layout is as follows:
14+
* --------------- ----------------- ---------------- -----------------------
15+
* | 7 bytes magic | 1 byte key slot | 16 byte vector | actual encrypted data |
16+
* --------------- ----------------- ---------------- -----------------------
17+
*/
18+
static const uint8_t encryption_magic_bytes[7] = {0x46, 0x45, 0x46, 0x2e, 0x41, 0x45, 0x53};
19+
static const size_t encryption_magic_size =
20+
sizeof(encryption_magic_bytes) / sizeof(encryption_magic_bytes[0]);
21+
static const size_t encryption_header_size =
22+
encryption_magic_size + sizeof(uint8_t) + ENCRYPTION_IV_SIZE;
23+
24+
/** Structure that holds file encryption info */
25+
typedef struct FileEncryption {
26+
bool decrypted; /**< Current encryption state */
27+
uint8_t key_slot; /**< Slot number of encryption key */
28+
} FileEncryption;
29+
930
/** File type */
1031
typedef enum {
1132
FileTypeClosed, /**< Closed file */
@@ -17,9 +38,11 @@ typedef enum {
1738
struct File {
1839
uint32_t file_id; /**< File ID for internal references */
1940
FileType type;
41+
const char* path; /**< Actual path of opened file */
2042
FS_Error error_id; /**< Standart API error from FS_Error enum */
2143
int32_t internal_error_id; /**< Internal API error value */
2244
void* storage;
45+
FileEncryption* encryption;
2346
};
2447

2548
/** File api structure

applications/services/storage/storage.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,39 @@ bool storage_file_sync(File* file);
135135
*/
136136
bool storage_file_eof(File* file);
137137

138+
/** Checks that file at given path is encrypted
139+
* @param storage
140+
* @param path path to file.
141+
* @return bool success flag
142+
*/
143+
bool storage_file_is_encrypted(Storage* storage, const char* path);
144+
145+
/** Checks that file is decrypted at the moment
146+
* @param file pointer to file object.
147+
* @return bool success flag
148+
*/
149+
bool storage_file_is_decrypted(File* file);
150+
151+
/** Reports if encryption is enabled for this file
152+
* @param file pointer to file object.
153+
* @return bool success flag
154+
*/
155+
bool storage_file_secured(File* file);
156+
157+
/** Decrypts previously encrypted file
158+
* @param file pointer to file object.
159+
* @return FS_Error operation result
160+
*/
161+
FS_Error storage_file_decrypt(File* file);
162+
163+
/** Encrypts file using key from given secure enclave slot
164+
* @param storage
165+
* @param path path to file.
166+
* @param key_slot slot of key in secure enclave.
167+
* @return FS_Error operation result
168+
*/
169+
FS_Error storage_file_encrypt(Storage* storage, const char* path, uint8_t key_slot);
170+
138171
/**
139172
* @brief Check that file exists
140173
*

applications/services/storage/storage_external_api.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,29 @@ bool storage_file_exists(Storage* storage, const char* path) {
259259
return exist;
260260
}
261261

262+
FS_Error storage_file_decrypt(File* file) {
263+
if(storage_file_is_decrypted(file)) {
264+
return FSE_OK;
265+
}
266+
267+
S_FILE_API_PROLOGUE;
268+
S_API_PROLOGUE;
269+
S_API_DATA_FILE;
270+
S_API_MESSAGE(StorageCommandFileDecrypt);
271+
S_API_EPILOGUE;
272+
return S_RETURN_ERROR;
273+
}
274+
275+
FS_Error storage_file_encrypt(Storage* storage, const char* path, uint8_t key_slot) {
276+
S_API_PROLOGUE;
277+
278+
SAData data = {.encryption = {.path = path, .key_slot = key_slot}};
279+
280+
S_API_MESSAGE(StorageCommandFileEncrypt);
281+
S_API_EPILOGUE;
282+
return S_RETURN_ERROR;
283+
}
284+
262285
/****************** DIR ******************/
263286

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

740+
bool storage_file_is_encrypted(Storage* storage, const char* path) {
741+
Stream* fstream = file_stream_alloc(storage);
742+
if(!file_stream_open(fstream, path, FSAM_READ, FSOM_OPEN_EXISTING)) {
743+
stream_free(fstream);
744+
return false;
745+
};
746+
uint8_t magic_buf[encryption_magic_size];
747+
stream_read(fstream, magic_buf, encryption_magic_size);
748+
stream_free(fstream);
749+
return memcmp(&encryption_magic_bytes, &magic_buf, encryption_magic_size) == 0;
750+
}
751+
752+
bool storage_file_is_decrypted(File* file) {
753+
return file->encryption && file->encryption->decrypted;
754+
}
755+
756+
bool storage_file_secured(File* file) {
757+
return file->encryption;
758+
}
759+
717760
void storage_file_free(File* file) {
718761
if(storage_file_is_open(file)) {
719762
if(storage_file_is_dir(file)) {
@@ -724,6 +767,7 @@ void storage_file_free(File* file) {
724767
}
725768

726769
FURI_LOG_T(TAG, "File/Dir %p free", (void*)((uint32_t)file - SRAM_BASE));
770+
free(file->encryption);
727771
free(file);
728772
}
729773

applications/services/storage/storage_message.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ typedef struct {
7070
File* file;
7171
} SADataFile;
7272

73+
typedef struct {
74+
const char* path;
75+
const uint8_t key_slot;
76+
} SADataEncryption;
77+
7378
typedef struct {
7479
SDInfo* info;
7580
} SAInfo;
@@ -91,6 +96,7 @@ typedef union {
9196

9297
SADataFile file;
9398
SADataPath path;
99+
SADataEncryption encryption;
94100

95101
SAInfo sdinfo;
96102
} SAData;
@@ -114,6 +120,8 @@ typedef enum {
114120
StorageCommandFileSize,
115121
StorageCommandFileSync,
116122
StorageCommandFileEof,
123+
StorageCommandFileEncrypt,
124+
StorageCommandFileDecrypt,
117125
StorageCommandDirOpen,
118126
StorageCommandDirClose,
119127
StorageCommandDirRead,

0 commit comments

Comments
 (0)