Merge branch 'dev' of https://github.com/DarkFlippers/unleashed-firmware into xfw-dev --nobuild

This commit is contained in:
Willy-JL
2023-08-13 02:26:24 +02:00
95 changed files with 1850 additions and 299 deletions

View File

@@ -327,6 +327,9 @@ distenv.PhonyTarget(
"cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py -p ${FLIP_PORT}"
)
# Update WiFi devboard firmware
distenv.PhonyTarget("devboard_flash", "${PYTHON3} ${FBT_SCRIPT_DIR}/wifi_board.py")
# Find blackmagic probe
distenv.PhonyTarget(

View File

@@ -0,0 +1,602 @@
#include <stdio.h>
#include <furi.h>
#include <furi_hal.h>
#include "../minunit.h"
static const uint8_t key_ctr_1[32] = {
0x77, 0x6B, 0xEF, 0xF2, 0x85, 0x1D, 0xB0, 0x6F, 0x4C, 0x8A, 0x05, 0x42, 0xC8, 0x69, 0x6F, 0x6C,
0x6A, 0x81, 0xAF, 0x1E, 0xEC, 0x96, 0xB4, 0xD3, 0x7F, 0xC1, 0xD6, 0x89, 0xE6, 0xC1, 0xC1, 0x04,
};
static const uint8_t iv_ctr_1[16] = {
0x00,
0x00,
0x00,
0x60,
0xDB,
0x56,
0x72,
0xC9,
0x7A,
0xA8,
0xF0,
0xB2,
0x00,
0x00,
0x00,
0x01,
};
static const uint8_t pt_ctr_1[16] = {
0x53,
0x69,
0x6E,
0x67,
0x6C,
0x65,
0x20,
0x62,
0x6C,
0x6F,
0x63,
0x6B,
0x20,
0x6D,
0x73,
0x67,
};
static const uint8_t tv_ctr_ct_1[16] = {
0x14,
0x5A,
0xD0,
0x1D,
0xBF,
0x82,
0x4E,
0xC7,
0x56,
0x08,
0x63,
0xDC,
0x71,
0xE3,
0xE0,
0xC0,
};
static const uint8_t key_ctr_2[32] = {
0x77, 0x6B, 0xEF, 0xF2, 0x85, 0x1D, 0xB0, 0x6F, 0x4C, 0x8A, 0x05, 0x42, 0xC8, 0x69, 0x6F, 0x6C,
0x6A, 0x81, 0xAF, 0x1E, 0xEC, 0x96, 0xB4, 0xD3, 0x7F, 0xC1, 0xD6, 0x89, 0xE6, 0xC1, 0xC1, 0x04,
};
static const uint8_t iv_ctr_2[16] = {
0x00,
0x00,
0x00,
0x60,
0xDB,
0x56,
0x72,
0xC9,
0x7A,
0xA8,
0xF0,
0xB2,
0x00,
0x00,
0x00,
0x01,
};
static const uint8_t pt_ctr_2[0] = {};
//static const uint8_t tv_ctr_ct_2[0] = {};
static const uint8_t key_ctr_3[32] = {
0xF6, 0xD6, 0x6D, 0x6B, 0xD5, 0x2D, 0x59, 0xBB, 0x07, 0x96, 0x36, 0x58, 0x79, 0xEF, 0xF8, 0x86,
0xC6, 0x6D, 0xD5, 0x1A, 0x5B, 0x6A, 0x99, 0x74, 0x4B, 0x50, 0x59, 0x0C, 0x87, 0xA2, 0x38, 0x84,
};
static const uint8_t iv_ctr_3[16] = {
0x00,
0xFA,
0xAC,
0x24,
0xC1,
0x58,
0x5E,
0xF1,
0x5A,
0x43,
0xD8,
0x75,
0x00,
0x00,
0x00,
0x01,
};
static const uint8_t pt_ctr_3[32] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
};
static const uint8_t tv_ctr_ct_3[32] = {
0xF0, 0x5E, 0x23, 0x1B, 0x38, 0x94, 0x61, 0x2C, 0x49, 0xEE, 0x00, 0x0B, 0x80, 0x4E, 0xB2, 0xA9,
0xB8, 0x30, 0x6B, 0x50, 0x8F, 0x83, 0x9D, 0x6A, 0x55, 0x30, 0x83, 0x1D, 0x93, 0x44, 0xAF, 0x1C,
};
static const uint8_t key_ctr_4[32] = {
0xFF, 0x7A, 0x61, 0x7C, 0xE6, 0x91, 0x48, 0xE4, 0xF1, 0x72, 0x6E, 0x2F, 0x43, 0x58, 0x1D, 0xE2,
0xAA, 0x62, 0xD9, 0xF8, 0x05, 0x53, 0x2E, 0xDF, 0xF1, 0xEE, 0xD6, 0x87, 0xFB, 0x54, 0x15, 0x3D,
};
static const uint8_t iv_ctr_4[16] = {
0x00,
0x1C,
0xC5,
0xB7,
0x51,
0xA5,
0x1D,
0x70,
0xA1,
0xC1,
0x11,
0x48,
0x00,
0x00,
0x00,
0x01,
};
static const uint8_t pt_ctr_4[36] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23,
};
static const uint8_t tv_ctr_ct_4[36] = {
0xEB, 0x6C, 0x52, 0x82, 0x1D, 0x0B, 0xBB, 0xF7, 0xCE, 0x75, 0x94, 0x46,
0x2A, 0xCA, 0x4F, 0xAA, 0xB4, 0x07, 0xDF, 0x86, 0x65, 0x69, 0xFD, 0x07,
0xF4, 0x8C, 0xC0, 0xB5, 0x83, 0xD6, 0x07, 0x1F, 0x1E, 0xC0, 0xE6, 0xB8,
};
static const uint8_t key_ctr_5[32] = {
0xFF, 0x7A, 0x61, 0x7C, 0xE6, 0x91, 0x48, 0xE4, 0xF1, 0x72, 0x6E, 0x2F, 0x43, 0x58, 0x1D, 0xE2,
0xAA, 0x62, 0xD9, 0xF8, 0x05, 0x53, 0x2E, 0xDF, 0xF1, 0xEE, 0xD6, 0x87, 0xFB, 0x54, 0x15, 0x3D,
};
static const uint8_t iv_ctr_5[16] = {
0x00,
0x1C,
0xC5,
0xB7,
0x51,
0xA5,
0x1D,
0x70,
0xA1,
0xC1,
0x11,
0x48,
0x00,
0x00,
0x00,
0x01,
};
static const uint8_t pt_ctr_5[0] = {};
//static const uint8_t tv_ctr_ct_5[0] = {};
static const uint8_t key_gcm_1[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const uint8_t iv_gcm_1[16] = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
static const uint8_t pt_gcm_1[0] = {};
//static const uint8_t tv_gcm_ct_1[0] = {};
static const uint8_t aad_gcm_1[0] = {};
static const uint8_t tv_gcm_tag_1[16] = {
0x53,
0x0F,
0x8A,
0xFB,
0xC7,
0x45,
0x36,
0xB9,
0xA9,
0x63,
0xB4,
0xF1,
0xC4,
0xCB,
0x73,
0x8B,
};
static const uint8_t key_gcm_2[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const uint8_t iv_gcm_2[16] = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
static const uint8_t pt_gcm_2[16] = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
static const uint8_t tv_gcm_ct_2[16] = {
0xCE,
0xA7,
0x40,
0x3D,
0x4D,
0x60,
0x6B,
0x6E,
0x07,
0x4E,
0xC5,
0xD3,
0xBA,
0xF3,
0x9D,
0x18,
};
static const uint8_t aad_gcm_2[0] = {};
static const uint8_t tv_gcm_tag_2[16] = {
0xD0,
0xD1,
0xC8,
0xA7,
0x99,
0x99,
0x6B,
0xF0,
0x26,
0x5B,
0x98,
0xB5,
0xD4,
0x8A,
0xB9,
0x19,
};
static const uint8_t key_gcm_3[32] = {
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
};
static const uint8_t iv_gcm_3[16] = {
0xCA,
0xFE,
0xBA,
0xBE,
0xFA,
0xCE,
0xDB,
0xAD,
0xDE,
0xCA,
0xF8,
0x88,
0x00,
0x00,
0x00,
0x00,
};
static const uint8_t pt_gcm_3[64] = {
0xD9, 0x31, 0x32, 0x25, 0xF8, 0x84, 0x06, 0xE5, 0xA5, 0x59, 0x09, 0xC5, 0xAF, 0xF5, 0x26, 0x9A,
0x86, 0xA7, 0xA9, 0x53, 0x15, 0x34, 0xF7, 0xDA, 0x2E, 0x4C, 0x30, 0x3D, 0x8A, 0x31, 0x8A, 0x72,
0x1C, 0x3C, 0x0C, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2F, 0xCF, 0x0E, 0x24, 0x49, 0xA6, 0xB5, 0x25,
0xB1, 0x6A, 0xED, 0xF5, 0xAA, 0x0D, 0xE6, 0x57, 0xBA, 0x63, 0x7B, 0x39, 0x1A, 0xAF, 0xD2, 0x55,
};
static const uint8_t tv_gcm_ct_3[64] = {
0x52, 0x2D, 0xC1, 0xF0, 0x99, 0x56, 0x7D, 0x07, 0xF4, 0x7F, 0x37, 0xA3, 0x2A, 0x84, 0x42, 0x7D,
0x64, 0x3A, 0x8C, 0xDC, 0xBF, 0xE5, 0xC0, 0xC9, 0x75, 0x98, 0xA2, 0xBD, 0x25, 0x55, 0xD1, 0xAA,
0x8C, 0xB0, 0x8E, 0x48, 0x59, 0x0D, 0xBB, 0x3D, 0xA7, 0xB0, 0x8B, 0x10, 0x56, 0x82, 0x88, 0x38,
0xC5, 0xF6, 0x1E, 0x63, 0x93, 0xBA, 0x7A, 0x0A, 0xBC, 0xC9, 0xF6, 0x62, 0x89, 0x80, 0x15, 0xAD,
};
static const uint8_t aad_gcm_3[0] = {};
static const uint8_t tv_gcm_tag_3[16] = {
0xB0,
0x94,
0xDA,
0xC5,
0xD9,
0x34,
0x71,
0xBD,
0xEC,
0x1A,
0x50,
0x22,
0x70,
0xE3,
0xCC,
0x6C,
};
static const uint8_t key_gcm_4[32] = {
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
};
static const uint8_t iv_gcm_4[16] = {
0xCA,
0xFE,
0xBA,
0xBE,
0xFA,
0xCE,
0xDB,
0xAD,
0xDE,
0xCA,
0xF8,
0x88,
0x00,
0x00,
0x00,
0x00,
};
static const uint8_t pt_gcm_4[60] = {
0xD9, 0x31, 0x32, 0x25, 0xF8, 0x84, 0x06, 0xE5, 0xA5, 0x59, 0x09, 0xC5, 0xAF, 0xF5, 0x26,
0x9A, 0x86, 0xA7, 0xA9, 0x53, 0x15, 0x34, 0xF7, 0xDA, 0x2E, 0x4C, 0x30, 0x3D, 0x8A, 0x31,
0x8A, 0x72, 0x1C, 0x3C, 0x0C, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2F, 0xCF, 0x0E, 0x24, 0x49,
0xA6, 0xB5, 0x25, 0xB1, 0x6A, 0xED, 0xF5, 0xAA, 0x0D, 0xE6, 0x57, 0xBA, 0x63, 0x7B, 0x39,
};
static const uint8_t tv_gcm_ct_4[60] = {
0x52, 0x2D, 0xC1, 0xF0, 0x99, 0x56, 0x7D, 0x07, 0xF4, 0x7F, 0x37, 0xA3, 0x2A, 0x84, 0x42,
0x7D, 0x64, 0x3A, 0x8C, 0xDC, 0xBF, 0xE5, 0xC0, 0xC9, 0x75, 0x98, 0xA2, 0xBD, 0x25, 0x55,
0xD1, 0xAA, 0x8C, 0xB0, 0x8E, 0x48, 0x59, 0x0D, 0xBB, 0x3D, 0xA7, 0xB0, 0x8B, 0x10, 0x56,
0x82, 0x88, 0x38, 0xC5, 0xF6, 0x1E, 0x63, 0x93, 0xBA, 0x7A, 0x0A, 0xBC, 0xC9, 0xF6, 0x62,
};
static const uint8_t aad_gcm_4[20] = {
0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED,
0xFA, 0xCE, 0xDE, 0xAD, 0xBE, 0xEF, 0xAB, 0xAD, 0xDA, 0xD2,
};
static const uint8_t tv_gcm_tag_4[16] = {
0x76,
0xFC,
0x6E,
0xCE,
0x0F,
0x4E,
0x17,
0x68,
0xCD,
0xDF,
0x88,
0x53,
0xBB,
0x2D,
0x55,
0x1B,
};
static void furi_hal_crypto_ctr_setup() {
}
static void furi_hal_crypto_ctr_teardown() {
}
static void furi_hal_crypto_gcm_setup() {
}
static void furi_hal_crypto_gcm_teardown() {
}
MU_TEST(furi_hal_crypto_ctr_1) {
bool ret = false;
uint8_t ct[sizeof(pt_ctr_1)];
ret = furi_hal_crypto_ctr(key_ctr_1, iv_ctr_1, pt_ctr_1, ct, sizeof(pt_ctr_1));
mu_assert(ret, "CTR 1 failed");
mu_assert_mem_eq(tv_ctr_ct_1, ct, sizeof(pt_ctr_1));
}
MU_TEST(furi_hal_crypto_ctr_2) {
bool ret = false;
uint8_t ct[sizeof(pt_ctr_2)];
ret = furi_hal_crypto_ctr(key_ctr_2, iv_ctr_2, pt_ctr_2, ct, sizeof(pt_ctr_2));
mu_assert(ret, "CTR 2 failed");
//mu_assert_mem_eq(tv_ctr_ct_2, ct, sizeof(pt_ctr_2));
}
MU_TEST(furi_hal_crypto_ctr_3) {
bool ret = false;
uint8_t ct[sizeof(pt_ctr_3)];
ret = furi_hal_crypto_ctr(key_ctr_3, iv_ctr_3, pt_ctr_3, ct, sizeof(pt_ctr_3));
mu_assert(ret, "CTR 3 failed");
mu_assert_mem_eq(tv_ctr_ct_3, ct, sizeof(pt_ctr_3));
}
MU_TEST(furi_hal_crypto_ctr_4) {
bool ret = false;
uint8_t ct[sizeof(pt_ctr_4)];
ret = furi_hal_crypto_ctr(key_ctr_4, iv_ctr_4, pt_ctr_4, ct, sizeof(pt_ctr_4));
mu_assert(ret, "CTR 4 failed");
mu_assert_mem_eq(tv_ctr_ct_4, ct, sizeof(pt_ctr_4));
}
MU_TEST(furi_hal_crypto_ctr_5) {
bool ret = false;
uint8_t ct[sizeof(pt_ctr_5)];
ret = furi_hal_crypto_ctr(key_ctr_5, iv_ctr_5, pt_ctr_5, ct, sizeof(pt_ctr_5));
mu_assert(ret, "CTR 5 failed");
//mu_assert_mem_eq(tv_ctr_ct_5, ct, sizeof(pt_ctr_5));
}
MU_TEST(furi_hal_crypto_gcm_1) {
bool ret = false;
uint8_t pt[sizeof(pt_gcm_1)];
uint8_t ct[sizeof(pt_gcm_1)];
uint8_t tag_enc[16];
uint8_t tag_dec[16];
ret = furi_hal_crypto_gcm(
key_gcm_1,
iv_gcm_1,
aad_gcm_1,
sizeof(aad_gcm_1),
pt_gcm_1,
ct,
sizeof(pt_gcm_1),
tag_enc,
false);
mu_assert(ret, "GCM 1 encryption failed");
//mu_assert_mem_eq(tv_gcm_ct_1, ct, sizeof(pt_gcm_1));
mu_assert_mem_eq(tv_gcm_tag_1, tag_enc, 16);
ret = furi_hal_crypto_gcm(
key_gcm_1, iv_gcm_1, aad_gcm_1, sizeof(aad_gcm_1), ct, pt, sizeof(pt_gcm_1), tag_dec, true);
mu_assert(ret, "GCM 1 decryption failed");
//mu_assert_mem_eq(pt_gcm_1, pt, sizeof(pt_gcm_1));
mu_assert_mem_eq(tv_gcm_tag_1, tag_dec, 16);
}
MU_TEST(furi_hal_crypto_gcm_2) {
bool ret = false;
uint8_t pt[sizeof(pt_gcm_2)];
uint8_t ct[sizeof(pt_gcm_2)];
uint8_t tag_enc[16];
uint8_t tag_dec[16];
ret = furi_hal_crypto_gcm(
key_gcm_2,
iv_gcm_2,
aad_gcm_2,
sizeof(aad_gcm_2),
pt_gcm_2,
ct,
sizeof(pt_gcm_2),
tag_enc,
false);
mu_assert(ret, "GCM 2 encryption failed");
mu_assert_mem_eq(tv_gcm_ct_2, ct, sizeof(pt_gcm_2));
mu_assert_mem_eq(tv_gcm_tag_2, tag_enc, 16);
ret = furi_hal_crypto_gcm(
key_gcm_2, iv_gcm_2, aad_gcm_2, sizeof(aad_gcm_2), ct, pt, sizeof(pt_gcm_2), tag_dec, true);
mu_assert(ret, "GCM 2 decryption failed");
mu_assert_mem_eq(pt_gcm_2, pt, sizeof(pt_gcm_2));
mu_assert_mem_eq(tv_gcm_tag_2, tag_dec, 16);
}
MU_TEST(furi_hal_crypto_gcm_3) {
bool ret = false;
uint8_t pt[sizeof(pt_gcm_3)];
uint8_t ct[sizeof(pt_gcm_3)];
uint8_t tag_enc[16];
uint8_t tag_dec[16];
ret = furi_hal_crypto_gcm(
key_gcm_3,
iv_gcm_3,
aad_gcm_3,
sizeof(aad_gcm_3),
pt_gcm_3,
ct,
sizeof(pt_gcm_3),
tag_enc,
false);
mu_assert(ret, "GCM 3 encryption failed");
mu_assert_mem_eq(tv_gcm_ct_3, ct, sizeof(pt_gcm_3));
mu_assert_mem_eq(tv_gcm_tag_3, tag_enc, 16);
ret = furi_hal_crypto_gcm(
key_gcm_3, iv_gcm_3, aad_gcm_3, sizeof(aad_gcm_3), ct, pt, sizeof(pt_gcm_3), tag_dec, true);
mu_assert(ret, "GCM 3 decryption failed");
mu_assert_mem_eq(pt_gcm_3, pt, sizeof(pt_gcm_3));
mu_assert_mem_eq(tv_gcm_tag_3, tag_dec, 16);
}
MU_TEST(furi_hal_crypto_gcm_4) {
bool ret = false;
uint8_t pt[sizeof(pt_gcm_4)];
uint8_t ct[sizeof(pt_gcm_4)];
uint8_t tag_enc[16];
uint8_t tag_dec[16];
ret = furi_hal_crypto_gcm(
key_gcm_4,
iv_gcm_4,
aad_gcm_4,
sizeof(aad_gcm_4),
pt_gcm_4,
ct,
sizeof(pt_gcm_4),
tag_enc,
false);
mu_assert(ret, "GCM 4 encryption failed");
mu_assert_mem_eq(tv_gcm_ct_4, ct, sizeof(pt_gcm_4));
mu_assert_mem_eq(tv_gcm_tag_4, tag_enc, 16);
ret = furi_hal_crypto_gcm(
key_gcm_4, iv_gcm_4, aad_gcm_4, sizeof(aad_gcm_4), ct, pt, sizeof(pt_gcm_4), tag_dec, true);
mu_assert(ret, "GCM 4 decryption failed");
mu_assert_mem_eq(pt_gcm_4, pt, sizeof(pt_gcm_4));
mu_assert_mem_eq(tv_gcm_tag_4, tag_dec, 16);
}
MU_TEST_SUITE(furi_hal_crypto_ctr_test) {
MU_SUITE_CONFIGURE(&furi_hal_crypto_ctr_setup, &furi_hal_crypto_ctr_teardown);
MU_RUN_TEST(furi_hal_crypto_ctr_1);
MU_RUN_TEST(furi_hal_crypto_ctr_2);
MU_RUN_TEST(furi_hal_crypto_ctr_3);
MU_RUN_TEST(furi_hal_crypto_ctr_4);
MU_RUN_TEST(furi_hal_crypto_ctr_5);
}
MU_TEST_SUITE(furi_hal_crypto_gcm_test) {
MU_SUITE_CONFIGURE(&furi_hal_crypto_gcm_setup, &furi_hal_crypto_gcm_teardown);
MU_RUN_TEST(furi_hal_crypto_gcm_1);
MU_RUN_TEST(furi_hal_crypto_gcm_2);
MU_RUN_TEST(furi_hal_crypto_gcm_3);
MU_RUN_TEST(furi_hal_crypto_gcm_4);
}
int run_minunit_test_furi_hal_crypto() {
MU_RUN_SUITE(furi_hal_crypto_ctr_test);
MU_RUN_SUITE(furi_hal_crypto_gcm_test);
return MU_EXIT_CODE;
}

View File

@@ -10,6 +10,7 @@
int run_minunit_test_furi();
int run_minunit_test_furi_hal();
int run_minunit_test_furi_hal_crypto();
int run_minunit_test_furi_string();
int run_minunit_test_infrared();
int run_minunit_test_rpc();
@@ -39,6 +40,7 @@ typedef struct {
const UnitTest unit_tests[] = {
{.name = "furi", .entry = run_minunit_test_furi},
{.name = "furi_hal", .entry = run_minunit_test_furi_hal},
{.name = "furi_hal_crypto", .entry = run_minunit_test_furi_hal_crypto},
{.name = "furi_string", .entry = run_minunit_test_furi_string},
{.name = "storage", .entry = run_minunit_test_storage},
{.name = "stream", .entry = run_minunit_test_stream},

View File

@@ -7,6 +7,5 @@ App(
requires=["gui"],
stack_size=1 * 1024,
order=60,
fap_icon="mouse_10px.png",
fap_category="Debug",
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -8,7 +8,7 @@
#define TAG "U2F"
#define U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_FACTORY 2
#define U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE 11
#define U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE FURI_HAL_CRYPTO_ENCLAVE_UNIQUE_KEY_SLOT
#define U2F_CERT_STOCK 0 // Stock certificate, private key is encrypted with factory key
#define U2F_CERT_USER 1 // User certificate, private key is encrypted with unique key
@@ -130,7 +130,7 @@ static bool u2f_data_cert_key_encrypt(uint8_t* cert_key) {
// Generate random IV
furi_hal_random_fill_buf(iv, 16);
if(!furi_hal_crypto_store_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) {
if(!furi_hal_crypto_enclave_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) {
FURI_LOG_E(TAG, "Unable to load encryption key");
return false;
}
@@ -139,7 +139,7 @@ static bool u2f_data_cert_key_encrypt(uint8_t* cert_key) {
FURI_LOG_E(TAG, "Encryption failed");
return false;
}
furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE);
furi_hal_crypto_enclave_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE);
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* flipper_format = flipper_format_file_alloc(storage);
@@ -172,8 +172,8 @@ bool u2f_data_cert_key_load(uint8_t* cert_key) {
uint8_t key_slot = 0;
uint32_t version = 0;
// Check if unique key exists in secure eclave(typo?) and generate it if missing
if(!furi_hal_crypto_verify_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE)) return false;
// Check if unique key exists in secure eclave and generate it if missing
if(!furi_hal_crypto_enclave_ensure_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE)) return false;
FuriString* filetype;
filetype = furi_string_alloc();
@@ -220,7 +220,7 @@ bool u2f_data_cert_key_load(uint8_t* cert_key) {
break;
}
if(!furi_hal_crypto_store_load_key(key_slot, iv)) {
if(!furi_hal_crypto_enclave_load_key(key_slot, iv)) {
FURI_LOG_E(TAG, "Unable to load encryption key");
break;
}
@@ -231,7 +231,7 @@ bool u2f_data_cert_key_load(uint8_t* cert_key) {
FURI_LOG_E(TAG, "Decryption failed");
break;
}
furi_hal_crypto_store_unload_key(key_slot);
furi_hal_crypto_enclave_unload_key(key_slot);
} else {
if(!flipper_format_read_hex(flipper_format, "Data", cert_key, 32)) {
FURI_LOG_E(TAG, "Missing data");
@@ -286,7 +286,7 @@ bool u2f_data_key_load(uint8_t* device_key) {
FURI_LOG_E(TAG, "Missing data");
break;
}
if(!furi_hal_crypto_store_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) {
if(!furi_hal_crypto_enclave_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) {
FURI_LOG_E(TAG, "Unable to load encryption key");
break;
}
@@ -296,7 +296,7 @@ bool u2f_data_key_load(uint8_t* device_key) {
FURI_LOG_E(TAG, "Decryption failed");
break;
}
furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE);
furi_hal_crypto_enclave_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE);
state = true;
} while(0);
}
@@ -318,7 +318,7 @@ bool u2f_data_key_generate(uint8_t* device_key) {
furi_hal_random_fill_buf(iv, 16);
furi_hal_random_fill_buf(key, 32);
if(!furi_hal_crypto_store_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) {
if(!furi_hal_crypto_enclave_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) {
FURI_LOG_E(TAG, "Unable to load encryption key");
return false;
}
@@ -327,7 +327,7 @@ bool u2f_data_key_generate(uint8_t* device_key) {
FURI_LOG_E(TAG, "Encryption failed");
return false;
}
furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE);
furi_hal_crypto_enclave_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE);
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* flipper_format = flipper_format_file_alloc(storage);
@@ -392,7 +392,7 @@ bool u2f_data_cnt_read(uint32_t* cnt_val) {
FURI_LOG_E(TAG, "Missing data");
break;
}
if(!furi_hal_crypto_store_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) {
if(!furi_hal_crypto_enclave_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) {
FURI_LOG_E(TAG, "Unable to load encryption key");
break;
}
@@ -402,7 +402,7 @@ bool u2f_data_cnt_read(uint32_t* cnt_val) {
FURI_LOG_E(TAG, "Decryption failed");
break;
}
furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE);
furi_hal_crypto_enclave_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE);
if(cnt.control == U2F_COUNTER_CONTROL_VAL) {
*cnt_val = cnt.counter;
state = true;
@@ -434,7 +434,7 @@ bool u2f_data_cnt_write(uint32_t cnt_val) {
cnt.control = U2F_COUNTER_CONTROL_VAL;
cnt.counter = cnt_val;
if(!furi_hal_crypto_store_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) {
if(!furi_hal_crypto_enclave_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) {
FURI_LOG_E(TAG, "Unable to load encryption key");
return false;
}
@@ -443,7 +443,7 @@ bool u2f_data_cnt_write(uint32_t cnt_val) {
FURI_LOG_E(TAG, "Encryption failed");
return false;
}
furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE);
furi_hal_crypto_enclave_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE);
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* flipper_format = flipper_format_file_alloc(storage);

View File

@@ -33,7 +33,7 @@ void crypto_cli_encrypt(Cli* cli, FuriString* args) {
break;
}
if(!furi_hal_crypto_store_load_key(key_slot, iv)) {
if(!furi_hal_crypto_enclave_load_key(key_slot, iv)) {
printf("Unable to load key from slot %d", key_slot);
break;
}
@@ -88,7 +88,7 @@ void crypto_cli_encrypt(Cli* cli, FuriString* args) {
} while(0);
if(key_loaded) {
furi_hal_crypto_store_unload_key(key_slot);
furi_hal_crypto_enclave_unload_key(key_slot);
}
}
@@ -108,7 +108,7 @@ void crypto_cli_decrypt(Cli* cli, FuriString* args) {
break;
}
if(!furi_hal_crypto_store_load_key(key_slot, iv)) {
if(!furi_hal_crypto_enclave_load_key(key_slot, iv)) {
printf("Unable to load key from slot %d", key_slot);
break;
}
@@ -160,7 +160,7 @@ void crypto_cli_decrypt(Cli* cli, FuriString* args) {
} while(0);
if(key_loaded) {
furi_hal_crypto_store_unload_key(key_slot);
furi_hal_crypto_enclave_unload_key(key_slot);
}
}
@@ -175,14 +175,14 @@ void crypto_cli_has_key(Cli* cli, FuriString* args) {
break;
}
if(!furi_hal_crypto_store_load_key(key_slot, iv)) {
if(!furi_hal_crypto_enclave_load_key(key_slot, iv)) {
printf("Unable to load key from slot %d", key_slot);
break;
}
printf("Successfully loaded key from slot %d", key_slot);
furi_hal_crypto_store_unload_key(key_slot);
furi_hal_crypto_enclave_unload_key(key_slot);
} while(0);
}
@@ -251,25 +251,25 @@ void crypto_cli_store_key(Cli* cli, FuriString* args) {
if(key_slot > 0) {
uint8_t iv[16] = {0};
if(key_slot > 1) {
if(!furi_hal_crypto_store_load_key(key_slot - 1, iv)) {
if(!furi_hal_crypto_enclave_load_key(key_slot - 1, iv)) {
printf(
"Slot %d before %d is empty, which is not allowed",
key_slot - 1,
key_slot);
break;
}
furi_hal_crypto_store_unload_key(key_slot - 1);
furi_hal_crypto_enclave_unload_key(key_slot - 1);
}
if(furi_hal_crypto_store_load_key(key_slot, iv)) {
furi_hal_crypto_store_unload_key(key_slot);
if(furi_hal_crypto_enclave_load_key(key_slot, iv)) {
furi_hal_crypto_enclave_unload_key(key_slot);
printf("Key slot %d is already used", key_slot);
break;
}
}
uint8_t slot;
if(furi_hal_crypto_store_add_key(&key, &slot)) {
if(furi_hal_crypto_enclave_store_key(&key, &slot)) {
printf("Success. Stored to slot: %d", slot);
} else {
printf("Failure");

View File

@@ -1,6 +1,7 @@
#include <storage/storage.h>
#include <assets_icons.h>
#include <gui/gui.h>
#include <gui/gui_i.h>
#include <gui/view_stack.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
@@ -38,103 +39,69 @@ static void desktop_loader_callback(const void* message, void* context) {
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAfterAppFinished);
}
}
static void desktop_lock_icon_draw_callback(Canvas* canvas, void* context) {
UNUSED(context);
furi_assert(canvas);
canvas_draw_icon(canvas, 0, 0, &I_Lock_7x8);
}
static void desktop_clock_upd_time(Desktop* desktop, bool forced) {
static void desktop_clock_update(Desktop* desktop) {
furi_assert(desktop);
FuriHalRtcDateTime curr_dt;
furi_hal_rtc_get_datetime(&curr_dt);
bool time_format_12 = locale_get_time_format() == LocaleTimeFormat12h;
if(forced) {
desktop->clock_type = (locale_get_time_format() == LocaleTimeFormat24h);
}
if(forced || (desktop->minute != curr_dt.minute)) {
if(desktop->clock_type) {
desktop->hour = curr_dt.hour;
} else {
desktop->hour = (curr_dt.hour > 12) ? curr_dt.hour - 12 :
((curr_dt.hour == 0) ? 12 : curr_dt.hour);
}
desktop->minute = curr_dt.minute;
if(desktop->time_hour != curr_dt.hour || desktop->time_minute != curr_dt.minute ||
desktop->time_format_12 != time_format_12) {
desktop->time_format_12 = time_format_12;
desktop->time_hour = curr_dt.hour;
desktop->time_minute = curr_dt.minute;
view_port_update(desktop->clock_viewport);
}
}
static void desktop_clock_toggle_view(Desktop* desktop, bool is_enabled) {
static void desktop_clock_reconfigure(Desktop* desktop) {
furi_assert(desktop);
desktop_clock_upd_time(desktop, true);
desktop_clock_update(desktop);
if(is_enabled) { // && !furi_timer_is_running(desktop->update_clock_timer)) {
if(XTREME_SETTINGS()->statusbar_clock) {
furi_timer_start(desktop->update_clock_timer, furi_ms_to_ticks(1000));
} else if(!is_enabled) { //&& furi_timer_is_running(desktop->update_clock_timer)) {
} else {
furi_timer_stop(desktop->update_clock_timer);
}
view_port_enabled_set(desktop->clock_viewport, is_enabled);
view_port_enabled_set(desktop->clock_viewport, XTREME_SETTINGS()->statusbar_clock);
}
static uint8_t desktop_clock_get_num_w(uint8_t num) {
if(num == 1) {
return 3;
} else if(num == 4) {
return 6;
} else {
return 5;
}
}
static const char* digit[10] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
static void desktop_clock_draw_callback(Canvas* canvas, void* context) {
furi_assert(context);
furi_assert(canvas);
Desktop* desktop = context;
uint8_t d[4] = {
desktop->minute % 10,
desktop->minute / 10,
desktop->hour % 10,
desktop->hour / 10,
};
canvas_set_font(canvas, FontPrimary);
uint8_t new_w = desktop_clock_get_num_w(d[0]) + //c1
desktop_clock_get_num_w(d[1]) + //c2
desktop_clock_get_num_w(d[2]) + //c3
desktop_clock_get_num_w(d[3]) + //c4
2 + 4; // ":" + 4 separators
uint8_t hour = desktop->time_hour;
if(desktop->time_format_12) {
if(hour > 12) {
hour -= 12;
}
if(hour == 0) {
hour = 12;
}
}
// further away from the battery charge indicator, if the smallest minute is 1
view_port_set_width(desktop->clock_viewport, new_w - !(d[0] == 1));
char buffer[20];
snprintf(buffer, sizeof(buffer), "%02u:%02u", hour, desktop->time_minute);
uint8_t x = new_w;
// ToDo: never do that, may cause visual glitches
view_port_set_width(
desktop->clock_viewport,
canvas_string_width(canvas, buffer) - 1 + (desktop->time_minute % 10 == 1));
uint8_t y = 8;
uint8_t offset_r;
canvas_draw_str_aligned(canvas, x, y, AlignRight, AlignBottom, digit[d[0]]);
offset_r = desktop_clock_get_num_w(d[0]);
canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y, AlignRight, AlignBottom, digit[d[1]]);
offset_r = desktop_clock_get_num_w(d[1]);
canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y - 1, AlignRight, AlignBottom, ":");
offset_r = 2;
canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y, AlignRight, AlignBottom, digit[d[2]]);
offset_r = desktop_clock_get_num_w(d[2]);
canvas_draw_str_aligned(canvas, x -= (offset_r + 1), y, AlignRight, AlignBottom, digit[d[3]]);
canvas_draw_str_aligned(canvas, 0, 8, AlignLeft, AlignBottom, buffer);
}
static void desktop_stealth_mode_icon_draw_callback(Canvas* canvas, void* context) {
@@ -154,7 +121,7 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) {
return true;
case DesktopGlobalAfterAppFinished:
animation_manager_load_and_continue_animation(desktop->animation_manager);
desktop_clock_toggle_view(desktop, XTREME_SETTINGS()->statusbar_clock);
desktop_clock_reconfigure(desktop);
desktop_auto_lock_arm(desktop);
return true;
case DesktopGlobalAutoLock:
@@ -224,8 +191,8 @@ static void desktop_clock_timer_callback(void* context) {
furi_assert(context);
Desktop* desktop = context;
if(gui_get_count_of_enabled_view_port_in_layer(desktop->gui, GuiLayerStatusBarLeft) < 6) {
desktop_clock_upd_time(desktop, false);
if(gui_active_view_port_count(desktop->gui, GuiLayerStatusBarLeft) < 6) {
desktop_clock_update(desktop);
view_port_enabled_set(desktop->clock_viewport, true);
} else {
@@ -420,11 +387,6 @@ Desktop* desktop_alloc() {
desktop->update_clock_timer =
furi_timer_alloc(desktop_clock_timer_callback, FuriTimerTypePeriodic, desktop);
FuriHalRtcDateTime curr_dt;
furi_hal_rtc_get_datetime(&curr_dt);
desktop_clock_upd_time(desktop, true);
furi_record_create(RECORD_DESKTOP, desktop);
return desktop;
@@ -524,7 +486,7 @@ int32_t desktop_srv(void* p) {
DESKTOP_KEYBINDS_LOAD(&desktop->keybinds, sizeof(desktop->keybinds));
desktop_clock_toggle_view(desktop, XTREME_SETTINGS()->statusbar_clock);
desktop_clock_reconfigure(desktop);
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);

View File

@@ -74,9 +74,10 @@ struct Desktop {
FuriTimer* update_clock_timer;
FuriPubSub* status_pubsub;
uint8_t hour;
uint8_t minute;
bool clock_type : 1; // true - 24h false - 12h
uint8_t time_hour;
uint8_t time_minute;
bool time_format_12 : 1; // 1 - 12 hour, 0 - 24H
bool in_transition : 1;
};

View File

@@ -20,11 +20,12 @@ ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) {
return NULL;
}
uint8_t gui_get_count_of_enabled_view_port_in_layer(Gui* gui, GuiLayer layer) {
size_t gui_active_view_port_count(Gui* gui, GuiLayer layer) {
furi_assert(gui);
furi_check(layer < GuiLayerMAX);
uint8_t ret = 0;
size_t ret = 0;
gui_lock(gui);
ViewPortArray_it_t it;
ViewPortArray_it_last(it, gui->layers[layer]);
while(!ViewPortArray_end_p(it)) {
@@ -34,6 +35,8 @@ uint8_t gui_get_count_of_enabled_view_port_in_layer(Gui* gui, GuiLayer layer) {
}
ViewPortArray_previous(it);
}
gui_unlock(gui);
return ret;
}

View File

@@ -141,8 +141,6 @@ Canvas* gui_direct_draw_acquire(Gui* gui);
*/
void gui_direct_draw_release(Gui* gui);
uint8_t gui_get_count_of_enabled_view_port_in_layer(Gui* gui, GuiLayer layer);
#ifdef __cplusplus
}
#endif

View File

@@ -76,6 +76,12 @@ struct Gui {
ViewPort* ongoing_input_view_port;
};
/** Find enabled ViewPort in ViewPortArray
*
* @param[in] array The ViewPortArray instance
*
* @return ViewPort instance or NULL
*/
ViewPort* gui_view_port_find_enabled(ViewPortArray_t array);
/** Update GUI, request redraw
@@ -84,8 +90,30 @@ ViewPort* gui_view_port_find_enabled(ViewPortArray_t array);
*/
void gui_update(Gui* gui);
/** Input event callback
*
* Used to receive input from input service or to inject new input events
*
* @param[in] value The value pointer (InputEvent*)
* @param ctx The context (Gui instance)
*/
void gui_input_events_callback(const void* value, void* ctx);
/** Get count of view ports in layer
*
* @param gui The Gui instance
* @param[in] layer GuiLayer that we want to get count of view ports
*/
size_t gui_active_view_port_count(Gui* gui, GuiLayer layer);
/** Lock GUI
*
* @param gui The Gui instance
*/
void gui_lock(Gui* gui);
/** Unlock GUI
*
* @param gui The Gui instance
*/
void gui_unlock(Gui* gui);

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 980 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 979 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 859 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 889 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 907 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 769 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 915 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 883 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 997 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 949 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1016 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 991 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 970 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,284 @@
Filetype: Flipper Animation
Version: 1
Width: 128
Height: 64
Passive frames: 31
Active frames: 55
Frames order: 0 1 2 3 4 5 0 1 6 7 8 5 9 10 11 12 13 14 15 0 1 2 3 4 5 0 1 6 7 8 5 9 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 53 54 53 55 56 57 58 59 60 61 62 4 5
Active cycles: 1
Frame rate: 2
Duration: 3600
Active cooldown: 6
Bubble slots: 4
Slot: 0
X: 65
Y: 14
Text: All by myself
AlignH: Left
AlignV: Bottom
StartFrame: 45
EndFrame: 51
Slot: 0
X: 5
Y: 16
Text: Don't want
AlignH: Right
AlignV: Bottom
StartFrame: 56
EndFrame: 58
Slot: 0
X: 15
Y: 15
Text: to be
AlignH: Right
AlignV: Bottom
StartFrame: 59
EndFrame: 60
Slot: 0
X: 14
Y: 14
Text: All by myself
AlignH: Right
AlignV: Bottom
StartFrame: 63
EndFrame: 69
Slot: 0
X: 81
Y: 25
Text: anymore
AlignH: Left
AlignV: Bottom
StartFrame: 72
EndFrame: 74
Slot: 1
X: 65
Y: 14
Text: Nevermind
AlignH: Left
AlignV: Bottom
StartFrame: 45
EndFrame: 48
Slot: 1
X: 65
Y: 14
Text: I'll find
AlignH: Left
AlignV: Bottom
StartFrame: 49
EndFrame: 52
Slot: 1
X: 2
Y: 16
Text: Someone like
AlignH: Right
AlignV: Bottom
StartFrame: 56
EndFrame: 58
Slot: 1
X: 11
Y: 16
Text: youuuuu
AlignH: Right
AlignV: Bottom
StartFrame: 59
EndFrame: 60
Slot: 1
X: 3
Y: 14
Text: I wish nothing
AlignH: Right
AlignV: Bottom
StartFrame: 64
EndFrame: 66
Slot: 1
X: 6
Y: 14
Text: but the best
AlignH: Right
AlignV: Bottom
StartFrame: 67
EndFrame: 70
Slot: 1
X: 81
Y: 25
Text: for you
AlignH: Left
AlignV: Bottom
StartFrame: 72
EndFrame: 74
Slot: 2
X: 65
Y: 14
Text: What have I
AlignH: Left
AlignV: Bottom
StartFrame: 45
EndFrame: 48
Slot: 2
X: 65
Y: 14
Text: become
AlignH: Left
AlignV: Bottom
StartFrame: 47
EndFrame: 51
Slot: 2
X: 6
Y: 16
Text: My dearest
AlignH: Right
AlignV: Bottom
StartFrame: 56
EndFrame: 58
Slot: 2
X: 14
Y: 16
Text: friend
AlignH: Right
AlignV: Bottom
StartFrame: 59
EndFrame: 60
Slot: 2
X: 17
Y: 14
Text: Everyone
AlignH: Right
AlignV: Bottom
StartFrame: 63
EndFrame: 64
Slot: 2
X: 17
Y: 14
Text: I know
AlignH: Right
AlignV: Bottom
StartFrame: 65
EndFrame: 67
Slot: 2
X: 17
Y: 14
Text: goes away
AlignH: Right
AlignV: Bottom
StartFrame: 68
EndFrame: 70
Slot: 2
X: 81
Y: 25
Text: in the\n end
AlignH: Left
AlignV: Bottom
StartFrame: 72
EndFrame: 74
Slot: 3
X: 73
Y: 14
Text: We could\n have been
AlignH: Left
AlignV: Bottom
StartFrame: 45
EndFrame: 48
Slot: 3
X: 73
Y: 14
Text: so good\n together
AlignH: Left
AlignV: Bottom
StartFrame: 49
EndFrame: 51
Slot: 3
X: 7
Y: 17
Text: We could\n have lived
AlignH: Right
AlignV: Bottom
StartFrame: 55
EndFrame: 57
Slot: 3
X: 7
Y: 17
Text: this dance\n forever
AlignH: Right
AlignV: Bottom
StartFrame: 58
EndFrame: 60
Slot: 3
X: 12
Y: 14
Text: But now
AlignH: Right
AlignV: Bottom
StartFrame: 64
EndFrame: 65
Slot: 3
X: 5
Y: 14
Text: who's gonna
AlignH: Right
AlignV: Bottom
StartFrame: 66
EndFrame: 67
Slot: 3
X: 7
Y: 14
Text: dance with
AlignH: Right
AlignV: Bottom
StartFrame: 68
EndFrame: 69
Slot: 3
X: 26
Y: 14
Text: me?
AlignH: Right
AlignV: Bottom
StartFrame: 70
EndFrame: 70
Slot: 3
X: 81
Y: 25
Text: Please
AlignH: Left
AlignV: Bottom
StartFrame: 72
EndFrame: 74
Slot: 3
X: 81
Y: 25
Text: stay
AlignH: Left
AlignV: Bottom
StartFrame: 74
EndFrame: 75

View File

@@ -161,3 +161,10 @@ Max butthurt: 14
Min level: 27
Max level: 30
Weight: 3
Name: L1_Sad_song_128x64
Min butthurt: 11
Max butthurt: 14
Min level: 14
Max level: 30
Weight: 4

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,34.4,,
Version,+,35.0,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,,
@@ -1035,14 +1035,20 @@ Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t,
Function,+,furi_hal_cortex_timer_get,FuriHalCortexTimer,uint32_t
Function,+,furi_hal_cortex_timer_is_expired,_Bool,FuriHalCortexTimer
Function,+,furi_hal_cortex_timer_wait,void,FuriHalCortexTimer
Function,+,furi_hal_crypto_ctr,_Bool,"const uint8_t*, const uint8_t*, const uint8_t*, uint8_t*, size_t"
Function,+,furi_hal_crypto_decrypt,_Bool,"const uint8_t*, uint8_t*, size_t"
Function,+,furi_hal_crypto_encrypt,_Bool,"const uint8_t*, uint8_t*, size_t"
Function,+,furi_hal_crypto_gcm,_Bool,"const uint8_t*, const uint8_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, size_t, uint8_t*, _Bool"
Function,+,furi_hal_crypto_gcm_decrypt_and_verify,FuriHalCryptoGCMState,"const uint8_t*, const uint8_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, size_t, const uint8_t*"
Function,+,furi_hal_crypto_gcm_encrypt_and_tag,FuriHalCryptoGCMState,"const uint8_t*, const uint8_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, size_t, uint8_t*"
Function,-,furi_hal_crypto_init,void,
Function,+,furi_hal_crypto_store_add_key,_Bool,"FuriHalCryptoKey*, uint8_t*"
Function,+,furi_hal_crypto_store_load_key,_Bool,"uint8_t, const uint8_t*"
Function,+,furi_hal_crypto_store_unload_key,_Bool,uint8_t
Function,+,furi_hal_crypto_verify_enclave,_Bool,"uint8_t*, uint8_t*"
Function,+,furi_hal_crypto_verify_key,_Bool,uint8_t
Function,+,furi_hal_crypto_load_key,_Bool,"const uint8_t*, const uint8_t*"
Function,+,furi_hal_crypto_enclave_store_key,_Bool,"FuriHalCryptoKey*, uint8_t*"
Function,+,furi_hal_crypto_enclave_load_key,_Bool,"uint8_t, const uint8_t*"
Function,+,furi_hal_crypto_enclave_unload_key,_Bool,uint8_t
Function,+,furi_hal_crypto_unload_key,_Bool,
Function,+,furi_hal_crypto_enclave_verify,_Bool,"uint8_t*, uint8_t*"
Function,+,furi_hal_crypto_enclave_ensure_key,_Bool,uint8_t
Function,+,furi_hal_debug_disable,void,
Function,+,furi_hal_debug_enable,void,
Function,+,furi_hal_debug_is_gdb_session_active,_Bool,
1 entry status name type params
2 Version + 34.4 35.0
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
1035 Function + furi_hal_cortex_timer_get FuriHalCortexTimer uint32_t
1036 Function + furi_hal_cortex_timer_is_expired _Bool FuriHalCortexTimer
1037 Function + furi_hal_cortex_timer_wait void FuriHalCortexTimer
1038 Function + furi_hal_crypto_ctr _Bool const uint8_t*, const uint8_t*, const uint8_t*, uint8_t*, size_t
1039 Function + furi_hal_crypto_decrypt _Bool const uint8_t*, uint8_t*, size_t
1040 Function + furi_hal_crypto_encrypt _Bool const uint8_t*, uint8_t*, size_t
1041 Function + furi_hal_crypto_gcm _Bool const uint8_t*, const uint8_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, size_t, uint8_t*, _Bool
1042 Function + furi_hal_crypto_gcm_decrypt_and_verify FuriHalCryptoGCMState const uint8_t*, const uint8_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, size_t, const uint8_t*
1043 Function + furi_hal_crypto_gcm_encrypt_and_tag FuriHalCryptoGCMState const uint8_t*, const uint8_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, size_t, uint8_t*
1044 Function - furi_hal_crypto_init void
1045 Function + furi_hal_crypto_store_add_key furi_hal_crypto_load_key _Bool FuriHalCryptoKey*, uint8_t* const uint8_t*, const uint8_t*
1046 Function + furi_hal_crypto_store_load_key furi_hal_crypto_enclave_store_key _Bool uint8_t, const uint8_t* FuriHalCryptoKey*, uint8_t*
1047 Function + furi_hal_crypto_store_unload_key furi_hal_crypto_enclave_load_key _Bool uint8_t uint8_t, const uint8_t*
1048 Function + furi_hal_crypto_verify_enclave furi_hal_crypto_enclave_unload_key _Bool uint8_t*, uint8_t* uint8_t
1049 Function + furi_hal_crypto_verify_key furi_hal_crypto_unload_key _Bool uint8_t
1050 Function + furi_hal_crypto_enclave_verify _Bool uint8_t*, uint8_t*
1051 Function + furi_hal_crypto_enclave_ensure_key _Bool uint8_t
1052 Function + furi_hal_debug_disable void
1053 Function + furi_hal_debug_enable void
1054 Function + furi_hal_debug_is_gdb_session_active _Bool

View File

@@ -1169,14 +1169,20 @@ Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t,
Function,+,furi_hal_cortex_timer_get,FuriHalCortexTimer,uint32_t
Function,+,furi_hal_cortex_timer_is_expired,_Bool,FuriHalCortexTimer
Function,+,furi_hal_cortex_timer_wait,void,FuriHalCortexTimer
Function,+,furi_hal_crypto_ctr,_Bool,"const uint8_t*, const uint8_t*, const uint8_t*, uint8_t*, size_t"
Function,+,furi_hal_crypto_decrypt,_Bool,"const uint8_t*, uint8_t*, size_t"
Function,+,furi_hal_crypto_encrypt,_Bool,"const uint8_t*, uint8_t*, size_t"
Function,+,furi_hal_crypto_gcm,_Bool,"const uint8_t*, const uint8_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, size_t, uint8_t*, _Bool"
Function,+,furi_hal_crypto_gcm_decrypt_and_verify,FuriHalCryptoGCMState,"const uint8_t*, const uint8_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, size_t, const uint8_t*"
Function,+,furi_hal_crypto_gcm_encrypt_and_tag,FuriHalCryptoGCMState,"const uint8_t*, const uint8_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, size_t, uint8_t*"
Function,-,furi_hal_crypto_init,void,
Function,+,furi_hal_crypto_store_add_key,_Bool,"FuriHalCryptoKey*, uint8_t*"
Function,+,furi_hal_crypto_store_load_key,_Bool,"uint8_t, const uint8_t*"
Function,+,furi_hal_crypto_store_unload_key,_Bool,uint8_t
Function,+,furi_hal_crypto_verify_enclave,_Bool,"uint8_t*, uint8_t*"
Function,+,furi_hal_crypto_verify_key,_Bool,uint8_t
Function,+,furi_hal_crypto_load_key,_Bool,"const uint8_t*, const uint8_t*"
Function,+,furi_hal_crypto_enclave_store_key,_Bool,"FuriHalCryptoKey*, uint8_t*"
Function,+,furi_hal_crypto_enclave_load_key,_Bool,"uint8_t, const uint8_t*"
Function,+,furi_hal_crypto_enclave_unload_key,_Bool,uint8_t
Function,+,furi_hal_crypto_unload_key,_Bool,
Function,+,furi_hal_crypto_enclave_verify,_Bool,"uint8_t*, uint8_t*"
Function,+,furi_hal_crypto_enclave_ensure_key,_Bool,uint8_t
Function,+,furi_hal_debug_disable,void,
Function,+,furi_hal_debug_enable,void,
Function,+,furi_hal_debug_is_gdb_session_active,_Bool,
@@ -1713,7 +1719,6 @@ Function,+,gui_add_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, voi
Function,+,gui_add_view_port,void,"Gui*, ViewPort*, GuiLayer"
Function,+,gui_direct_draw_acquire,Canvas*,Gui*
Function,+,gui_direct_draw_release,void,Gui*
Function,-,gui_get_count_of_enabled_view_port_in_layer,uint8_t,"Gui*, GuiLayer"
Function,+,gui_get_framebuffer_size,size_t,const Gui*
Function,+,gui_remove_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, void*"
Function,+,gui_remove_view_port,void,"Gui*, ViewPort*"
1 entry status name type params
1169 Function + furi_hal_cortex_timer_get FuriHalCortexTimer uint32_t
1170 Function + furi_hal_cortex_timer_is_expired _Bool FuriHalCortexTimer
1171 Function + furi_hal_cortex_timer_wait void FuriHalCortexTimer
1172 Function + furi_hal_crypto_ctr _Bool const uint8_t*, const uint8_t*, const uint8_t*, uint8_t*, size_t
1173 Function + furi_hal_crypto_decrypt _Bool const uint8_t*, uint8_t*, size_t
1174 Function + furi_hal_crypto_encrypt _Bool const uint8_t*, uint8_t*, size_t
1175 Function + furi_hal_crypto_gcm _Bool const uint8_t*, const uint8_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, size_t, uint8_t*, _Bool
1176 Function + furi_hal_crypto_gcm_decrypt_and_verify FuriHalCryptoGCMState const uint8_t*, const uint8_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, size_t, const uint8_t*
1177 Function + furi_hal_crypto_gcm_encrypt_and_tag FuriHalCryptoGCMState const uint8_t*, const uint8_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*, size_t, uint8_t*
1178 Function - furi_hal_crypto_init void
1179 Function + furi_hal_crypto_store_add_key furi_hal_crypto_load_key _Bool FuriHalCryptoKey*, uint8_t* const uint8_t*, const uint8_t*
1180 Function + furi_hal_crypto_store_load_key furi_hal_crypto_enclave_store_key _Bool uint8_t, const uint8_t* FuriHalCryptoKey*, uint8_t*
1181 Function + furi_hal_crypto_store_unload_key furi_hal_crypto_enclave_load_key _Bool uint8_t uint8_t, const uint8_t*
1182 Function + furi_hal_crypto_verify_enclave furi_hal_crypto_enclave_unload_key _Bool uint8_t*, uint8_t* uint8_t
1183 Function + furi_hal_crypto_verify_key furi_hal_crypto_unload_key _Bool uint8_t
1184 Function + furi_hal_crypto_enclave_verify _Bool uint8_t*, uint8_t*
1185 Function + furi_hal_crypto_enclave_ensure_key _Bool uint8_t
1186 Function + furi_hal_debug_disable void
1187 Function + furi_hal_debug_enable void
1188 Function + furi_hal_debug_is_gdb_session_active _Bool
1719 Function + gui_add_view_port void Gui*, ViewPort*, GuiLayer
1720 Function + gui_direct_draw_acquire Canvas* Gui*
1721 Function + gui_direct_draw_release void Gui*
Function - gui_get_count_of_enabled_view_port_in_layer uint8_t Gui*, GuiLayer
1722 Function + gui_get_framebuffer_size size_t const Gui*
1723 Function + gui_remove_framebuffer_callback void Gui*, GuiCanvasCommitCallback, void*
1724 Function + gui_remove_view_port void Gui*, ViewPort*

View File

@@ -1,4 +1,5 @@
#include <furi_hal_crypto.h>
#include <furi_hal_cortex.h>
#include <furi_hal_bt.h>
#include <furi_hal_random.h>
#include <furi_hal_bus.h>
@@ -13,7 +14,7 @@
#define ENCLAVE_SIGNATURE_SIZE 16
#define CRYPTO_BLK_LEN (4 * sizeof(uint32_t))
#define CRYPTO_TIMEOUT (1000)
#define CRYPTO_TIMEOUT_US (1000000)
#define CRYPTO_MODE_ENCRYPT 0U
#define CRYPTO_MODE_INIT (AES_CR_MODE_0)
@@ -24,6 +25,19 @@
#define CRYPTO_KEYSIZE_256B (AES_CR_KEYSIZE)
#define CRYPTO_AES_CBC (AES_CR_CHMOD_0)
#define CRYPTO_AES_CTR (AES_CR_CHMOD_1)
#define CRYPTO_CTR_IV_LEN (12U)
#define CRYPTO_CTR_CTR_LEN (4U)
#define CRYPTO_AES_GCM (AES_CR_CHMOD_1 | AES_CR_CHMOD_0)
#define CRYPTO_GCM_IV_LEN (12U)
#define CRYPTO_GCM_CTR_LEN (4U)
#define CRYPTO_GCM_TAG_LEN (16U)
#define CRYPTO_GCM_PH_INIT (0x0U << AES_CR_GCMPH_Pos)
#define CRYPTO_GCM_PH_HEADER (AES_CR_GCMPH_0)
#define CRYPTO_GCM_PH_PAYLOAD (AES_CR_GCMPH_1)
#define CRYPTO_GCM_PH_FINAL (AES_CR_GCMPH_1 | AES_CR_GCMPH_0)
static FuriMutex* furi_hal_crypto_mutex = NULL;
static bool furi_hal_crypto_mode_init_done = false;
@@ -80,7 +94,7 @@ static bool furi_hal_crypto_generate_unique_keys(uint8_t start_slot, uint8_t end
key.size = FuriHalCryptoKeySize256;
key.data = key_data;
furi_hal_random_fill_buf(key_data, 32);
if(!furi_hal_crypto_store_add_key(&key, &slot)) {
if(!furi_hal_crypto_enclave_store_key(&key, &slot)) {
explicit_bzero(key_data, sizeof(key_data));
FURI_LOG_E(TAG, "Error writing key to slot %u", slot);
return false;
@@ -90,21 +104,21 @@ static bool furi_hal_crypto_generate_unique_keys(uint8_t start_slot, uint8_t end
return true;
}
bool furi_hal_crypto_verify_key(uint8_t key_slot) {
bool furi_hal_crypto_enclave_ensure_key(uint8_t key_slot) {
uint8_t keys_nb = 0;
uint8_t valid_keys_nb = 0;
uint8_t last_valid_slot = ENCLAVE_FACTORY_KEY_SLOTS;
uint8_t empty_iv[16] = {0};
furi_hal_crypto_verify_enclave(&keys_nb, &valid_keys_nb);
furi_hal_crypto_enclave_verify(&keys_nb, &valid_keys_nb);
if(key_slot <= ENCLAVE_FACTORY_KEY_SLOTS) { // It's a factory key
if(key_slot > keys_nb) return false;
} else { // Unique key
if(keys_nb < ENCLAVE_FACTORY_KEY_SLOTS) // Some factory keys are missing
return false;
for(uint8_t i = key_slot; i > ENCLAVE_FACTORY_KEY_SLOTS; i--) {
if(furi_hal_crypto_store_load_key(i, empty_iv)) {
if(furi_hal_crypto_enclave_load_key(i, empty_iv)) {
last_valid_slot = i;
furi_hal_crypto_store_unload_key(i);
furi_hal_crypto_enclave_unload_key(i);
break;
}
}
@@ -116,14 +130,14 @@ bool furi_hal_crypto_verify_key(uint8_t key_slot) {
return true;
}
bool furi_hal_crypto_verify_enclave(uint8_t* keys_nb, uint8_t* valid_keys_nb) {
bool furi_hal_crypto_enclave_verify(uint8_t* keys_nb, uint8_t* valid_keys_nb) {
furi_assert(keys_nb);
furi_assert(valid_keys_nb);
uint8_t keys = 0;
uint8_t keys_valid = 0;
uint8_t buffer[ENCLAVE_SIGNATURE_SIZE];
for(size_t key_slot = 0; key_slot < ENCLAVE_FACTORY_KEY_SLOTS; key_slot++) {
if(furi_hal_crypto_store_load_key(key_slot + 1, enclave_signature_iv[key_slot])) {
if(furi_hal_crypto_enclave_load_key(key_slot + 1, enclave_signature_iv[key_slot])) {
keys++;
if(furi_hal_crypto_encrypt(
enclave_signature_input[key_slot], buffer, ENCLAVE_SIGNATURE_SIZE)) {
@@ -131,7 +145,7 @@ bool furi_hal_crypto_verify_enclave(uint8_t* keys_nb, uint8_t* valid_keys_nb) {
memcmp(buffer, enclave_signature_expected[key_slot], ENCLAVE_SIGNATURE_SIZE) ==
0;
}
furi_hal_crypto_store_unload_key(key_slot + 1);
furi_hal_crypto_enclave_unload_key(key_slot + 1);
}
}
*keys_nb = keys;
@@ -142,7 +156,7 @@ bool furi_hal_crypto_verify_enclave(uint8_t* keys_nb, uint8_t* valid_keys_nb) {
return false;
}
bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) {
bool furi_hal_crypto_enclave_store_key(FuriHalCryptoKey* key, uint8_t* slot) {
furi_assert(key);
furi_assert(slot);
@@ -208,6 +222,16 @@ static void crypto_key_init(uint32_t* key, uint32_t* iv) {
AES1->IVR0 = iv[3];
}
static bool furi_hal_crypto_wait_flag(uint32_t flag) {
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(CRYPTO_TIMEOUT_US);
while(!READ_BIT(AES1->SR, flag)) {
if(furi_hal_cortex_timer_is_expired(timer)) {
return false;
}
}
return true;
}
static bool crypto_process_block(uint32_t* in, uint32_t* out, uint8_t blk_len) {
furi_check((blk_len <= 4) && (blk_len > 0));
@@ -219,15 +243,9 @@ static bool crypto_process_block(uint32_t* in, uint32_t* out, uint8_t blk_len) {
}
}
uint32_t countdown = CRYPTO_TIMEOUT;
while(!READ_BIT(AES1->SR, AES_SR_CCF)) {
if(LL_SYSTICK_IsActiveCounterFlag()) {
countdown--;
}
if(countdown == 0) {
if(!furi_hal_crypto_wait_flag(AES_SR_CCF)) {
return false;
}
}
SET_BIT(AES1->CR, AES_CR_CCFC);
@@ -240,7 +258,7 @@ static bool crypto_process_block(uint32_t* in, uint32_t* out, uint8_t blk_len) {
return true;
}
bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) {
bool furi_hal_crypto_enclave_load_key(uint8_t slot, const uint8_t* iv) {
furi_assert(slot > 0 && slot <= 100);
furi_assert(furi_hal_crypto_mutex);
furi_check(furi_mutex_acquire(furi_hal_crypto_mutex, FuriWaitForever) == FuriStatusOk);
@@ -263,7 +281,7 @@ bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) {
}
}
bool furi_hal_crypto_store_unload_key(uint8_t slot) {
bool furi_hal_crypto_enclave_unload_key(uint8_t slot) {
if(!furi_hal_bt_is_alive()) {
return false;
}
@@ -279,6 +297,27 @@ bool furi_hal_crypto_store_unload_key(uint8_t slot) {
return (shci_state == SHCI_Success);
}
bool furi_hal_crypto_load_key(const uint8_t* key, const uint8_t* iv) {
furi_assert(furi_hal_crypto_mutex);
furi_check(furi_mutex_acquire(furi_hal_crypto_mutex, FuriWaitForever) == FuriStatusOk);
furi_hal_bus_enable(FuriHalBusAES1);
furi_hal_crypto_mode_init_done = false;
crypto_key_init((uint32_t*)key, (uint32_t*)iv);
return true;
}
bool furi_hal_crypto_unload_key(void) {
CLEAR_BIT(AES1->CR, AES_CR_EN);
furi_hal_bus_disable(FuriHalBusAES1);
furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk);
return true;
}
bool furi_hal_crypto_encrypt(const uint8_t* input, uint8_t* output, size_t size) {
bool state = false;
@@ -310,15 +349,9 @@ bool furi_hal_crypto_decrypt(const uint8_t* input, uint8_t* output, size_t size)
SET_BIT(AES1->CR, AES_CR_EN);
uint32_t countdown = CRYPTO_TIMEOUT;
while(!READ_BIT(AES1->SR, AES_SR_CCF)) {
if(LL_SYSTICK_IsActiveCounterFlag()) {
countdown--;
}
if(countdown == 0) {
if(!furi_hal_crypto_wait_flag(AES_SR_CCF)) {
return false;
}
}
SET_BIT(AES1->CR, AES_CR_CCFC);
@@ -343,3 +376,360 @@ bool furi_hal_crypto_decrypt(const uint8_t* input, uint8_t* output, size_t size)
return state;
}
static void crypto_key_init_bswap(uint32_t* key, uint32_t* iv, uint32_t chaining_mode) {
CLEAR_BIT(AES1->CR, AES_CR_EN);
MODIFY_REG(
AES1->CR,
AES_CR_DATATYPE | AES_CR_KEYSIZE | AES_CR_CHMOD,
CRYPTO_DATATYPE_32B | CRYPTO_KEYSIZE_256B | chaining_mode);
if(key != NULL) {
AES1->KEYR7 = __builtin_bswap32(key[0]);
AES1->KEYR6 = __builtin_bswap32(key[1]);
AES1->KEYR5 = __builtin_bswap32(key[2]);
AES1->KEYR4 = __builtin_bswap32(key[3]);
AES1->KEYR3 = __builtin_bswap32(key[4]);
AES1->KEYR2 = __builtin_bswap32(key[5]);
AES1->KEYR1 = __builtin_bswap32(key[6]);
AES1->KEYR0 = __builtin_bswap32(key[7]);
}
AES1->IVR3 = __builtin_bswap32(iv[0]);
AES1->IVR2 = __builtin_bswap32(iv[1]);
AES1->IVR1 = __builtin_bswap32(iv[2]);
AES1->IVR0 = __builtin_bswap32(iv[3]);
}
static bool
furi_hal_crypto_load_key_bswap(const uint8_t* key, const uint8_t* iv, uint32_t chaining_mode) {
furi_assert(furi_hal_crypto_mutex);
furi_check(furi_mutex_acquire(furi_hal_crypto_mutex, FuriWaitForever) == FuriStatusOk);
furi_hal_bus_enable(FuriHalBusAES1);
crypto_key_init_bswap((uint32_t*)key, (uint32_t*)iv, chaining_mode);
return true;
}
static bool wait_for_crypto(void) {
if(!furi_hal_crypto_wait_flag(AES_SR_CCF)) {
return false;
}
SET_BIT(AES1->CR, AES_CR_CCFC);
return true;
}
static bool furi_hal_crypto_process_block_bswap(const uint8_t* in, uint8_t* out, size_t bytes) {
uint32_t block[CRYPTO_BLK_LEN / 4];
memset(block, 0, sizeof(block));
memcpy(block, in, bytes);
block[0] = __builtin_bswap32(block[0]);
block[1] = __builtin_bswap32(block[1]);
block[2] = __builtin_bswap32(block[2]);
block[3] = __builtin_bswap32(block[3]);
if(!crypto_process_block(block, block, CRYPTO_BLK_LEN / 4)) {
return false;
}
block[0] = __builtin_bswap32(block[0]);
block[1] = __builtin_bswap32(block[1]);
block[2] = __builtin_bswap32(block[2]);
block[3] = __builtin_bswap32(block[3]);
memcpy(out, block, bytes);
return true;
}
static bool furi_hal_crypto_process_block_no_read_bswap(const uint8_t* in, size_t bytes) {
uint32_t block[CRYPTO_BLK_LEN / 4];
memset(block, 0, sizeof(block));
memcpy(block, in, bytes);
AES1->DINR = __builtin_bswap32(block[0]);
AES1->DINR = __builtin_bswap32(block[1]);
AES1->DINR = __builtin_bswap32(block[2]);
AES1->DINR = __builtin_bswap32(block[3]);
return wait_for_crypto();
}
static void furi_hal_crypto_ctr_prep_iv(uint8_t* iv) {
/* append counter to IV */
iv[CRYPTO_CTR_IV_LEN] = 0;
iv[CRYPTO_CTR_IV_LEN + 1] = 0;
iv[CRYPTO_CTR_IV_LEN + 2] = 0;
iv[CRYPTO_CTR_IV_LEN + 3] = 1;
}
static bool furi_hal_crypto_ctr_payload(const uint8_t* input, uint8_t* output, size_t length) {
SET_BIT(AES1->CR, AES_CR_EN);
MODIFY_REG(AES1->CR, AES_CR_MODE, CRYPTO_MODE_ENCRYPT);
size_t last_block_bytes = length % CRYPTO_BLK_LEN;
size_t i;
for(i = 0; i < length - last_block_bytes; i += CRYPTO_BLK_LEN) {
if(!furi_hal_crypto_process_block_bswap(&input[i], &output[i], CRYPTO_BLK_LEN)) {
CLEAR_BIT(AES1->CR, AES_CR_EN);
return false;
}
}
if(last_block_bytes > 0) {
if(!furi_hal_crypto_process_block_bswap(&input[i], &output[i], last_block_bytes)) {
CLEAR_BIT(AES1->CR, AES_CR_EN);
return false;
}
}
CLEAR_BIT(AES1->CR, AES_CR_EN);
return true;
}
bool furi_hal_crypto_ctr(
const uint8_t* key,
const uint8_t* iv,
const uint8_t* input,
uint8_t* output,
size_t length) {
/* prepare IV and counter */
uint8_t iv_and_counter[CRYPTO_CTR_IV_LEN + CRYPTO_CTR_CTR_LEN];
memcpy(iv_and_counter, iv, CRYPTO_CTR_IV_LEN); //-V1086
furi_hal_crypto_ctr_prep_iv(iv_and_counter);
/* load key and IV and set the mode to CTR */
if(!furi_hal_crypto_load_key_bswap(key, iv_and_counter, CRYPTO_AES_CTR)) {
furi_hal_crypto_unload_key();
return false;
}
/* process the input and write to output */
bool state = furi_hal_crypto_ctr_payload(input, output, length);
furi_hal_crypto_unload_key();
return state;
}
static void furi_hal_crypto_gcm_prep_iv(uint8_t* iv) {
/* append counter to IV */
iv[CRYPTO_GCM_IV_LEN] = 0;
iv[CRYPTO_GCM_IV_LEN + 1] = 0;
iv[CRYPTO_GCM_IV_LEN + 2] = 0;
iv[CRYPTO_GCM_IV_LEN + 3] = 2;
}
static bool furi_hal_crypto_gcm_init(bool decrypt) {
/* GCM init phase */
MODIFY_REG(AES1->CR, AES_CR_GCMPH, CRYPTO_GCM_PH_INIT);
if(decrypt) {
MODIFY_REG(AES1->CR, AES_CR_MODE, CRYPTO_MODE_DECRYPT);
} else {
MODIFY_REG(AES1->CR, AES_CR_MODE, CRYPTO_MODE_ENCRYPT);
}
SET_BIT(AES1->CR, AES_CR_EN);
if(!wait_for_crypto()) {
CLEAR_BIT(AES1->CR, AES_CR_EN);
return false;
}
return true;
}
static bool furi_hal_crypto_gcm_header(const uint8_t* aad, size_t aad_length) {
/* GCM header phase */
MODIFY_REG(AES1->CR, AES_CR_GCMPH, CRYPTO_GCM_PH_HEADER);
SET_BIT(AES1->CR, AES_CR_EN);
size_t last_block_bytes = aad_length % CRYPTO_BLK_LEN;
size_t i;
for(i = 0; i < aad_length - last_block_bytes; i += CRYPTO_BLK_LEN) {
if(!furi_hal_crypto_process_block_no_read_bswap(&aad[i], CRYPTO_BLK_LEN)) {
CLEAR_BIT(AES1->CR, AES_CR_EN);
return false;
}
}
if(last_block_bytes > 0) {
if(!furi_hal_crypto_process_block_no_read_bswap(&aad[i], last_block_bytes)) {
CLEAR_BIT(AES1->CR, AES_CR_EN);
return false;
}
}
return true;
}
static bool furi_hal_crypto_gcm_payload(
const uint8_t* input,
uint8_t* output,
size_t length,
bool decrypt) {
/* GCM payload phase */
MODIFY_REG(AES1->CR, AES_CR_GCMPH, CRYPTO_GCM_PH_PAYLOAD);
SET_BIT(AES1->CR, AES_CR_EN);
size_t last_block_bytes = length % CRYPTO_BLK_LEN;
size_t i;
for(i = 0; i < length - last_block_bytes; i += CRYPTO_BLK_LEN) {
if(!furi_hal_crypto_process_block_bswap(&input[i], &output[i], CRYPTO_BLK_LEN)) {
CLEAR_BIT(AES1->CR, AES_CR_EN);
return false;
}
}
if(last_block_bytes > 0) {
if(!decrypt) {
MODIFY_REG(
AES1->CR, AES_CR_NPBLB, (CRYPTO_BLK_LEN - last_block_bytes) << AES_CR_NPBLB_Pos);
}
if(!furi_hal_crypto_process_block_bswap(&input[i], &output[i], last_block_bytes)) {
CLEAR_BIT(AES1->CR, AES_CR_EN);
return false;
}
}
return true;
}
static bool furi_hal_crypto_gcm_finish(size_t aad_length, size_t payload_length, uint8_t* tag) {
/* GCM final phase */
MODIFY_REG(AES1->CR, AES_CR_GCMPH, CRYPTO_GCM_PH_FINAL);
uint32_t last_block[CRYPTO_BLK_LEN / 4];
memset(last_block, 0, sizeof(last_block));
last_block[1] = __builtin_bswap32((uint32_t)(aad_length * 8));
last_block[3] = __builtin_bswap32((uint32_t)(payload_length * 8));
if(!furi_hal_crypto_process_block_bswap((uint8_t*)&last_block[0], tag, CRYPTO_BLK_LEN)) {
CLEAR_BIT(AES1->CR, AES_CR_EN);
return false;
}
return true;
}
static bool furi_hal_crypto_gcm_compare_tag(const uint8_t* tag1, const uint8_t* tag2) {
uint8_t diff = 0;
size_t i;
for(i = 0; i < CRYPTO_GCM_TAG_LEN; i++) {
diff |= tag1[i] ^ tag2[i];
}
return (diff == 0);
}
bool furi_hal_crypto_gcm(
const uint8_t* key,
const uint8_t* iv,
const uint8_t* aad,
size_t aad_length,
const uint8_t* input,
uint8_t* output,
size_t length,
uint8_t* tag,
bool decrypt) {
/* GCM init phase */
/* prepare IV and counter */
uint8_t iv_and_counter[CRYPTO_GCM_IV_LEN + CRYPTO_GCM_CTR_LEN];
memcpy(iv_and_counter, iv, CRYPTO_GCM_IV_LEN); //-V1086
furi_hal_crypto_gcm_prep_iv(iv_and_counter);
/* load key and IV and set the mode to CTR */
if(!furi_hal_crypto_load_key_bswap(key, iv_and_counter, CRYPTO_AES_GCM)) {
furi_hal_crypto_unload_key();
return false;
}
if(!furi_hal_crypto_gcm_init(decrypt)) {
furi_hal_crypto_unload_key();
return false;
}
/* GCM header phase */
if(aad_length > 0) {
if(!furi_hal_crypto_gcm_header(aad, aad_length)) {
furi_hal_crypto_unload_key();
return false;
}
}
/* GCM payload phase */
if(!furi_hal_crypto_gcm_payload(input, output, length, decrypt)) {
furi_hal_crypto_unload_key();
return false;
}
/* GCM final phase */
if(!furi_hal_crypto_gcm_finish(aad_length, length, tag)) {
furi_hal_crypto_unload_key();
return false;
}
furi_hal_crypto_unload_key();
return true;
}
FuriHalCryptoGCMState furi_hal_crypto_gcm_encrypt_and_tag(
const uint8_t* key,
const uint8_t* iv,
const uint8_t* aad,
size_t aad_length,
const uint8_t* input,
uint8_t* output,
size_t length,
uint8_t* tag) {
if(!furi_hal_crypto_gcm(key, iv, aad, aad_length, input, output, length, tag, false)) {
memset(output, 0, length);
memset(tag, 0, CRYPTO_GCM_TAG_LEN);
return FuriHalCryptoGCMStateError;
}
return FuriHalCryptoGCMStateOk;
}
FuriHalCryptoGCMState furi_hal_crypto_gcm_decrypt_and_verify(
const uint8_t* key,
const uint8_t* iv,
const uint8_t* aad,
size_t aad_length,
const uint8_t* input,
uint8_t* output,
size_t length,
const uint8_t* tag) {
uint8_t dtag[CRYPTO_GCM_TAG_LEN];
if(!furi_hal_crypto_gcm(key, iv, aad, aad_length, input, output, length, dtag, true)) {
memset(output, 0, length);
return FuriHalCryptoGCMStateError;
}
if(!furi_hal_crypto_gcm_compare_tag(dtag, tag)) {
memset(output, 0, length);
return FuriHalCryptoGCMStateAuthFailure;
}
return FuriHalCryptoGCMStateOk;
}

View File

@@ -283,7 +283,7 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) {
// Signature verification
uint8_t enclave_keys = 0;
uint8_t enclave_valid_keys = 0;
bool enclave_valid = furi_hal_crypto_verify_enclave(&enclave_keys, &enclave_valid_keys);
bool enclave_valid = furi_hal_crypto_enclave_verify(&enclave_keys, &enclave_valid_keys);
if(sep == '.') {
property_value_out(
&property_context, "%d", 3, "enclave", "keys", "valid", enclave_valid_keys);

View File

@@ -1,6 +1,40 @@
/**
* @file furi_hal_crypto.h
*
* Cryptography HAL API
*
* !!! READ THIS FIRST !!!
*
* Flipper was never designed to be secure, nor it passed cryptography audit.
* Despite of the fact that keys are stored in secure enclave there are some
* types of attack that can be performed against AES engine to recover
* keys(theoretical). Also there is no way to securely deliver user keys to
* device and never will be. In addition device is fully open and there is no
* way to guarantee safety of your data, it can be easily dumped with debugger
* or modified code.
*
* Secure enclave on WB series is implemented on core2 FUS side and can be used
* only if core2 alive. Enclave is responsible for storing, loading and
* unloading keys to and from enclave/AES in secure manner(AES engine key
* registers will be locked when key from enclave loaded)
*
* There are 11 keys that we provision at factory:
* - 0 - Master key for secure key delivery. Impossible to use for anything but
* key provisioning. We don't plan to use it too.
* - 1 - 10 - Keys used by firmware. All devices got the same set of keys. You
* also can use them in your applications.
*
* Also there is a slot 11 that we use for device unique key. This slot is
* intentionally left blank till the moment of first use, so you can ensure that
* we don't know your unique key. Also you can provision this key by your self
* with crypto cli or API.
*
* Other slots can be used for your needs. But since enclave is sequential
* append only, we can not guarantee you that slots you want are free. NEVER USE
* THEM FOR PUBLIC APPLICATIONS.
*
* Also you can directly load raw keys into AES engine and use it for your
* needs.
*/
#pragma once
@@ -12,10 +46,27 @@
extern "C" {
#endif
/** Factory provisioned master key slot. Should never be used. */
#define FURI_HAL_CRYPTO_ENCLAVE_MASTER_KEY_SLOT (0u)
/** Factory provisioned keys slot range. All of them are exactly same on all flippers. */
#define FURI_HAL_CRYPTO_ENCLAVE_FACTORY_KEY_SLOT_START (1u)
#define FURI_HAL_CRYPTO_ENCLAVE_FACTORY_KEY_SLOT_END (10u)
/** Device unique key slot. This key generated on first use or provisioned by user. Use furi_hal_crypto_enclave_ensure_key before using this slot. */
#define FURI_HAL_CRYPTO_ENCLAVE_UNIQUE_KEY_SLOT (11u)
/** User key slot range. This slots can be used for your needs, but never use them in public apps. */
#define FURI_HAL_CRYPTO_ENCLAVE_USER_KEY_SLOT_START (12u)
#define FURI_HAL_CRYPTO_ENCLAVE_USER_KEY_SLOT_END (100u)
/** [Deprecated] Indicates availability of advanced crypto functions, will be dropped before v1.0 */
#define FURI_HAL_CRYPTO_ADVANCED_AVAIL 1
/** FuriHalCryptoKey Type */
typedef enum {
FuriHalCryptoKeyTypeMaster, /**< Master key */
FuriHalCryptoKeyTypeSimple, /**< Simple enencrypted key */
FuriHalCryptoKeyTypeSimple, /**< Simple unencrypted key */
FuriHalCryptoKeyTypeEncrypted, /**< Encrypted with Master key */
} FuriHalCryptoKeyType;
@@ -32,40 +83,89 @@ typedef struct {
uint8_t* data;
} FuriHalCryptoKey;
/** Initialize cryptography layer This includes AES engines, PKA and RNG
*/
/** FuriHalCryptoGCMState Result of a GCM operation */
typedef enum {
FuriHalCryptoGCMStateOk, /**< operation successful */
FuriHalCryptoGCMStateError, /**< error during encryption/decryption */
FuriHalCryptoGCMStateAuthFailure, /**< tags do not match, auth failed */
} FuriHalCryptoGCMState;
/** Initialize cryptography layer(includes AES engines, PKA and RNG) */
void furi_hal_crypto_init();
bool furi_hal_crypto_verify_enclave(uint8_t* keys_nb, uint8_t* valid_keys_nb);
bool furi_hal_crypto_verify_key(uint8_t key_slot);
/** Store key in crypto storage
/** Verify factory provisioned keys
*
* @param key FuriHalCryptoKey to store. Only Master, Simple or
* Encrypted
* @param slot pinter to int where store slot number will be saved
* @param keys_nb The keys number of
* @param valid_keys_nb The valid keys number of
*
* @return true if all enclave keys are intact, false otherwise
*/
bool furi_hal_crypto_enclave_verify(uint8_t* keys_nb, uint8_t* valid_keys_nb);
/** Ensure that requested slot and slots before this slot contains keys.
*
* This function is used to provision FURI_HAL_CRYPTO_ENCLAVE_UNIQUE_KEY_SLOT. Also you
* may want to use it to generate some unique keys in user key slot range.
*
* @warning Because of the sequential nature of the secure enclave this
* method will generate key for all slots from
* FURI_HAL_CRYPTO_ENCLAVE_FACTORY_KEY_SLOT_END to the slot your requested.
* Keys are generated using on-chip RNG.
*
* @param[in] key_slot The key slot to enclave
*
* @return true if key exists or created, false if enclave corrupted
*/
bool furi_hal_crypto_enclave_ensure_key(uint8_t key_slot);
/** Store key in crypto enclave
*
* @param key FuriHalCryptoKey to be stored
* @param slot pointer to int where enclave slot will be stored
*
* @return true on success
*/
bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot);
bool furi_hal_crypto_enclave_store_key(FuriHalCryptoKey* key, uint8_t* slot);
/** Init AES engine and load key from crypto store
/** Init AES engine and load key from crypto enclave
*
* @param slot store slot number
* @warning Use only with furi_hal_crypto_enclave_unload_key()
*
* @param slot enclave slot
* @param[in] iv pointer to 16 bytes Initialization Vector data
*
* @return true on success
*/
bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv);
bool furi_hal_crypto_enclave_load_key(uint8_t slot, const uint8_t* iv);
/** Unload key engine and deinit AES engine
/** Unload key and deinit AES engine
*
* @param slot store slot number
* @warning Use only with furi_hal_crypto_enclave_load_key()
*
* @param slot enclave slot
*
* @return true on success
*/
bool furi_hal_crypto_store_unload_key(uint8_t slot);
bool furi_hal_crypto_enclave_unload_key(uint8_t slot);
/** Init AES engine and load supplied key
*
* @warning Use only with furi_hal_crypto_unload_key()
*
* @param[in] key pointer to 32 bytes key data
* @param[in] iv pointer to 16 bytes Initialization Vector data
*
* @return true on success
*/
bool furi_hal_crypto_load_key(const uint8_t* key, const uint8_t* iv);
/** Unload key and de-init AES engine
*
* @warning Use this function only with furi_hal_crypto_load_key()
*
* @return true on success
*/
bool furi_hal_crypto_unload_key(void);
/** Encrypt data
*
@@ -87,6 +187,109 @@ bool furi_hal_crypto_encrypt(const uint8_t* input, uint8_t* output, size_t size)
*/
bool furi_hal_crypto_decrypt(const uint8_t* input, uint8_t* output, size_t size);
/** Encrypt the input using AES-CTR
*
* Decryption can be performed by supplying the ciphertext as input. Inits and
* deinits the AES engine internally.
*
* @param[in] key pointer to 32 bytes key data
* @param[in] iv pointer to 12 bytes Initialization Vector data
* @param[in] input pointer to input data
* @param[out] output pointer to output data
* @param length length of the input and output in bytes
*
* @return true on success
*/
bool furi_hal_crypto_ctr(
const uint8_t* key,
const uint8_t* iv,
const uint8_t* input,
uint8_t* output,
size_t length);
/** Encrypt/decrypt the input using AES-GCM
*
* When decrypting the tag generated needs to be compared to the tag attached to
* the ciphertext in a constant-time fashion. If the tags are not equal, the
* decryption failed and the plaintext returned needs to be discarded. Inits and
* deinits the AES engine internally.
*
* @param[in] key pointer to 32 bytes key data
* @param[in] iv pointer to 12 bytes Initialization Vector data
* @param[in] aad pointer to additional authentication data
* @param aad_length length of the additional authentication data in bytes
* @param[in] input pointer to input data
* @param[out] output pointer to output data
* @param length length of the input and output in bytes
* @param[out] tag pointer to 16 bytes space for the tag
* @param decrypt true for decryption, false otherwise
*
* @return true on success
*/
bool furi_hal_crypto_gcm(
const uint8_t* key,
const uint8_t* iv,
const uint8_t* aad,
size_t aad_length,
const uint8_t* input,
uint8_t* output,
size_t length,
uint8_t* tag,
bool decrypt);
/** Encrypt the input using AES-GCM and generate a tag
*
* Inits and deinits the AES engine internally.
*
* @param[in] key pointer to 32 bytes key data
* @param[in] iv pointer to 12 bytes Initialization Vector data
* @param[in] aad pointer to additional authentication data
* @param aad_length length of the additional authentication data in bytes
* @param[in] input pointer to input data
* @param[out] output pointer to output data
* @param length length of the input and output in bytes
* @param[out] tag pointer to 16 bytes space for the tag
*
* @return FuriHalCryptoGCMStateOk on success, FuriHalCryptoGCMStateError on
* failure
*/
FuriHalCryptoGCMState furi_hal_crypto_gcm_encrypt_and_tag(
const uint8_t* key,
const uint8_t* iv,
const uint8_t* aad,
size_t aad_length,
const uint8_t* input,
uint8_t* output,
size_t length,
uint8_t* tag);
/** Decrypt the input using AES-GCM and verify the provided tag
*
* Inits and deinits the AES engine internally.
*
* @param[in] key pointer to 32 bytes key data
* @param[in] iv pointer to 12 bytes Initialization Vector data
* @param[in] aad pointer to additional authentication data
* @param aad_length length of the additional authentication data in bytes
* @param[in] input pointer to input data
* @param[out] output pointer to output data
* @param length length of the input and output in bytes
* @param[out] tag pointer to 16 bytes tag
*
* @return FuriHalCryptoGCMStateOk on success, FuriHalCryptoGCMStateError on
* failure, FuriHalCryptoGCMStateAuthFailure if the tag does not
* match
*/
FuriHalCryptoGCMState furi_hal_crypto_gcm_decrypt_and_verify(
const uint8_t* key,
const uint8_t* iv,
const uint8_t* aad,
size_t aad_length,
const uint8_t* input,
uint8_t* output,
size_t length,
const uint8_t* tag);
#ifdef __cplusplus
}
#endif

View File

@@ -122,7 +122,7 @@ static bool subghz_keystore_read_file(SubGhzKeystore* instance, Stream* stream,
do {
if(iv) {
if(!furi_hal_crypto_store_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv)) {
if(!furi_hal_crypto_enclave_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv)) {
FURI_LOG_E(TAG, "Unable to load decryption key");
break;
}
@@ -181,7 +181,7 @@ static bool subghz_keystore_read_file(SubGhzKeystore* instance, Stream* stream,
}
} while(ret > 0 && result);
if(iv) furi_hal_crypto_store_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT);
if(iv) furi_hal_crypto_enclave_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT);
} while(false);
free(encrypted_line);
@@ -280,7 +280,7 @@ bool subghz_keystore_save(SubGhzKeystore* instance, const char* file_name, uint8
subghz_keystore_mess_with_iv(iv);
if(!furi_hal_crypto_store_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv)) {
if(!furi_hal_crypto_enclave_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv)) {
FURI_LOG_E(TAG, "Unable to load encryption key");
break;
}
@@ -326,7 +326,7 @@ bool subghz_keystore_save(SubGhzKeystore* instance, const char* file_name, uint8
stream_write_char(stream, '\n');
encrypted_line_count++;
}
furi_hal_crypto_store_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT);
furi_hal_crypto_enclave_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT);
size_t total_keys = SubGhzKeyArray_size(instance->data);
result = encrypted_line_count == total_keys;
if(result) {
@@ -421,7 +421,7 @@ bool subghz_keystore_raw_encrypted_save(
subghz_keystore_mess_with_iv(iv);
if(!furi_hal_crypto_store_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv)) {
if(!furi_hal_crypto_enclave_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv)) {
FURI_LOG_E(TAG, "Unable to load encryption key");
break;
}
@@ -474,7 +474,7 @@ bool subghz_keystore_raw_encrypted_save(
flipper_format_free(output_flipper_format);
furi_hal_crypto_store_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT);
furi_hal_crypto_enclave_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT);
if(!result) break;
@@ -576,7 +576,7 @@ bool subghz_keystore_raw_get_data(const char* file_name, size_t offset, uint8_t*
}
}
if(!furi_hal_crypto_store_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv)) {
if(!furi_hal_crypto_enclave_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv)) {
FURI_LOG_E(TAG, "Unable to load encryption key");
break;
}
@@ -604,7 +604,7 @@ bool subghz_keystore_raw_get_data(const char* file_name, size_t offset, uint8_t*
memcpy(data, (uint8_t*)decrypted_line + (offset - (offset / 16) * 16), len);
} while(0);
furi_hal_crypto_store_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT);
furi_hal_crypto_enclave_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT);
if(decrypted) result = true;
} while(0);
flipper_format_free(flipper_format);

View File

@@ -2,6 +2,7 @@ import os
import re
from dataclasses import dataclass, field
from enum import Enum
from fbt.util import resolve_real_dir_node
from typing import Callable, ClassVar, List, Optional, Tuple, Union
@@ -147,7 +148,7 @@ class AppManager:
FlipperApplication(
*args,
**kw,
_appdir=app_dir_node,
_appdir=resolve_real_dir_node(app_dir_node),
_apppath=os.path.dirname(app_manifest_path),
_appmanager=self,
),

View File

@@ -45,7 +45,7 @@ def single_quote(arg_list):
return " ".join(f"'{arg}'" if " " in arg else str(arg) for arg in arg_list)
def extract_abs_dir(node):
def resolve_real_dir_node(node):
if isinstance(node, SCons.Node.FS.EntryProxy):
node = node.get()
@@ -53,15 +53,7 @@ def extract_abs_dir(node):
if os.path.exists(repo_dir.abspath):
return repo_dir
def extract_abs_dir_path(node):
abs_dir_node = extract_abs_dir(node)
if abs_dir_node is None:
raise StopError(f"Can't find absolute path for {node.name}")
# Don't return abspath attribute (type is str), it will break in
# OverrideEnvironment.subst_list() by splitting path on spaces
return abs_dir_node
raise StopError(f"Can't find absolute path for {node.name} ({node})")
def path_as_posix(path):

View File

@@ -8,11 +8,14 @@ from SCons.Errors import StopError
def icons_emitter(target, source, env):
icons_src = env.GlobRecursive("*.png", env["ICON_SRC_DIR"])
icons_src += env.GlobRecursive("frame_rate", env["ICON_SRC_DIR"])
target = [
target[0].File(env.subst("${ICON_FILE_NAME}.c")),
target[0].File(env.subst("${ICON_FILE_NAME}.h")),
]
return target, source
return target, icons_src
def proto_emitter(target, source, env):
@@ -104,21 +107,16 @@ def proto_ver_generator(target, source, env):
def CompileIcons(env, target_dir, source_dir, *, icon_bundle_name="assets_icons"):
# Gathering icons sources
try:
os.mkdir(str(source_dir))
except FileExistsError:
pass
icons_src = env.GlobRecursive("*.png", source_dir)
icons_src += env.GlobRecursive("frame_rate", source_dir)
icons = env.IconBuilder(
return env.IconBuilder(
target_dir,
source_dir,
None,
ICON_SRC_DIR=source_dir,
ICON_FILE_NAME=icon_bundle_name,
)
env.Depends(icons, icons_src)
return icons
def generate(env):
@@ -141,7 +139,7 @@ def generate(env):
BUILDERS={
"IconBuilder": Builder(
action=Action(
'${PYTHON3} ${ASSETS_COMPILER} icons ${ABSPATHGETTERFUNC(SOURCE)} ${TARGET.dir} --filename "${ICON_FILE_NAME}"',
'${PYTHON3} ${ASSETS_COMPILER} icons ${ICON_SRC_DIR} ${TARGET.dir} --filename "${ICON_FILE_NAME}"',
"${ICONSCOMSTR}",
),
emitter=icons_emitter,

View File

@@ -11,7 +11,7 @@ from fbt.appmanifest import FlipperApplication, FlipperAppType, FlipperManifestE
from fbt.elfmanifest import assemble_manifest_data
from fbt.fapassets import FileBundler
from fbt.sdk.cache import SdkCache
from fbt.util import extract_abs_dir_path
from fbt.util import resolve_real_dir_node
from SCons.Action import Action
from SCons.Builder import Builder
from SCons.Errors import UserError
@@ -50,7 +50,8 @@ class AppBuilder:
def _setup_app_env(self):
self.app_env = self.fw_env.Clone(
FAP_SRC_DIR=self.app._appdir, FAP_WORK_DIR=self.app_work_dir
FAP_SRC_DIR=self.app._appdir,
FAP_WORK_DIR=self.app_work_dir,
)
self.app_env.VariantDir(self.app_work_dir, self.app._appdir, duplicate=False)
@@ -119,7 +120,7 @@ class AppBuilder:
CPPDEFINES=lib_def.cdefines,
CPPPATH=list(
map(
lambda cpath: extract_abs_dir_path(self.app._appdir.Dir(cpath)),
lambda cpath: resolve_real_dir_node(self.app._appdir.Dir(cpath)),
lib_def.cincludes,
)
),
@@ -133,7 +134,7 @@ class AppBuilder:
def _build_app(self):
self.app_env.Append(
LIBS=[*self.app.fap_libs, *self.private_libs],
CPPPATH=self.app_env.Dir(self.app_work_dir),
CPPPATH=[self.app_env.Dir(self.app_work_dir), self.app._appdir],
)
app_sources = list(

View File

@@ -26,6 +26,10 @@ class Programmer(ABC):
def option_bytes_set(self, file_path: str) -> bool:
pass
@abstractmethod
def option_bytes_recover(self) -> bool:
pass
@abstractmethod
def otp_write(self, address: int, file_path: str) -> bool:
pass

View File

@@ -44,11 +44,11 @@ class OpenOCDProgrammer(Programmer):
self.logger = logging.getLogger()
def reset(self, mode: Programmer.RunMode = Programmer.RunMode.Run) -> bool:
stm32 = STM32WB55()
stm32 = STM32WB55(self.openocd)
if mode == Programmer.RunMode.Run:
stm32.reset(self.openocd, stm32.RunMode.Run)
stm32.reset(stm32.RunMode.Run)
elif mode == Programmer.RunMode.Stop:
stm32.reset(self.openocd, stm32.RunMode.Init)
stm32.reset(stm32.RunMode.Init)
else:
raise Exception("Unknown mode")
@@ -96,11 +96,11 @@ class OpenOCDProgrammer(Programmer):
def option_bytes_validate(self, file_path: str) -> bool:
# Registers
stm32 = STM32WB55()
stm32 = STM32WB55(self.openocd)
# OpenOCD
self.openocd.start()
stm32.reset(self.openocd, stm32.RunMode.Init)
stm32.reset(stm32.RunMode.Init)
# Generate Option Bytes data
ob_data = OptionBytesData(file_path)
@@ -133,7 +133,7 @@ class OpenOCDProgrammer(Programmer):
self._ob_print_diff_table(ob_reference, ob_compare, self.logger.error)
# Stop OpenOCD
stm32.reset(self.openocd, stm32.RunMode.Run)
stm32.reset(stm32.RunMode.Run)
self.openocd.stop()
return return_code
@@ -143,11 +143,11 @@ class OpenOCDProgrammer(Programmer):
def option_bytes_set(self, file_path: str) -> bool:
# Registers
stm32 = STM32WB55()
stm32 = STM32WB55(self.openocd)
# OpenOCD
self.openocd.start()
stm32.reset(self.openocd, stm32.RunMode.Init)
stm32.reset(stm32.RunMode.Init)
# Generate Option Bytes data
ob_data = OptionBytesData(file_path)
@@ -159,11 +159,11 @@ class OpenOCDProgrammer(Programmer):
ob_dwords = int(ob_length / 8)
# Clear flash errors
stm32.clear_flash_errors(self.openocd)
stm32.clear_flash_errors()
# Unlock Flash and Option Bytes
stm32.flash_unlock(self.openocd)
stm32.option_bytes_unlock(self.openocd)
stm32.flash_unlock()
stm32.option_bytes_unlock()
ob_need_to_apply = False
@@ -194,16 +194,16 @@ class OpenOCDProgrammer(Programmer):
self.openocd.write_32(device_reg_addr, ob_value)
if ob_need_to_apply:
stm32.option_bytes_apply(self.openocd)
stm32.option_bytes_apply()
else:
self.logger.info("Option Bytes are already correct")
# Load Option Bytes
# That will reset and also lock the Option Bytes and the Flash
stm32.option_bytes_load(self.openocd)
stm32.option_bytes_load()
# Stop OpenOCD
stm32.reset(self.openocd, stm32.RunMode.Run)
stm32.reset(stm32.RunMode.Run)
self.openocd.stop()
return True
@@ -233,11 +233,10 @@ class OpenOCDProgrammer(Programmer):
self.logger.debug(f"Data: {data.hex().upper()}")
# Start OpenOCD
oocd = self.openocd
oocd.start()
self.openocd.start()
# Registers
stm32 = STM32WB55()
stm32 = STM32WB55(self.openocd)
try:
# Check that OTP is empty for the given address
@@ -245,7 +244,7 @@ class OpenOCDProgrammer(Programmer):
already_written = True
for i in range(0, data_size, 4):
file_word = int.from_bytes(data[i : i + 4], "little")
device_word = oocd.read_32(address + i)
device_word = self.openocd.read_32(address + i)
if device_word != 0xFFFFFFFF and device_word != file_word:
self.logger.error(
f"OTP memory at {address + i:08X} is not empty: {device_word:08X}"
@@ -260,7 +259,7 @@ class OpenOCDProgrammer(Programmer):
return OpenOCDProgrammerResult.Success
self.reset(self.RunMode.Stop)
stm32.clear_flash_errors(oocd)
stm32.clear_flash_errors()
# Write OTP memory by 8 bytes
for i in range(0, data_size, 8):
@@ -269,14 +268,14 @@ class OpenOCDProgrammer(Programmer):
self.logger.debug(
f"Writing {word_1:08X} {word_2:08X} to {address + i:08X}"
)
stm32.write_flash_64(oocd, address + i, word_1, word_2)
stm32.write_flash_64(address + i, word_1, word_2)
# Validate OTP memory
validation_result = True
for i in range(0, data_size, 4):
file_word = int.from_bytes(data[i : i + 4], "little")
device_word = oocd.read_32(address + i)
device_word = self.openocd.read_32(address + i)
if file_word != device_word:
self.logger.error(
f"Validation failed: {file_word:08X} != {device_word:08X} at {address + i:08X}"
@@ -284,11 +283,21 @@ class OpenOCDProgrammer(Programmer):
validation_result = False
finally:
# Stop OpenOCD
stm32.reset(oocd, stm32.RunMode.Run)
oocd.stop()
stm32.reset(stm32.RunMode.Run)
self.openocd.stop()
return (
OpenOCDProgrammerResult.Success
if validation_result
else OpenOCDProgrammerResult.ErrorValidation
)
def option_bytes_recover(self) -> bool:
try:
self.openocd.start()
stm32 = STM32WB55(self.openocd)
stm32.reset(stm32.RunMode.Halt)
stm32.option_bytes_recover()
return True
finally:
self.openocd.stop()

View File

@@ -16,6 +16,7 @@ class Register32:
self.names = [definition.name for definition in definition_list] # typecheck
self.address = address
self.definition_list = definition_list
self.openocd = None
# Validate that the definitions are not overlapping
for i in range(len(definition_list)):
@@ -76,6 +77,14 @@ class Register32:
def __dir__(self):
return self.names
def set_openocd(self, openocd: OpenOCD):
self.openocd = openocd
def get_openocd(self) -> OpenOCD:
if self.openocd is None:
raise RuntimeError("OpenOCD is not installed")
return self.openocd
def set(self, value: int):
for definition in self.definition_list:
definition.value = (value >> definition.offset) & (
@@ -88,8 +97,8 @@ class Register32:
value |= definition.value << definition.offset
return value
def load(self, openocd: OpenOCD):
self.set(openocd.read_32(self.address))
def load(self):
self.set(self.get_openocd().read_32(self.address))
def store(self, openocd: OpenOCD):
openocd.write_32(self.address, self.get())
def store(self):
self.get_openocd().write_32(self.address, self.get())

View File

@@ -108,23 +108,27 @@ class STM32WB55:
15: None, # Core 2 Options
}
def __init__(self):
def __init__(self, openocd: OpenOCD):
self.openocd = openocd
self.logger = logging.getLogger("STM32WB55")
self.FLASH_CR.set_openocd(self.openocd)
self.FLASH_SR.set_openocd(self.openocd)
class RunMode(Enum):
Init = "init"
Run = "run"
Halt = "halt"
def reset(self, oocd: OpenOCD, mode: RunMode):
def reset(self, mode: RunMode):
self.logger.debug("Resetting device")
oocd.send_tcl(f"reset {mode.value}")
self.openocd.send_tcl(f"reset {mode.value}")
def clear_flash_errors(self, oocd: OpenOCD):
def clear_flash_errors(self):
# Errata 2.2.9: Flash OPTVERR flag is always set after system reset
# And also clear all other flash error flags
self.logger.debug("Resetting flash errors")
self.FLASH_SR.load(oocd)
self.FLASH_SR.load()
self.FLASH_SR.OP_ERR = 1
self.FLASH_SR.PROG_ERR = 1
self.FLASH_SR.WRP_ERR = 1
@@ -135,51 +139,51 @@ class STM32WB55:
self.FLASH_SR.FAST_ERR = 1
self.FLASH_SR.RD_ERR = 1
self.FLASH_SR.OPTV_ERR = 1
self.FLASH_SR.store(oocd)
self.FLASH_SR.store()
def flash_unlock(self, oocd: OpenOCD):
def flash_unlock(self):
# Check if flash is already unlocked
self.FLASH_CR.load(oocd)
self.FLASH_CR.load()
if self.FLASH_CR.LOCK == 0:
self.logger.debug("Flash is already unlocked")
return
# Unlock flash
self.logger.debug("Unlocking Flash")
oocd.write_32(self.FLASH_KEYR, self.FLASH_UNLOCK_KEY1)
oocd.write_32(self.FLASH_KEYR, self.FLASH_UNLOCK_KEY2)
self.openocd.write_32(self.FLASH_KEYR, self.FLASH_UNLOCK_KEY1)
self.openocd.write_32(self.FLASH_KEYR, self.FLASH_UNLOCK_KEY2)
# Check if flash is unlocked
self.FLASH_CR.load(oocd)
self.FLASH_CR.load()
if self.FLASH_CR.LOCK == 0:
self.logger.debug("Flash unlocked")
else:
self.logger.error("Flash unlock failed")
raise Exception("Flash unlock failed")
def option_bytes_unlock(self, oocd: OpenOCD):
def option_bytes_unlock(self):
# Check if options is already unlocked
self.FLASH_CR.load(oocd)
self.FLASH_CR.load()
if self.FLASH_CR.OPT_LOCK == 0:
self.logger.debug("Options is already unlocked")
return
# Unlock options
self.logger.debug("Unlocking Options")
oocd.write_32(self.FLASH_OPTKEYR, self.FLASH_UNLOCK_OPTKEY1)
oocd.write_32(self.FLASH_OPTKEYR, self.FLASH_UNLOCK_OPTKEY2)
self.openocd.write_32(self.FLASH_OPTKEYR, self.FLASH_UNLOCK_OPTKEY1)
self.openocd.write_32(self.FLASH_OPTKEYR, self.FLASH_UNLOCK_OPTKEY2)
# Check if options is unlocked
self.FLASH_CR.load(oocd)
self.FLASH_CR.load()
if self.FLASH_CR.OPT_LOCK == 0:
self.logger.debug("Options unlocked")
else:
self.logger.error("Options unlock failed")
raise Exception("Options unlock failed")
def option_bytes_lock(self, oocd: OpenOCD):
def option_bytes_lock(self):
# Check if options is already locked
self.FLASH_CR.load(oocd)
self.FLASH_CR.load()
if self.FLASH_CR.OPT_LOCK == 1:
self.logger.debug("Options is already locked")
return
@@ -187,19 +191,19 @@ class STM32WB55:
# Lock options
self.logger.debug("Locking Options")
self.FLASH_CR.OPT_LOCK = 1
self.FLASH_CR.store(oocd)
self.FLASH_CR.store()
# Check if options is locked
self.FLASH_CR.load(oocd)
self.FLASH_CR.load()
if self.FLASH_CR.OPT_LOCK == 1:
self.logger.debug("Options locked")
else:
self.logger.error("Options lock failed")
raise Exception("Options lock failed")
def flash_lock(self, oocd: OpenOCD):
def flash_lock(self):
# Check if flash is already locked
self.FLASH_CR.load(oocd)
self.FLASH_CR.load()
if self.FLASH_CR.LOCK == 1:
self.logger.debug("Flash is already locked")
return
@@ -207,31 +211,31 @@ class STM32WB55:
# Lock flash
self.logger.debug("Locking Flash")
self.FLASH_CR.LOCK = 1
self.FLASH_CR.store(oocd)
self.FLASH_CR.store()
# Check if flash is locked
self.FLASH_CR.load(oocd)
self.FLASH_CR.load()
if self.FLASH_CR.LOCK == 1:
self.logger.debug("Flash locked")
else:
self.logger.error("Flash lock failed")
raise Exception("Flash lock failed")
def option_bytes_apply(self, oocd: OpenOCD):
def option_bytes_apply(self):
self.logger.debug("Applying Option Bytes")
self.FLASH_CR.load(oocd)
self.FLASH_CR.load()
self.FLASH_CR.OPT_STRT = 1
self.FLASH_CR.store(oocd)
self.FLASH_CR.store()
# Wait for Option Bytes to be applied
self.flash_wait_for_operation(oocd)
self.flash_wait_for_operation()
def option_bytes_load(self, oocd: OpenOCD):
def option_bytes_load(self):
self.logger.debug("Loading Option Bytes")
self.FLASH_CR.load(oocd)
self.FLASH_CR.load()
self.FLASH_CR.OBL_LAUNCH = 1
self.FLASH_CR.store(oocd)
self.FLASH_CR.store()
def option_bytes_id_to_address(self, id: int) -> int:
# Check if this option byte (dword) is mapped to a register
@@ -241,16 +245,16 @@ class STM32WB55:
return device_reg_addr
def flash_wait_for_operation(self, oocd: OpenOCD):
def flash_wait_for_operation(self):
# Wait for flash operation to complete
# TODO: timeout
while True:
self.FLASH_SR.load(oocd)
self.FLASH_SR.load()
if self.FLASH_SR.BSY == 0:
break
def flash_dump_status_register(self, oocd: OpenOCD):
self.FLASH_SR.load(oocd)
def flash_dump_status_register(self):
self.FLASH_SR.load()
self.logger.info(f"FLASH_SR: {self.FLASH_SR.get():08x}")
if self.FLASH_SR.EOP:
self.logger.info(" End of operation")
@@ -283,70 +287,87 @@ class STM32WB55:
if self.FLASH_SR.PESD:
self.logger.info(" Programming / erase operation suspended.")
def write_flash_64(self, oocd: OpenOCD, address: int, word_1: int, word_2: int):
def write_flash_64(self, address: int, word_1: int, word_2: int):
self.logger.debug(f"Writing flash at address {address:08x}")
if address % 8 != 0:
self.logger.error("Address must be aligned to 8 bytes")
raise Exception("Address must be aligned to 8 bytes")
if word_1 == oocd.read_32(address) and word_2 == oocd.read_32(address + 4):
if word_1 == self.openocd.read_32(address) and word_2 == self.openocd.read_32(
address + 4
):
self.logger.debug("Data is already programmed")
return
self.flash_unlock(oocd)
self.flash_unlock()
# Check that no flash main memory operation is ongoing by checking the BSY bit
self.FLASH_SR.load(oocd)
self.FLASH_SR.load()
if self.FLASH_SR.BSY:
self.logger.error("Flash is busy")
self.flash_dump_status_register(oocd)
self.flash_dump_status_register()
raise Exception("Flash is busy")
# Enable end of operation interrupts and error interrupts
self.FLASH_CR.load(oocd)
self.FLASH_CR.load()
self.FLASH_CR.EOPIE = 1
self.FLASH_CR.ERRIE = 1
self.FLASH_CR.store(oocd)
self.FLASH_CR.store()
# Check that flash memory program and erase operations are allowed
if self.FLASH_SR.PESD:
self.logger.error("Flash operations are not allowed")
self.flash_dump_status_register(oocd)
self.flash_dump_status_register()
raise Exception("Flash operations are not allowed")
# Check and clear all error programming flags due to a previous programming.
self.clear_flash_errors(oocd)
self.clear_flash_errors()
# Set the PG bit in the Flash memory control register (FLASH_CR)
self.FLASH_CR.load(oocd)
self.FLASH_CR.load()
self.FLASH_CR.PG = 1
self.FLASH_CR.store(oocd)
self.FLASH_CR.store()
# Perform the data write operation at the desired memory address, only double word (64 bits) can be programmed.
# Write the first word
oocd.send_tcl(f"mww 0x{address:08x} 0x{word_1:08x}")
self.openocd.send_tcl(f"mww 0x{address:08x} 0x{word_1:08x}")
# Write the second word
oocd.send_tcl(f"mww 0x{(address + 4):08x} 0x{word_2:08x}")
self.openocd.send_tcl(f"mww 0x{(address + 4):08x} 0x{word_2:08x}")
# Wait for the BSY bit to be cleared
self.flash_wait_for_operation(oocd)
self.flash_wait_for_operation()
# Check that EOP flag is set in the FLASH_SR register
self.FLASH_SR.load(oocd)
self.FLASH_SR.load()
if not self.FLASH_SR.EOP:
self.logger.error("Flash operation failed")
self.flash_dump_status_register(oocd)
self.flash_dump_status_register()
raise Exception("Flash operation failed")
# Clear the EOP flag
self.FLASH_SR.load(oocd)
self.FLASH_SR.load()
self.FLASH_SR.EOP = 1
self.FLASH_SR.store(oocd)
self.FLASH_SR.store()
# Clear the PG bit in the FLASH_CR register
self.FLASH_CR.load(oocd)
self.FLASH_CR.load()
self.FLASH_CR.PG = 0
self.FLASH_CR.store(oocd)
self.FLASH_CR.store()
self.flash_lock(oocd)
self.flash_lock()
def option_bytes_recover(self):
self.openocd.send_tcl("mww 0x58004010 0x8000") # set OPTVERR to reset
# Replace flash_unlock and option_bytes_unlock with the following lines, if this does not work
# self.openocd.send_tcl("mww 0x58004008 0x45670123") # unlock FLASH
# self.openocd.send_tcl("mww 0x58004008 0xCDEF89AB")
# self.openocd.send_tcl("mww 0x5800400c 0x08192A3B") # unlock OB
# self.openocd.send_tcl("mww 0x5800400c 0x4C5D6E7F")
self.flash_unlock()
self.option_bytes_unlock()
self.openocd.send_tcl("mmw 0x58004020 0x3ffff1aa 0xffffffff") # Reset OB
self.openocd.send_tcl("mww 0x5800402c 0xff") # Reset WRP1AR
self.openocd.send_tcl("mww 0x58004030 0xff") # Reset WRP1BR
self.openocd.send_tcl("mmw 0x58004014 0x00020000 0") # OPTSTRT
self.openocd.send_tcl("mmw 0x58004014 0x08000000 0") # OBL_LAUNCH

View File

@@ -22,6 +22,12 @@ class Main(App):
self.parser_set = self.subparsers.add_parser("set", help="Set Option Bytes")
self._add_args(self.parser_set)
self.parser_set.set_defaults(func=self.set)
# Set command
self.parser_recover = self.subparsers.add_parser(
"recover", help="Recover Option Bytes"
)
self._add_args(self.parser_recover)
self.parser_recover.set_defaults(func=self.recover)
def _add_args(self, parser):
parser.add_argument(
@@ -75,6 +81,20 @@ class Main(App):
return return_code
def recover(self):
self.logger.info("Setting Option Bytes")
# OpenOCD
openocd = OpenOCDProgrammer(
self.args.interface,
self.args.port_base,
self.args.serial,
)
openocd.option_bytes_recover()
return 0
if __name__ == "__main__":
Main()()

View File

@@ -1,12 +1,11 @@
from SCons.Platform import TempFileMunge
from SCons.Node import FS
from SCons.Errors import UserError
import os
import multiprocessing
import os
import pathlib
from SCons.Errors import UserError
from SCons.Node import FS
from SCons.Platform import TempFileMunge
SetOption("num_jobs", multiprocessing.cpu_count())
SetOption("max_drift", 1)
# SetOption("silent", False)
@@ -67,16 +66,15 @@ core_env.Append(CPPDEFINES=GetOption("extra_defines"))
# Now we can import stuff bundled with SDK - it was added to sys.path by ufbt_state
from fbt.util import (
tempfile_arg_esc_func,
single_quote,
extract_abs_dir,
extract_abs_dir_path,
wrap_tempfile,
path_as_posix,
)
from fbt.appmanifest import FlipperAppType, FlipperApplication
from fbt.appmanifest import FlipperApplication, FlipperAppType
from fbt.sdk.cache import SdkCache
from fbt.util import (
path_as_posix,
resolve_real_dir_node,
single_quote,
tempfile_arg_esc_func,
wrap_tempfile,
)
# Base environment with all tools loaded from SDK
env = core_env.Clone(
@@ -107,7 +105,7 @@ env = core_env.Clone(
PROGSUFFIX=".elf",
TEMPFILEARGESCFUNC=tempfile_arg_esc_func,
SINGLEQUOTEFUNC=single_quote,
ABSPATHGETTERFUNC=extract_abs_dir_path,
ABSPATHGETTERFUNC=resolve_real_dir_node,
APPS=[],
UFBT_API_VERSION=SdkCache(
core_env.subst("$SDK_DEFINITION"), load_version_only=True
@@ -277,7 +275,7 @@ for app in known_extapps:
continue
app_artifacts = appenv.BuildAppElf(app)
app_src_dir = extract_abs_dir(app_artifacts.app._appdir)
app_src_dir = resolve_real_dir_node(app_artifacts.app._appdir)
app_artifacts.installer = [
appenv.Install(app_src_dir.Dir("dist"), app_artifacts.compact),
appenv.Install(app_src_dir.Dir("dist").Dir("debug"), app_artifacts.debug),
@@ -348,6 +346,9 @@ appenv.PhonyTarget(
'${PYTHON3} "${FBT_SCRIPT_DIR}/serial_cli.py" -p ${FLIP_PORT}',
)
# Update WiFi devboard firmware
dist_env.PhonyTarget("devboard_flash", "${PYTHON3} ${FBT_SCRIPT_DIR}/wifi_board.py")
# Linter
dist_env.PhonyTarget(

View File

@@ -26,6 +26,8 @@ Flashing & debugging:
Install firmware using self-update package
debug, debug_other, blackmagic:
Start GDB
devboard_flash:
Update WiFi dev board with the latest firmware
Other:
cli:

View File

@@ -3,7 +3,7 @@ from fbt.util import (
tempfile_arg_esc_func,
single_quote,
wrap_tempfile,
extract_abs_dir_path,
resolve_real_dir_node,
)
import os
@@ -59,7 +59,7 @@ coreenv = VAR_ENV.Clone(
PROGSUFFIX=".elf",
ENV=forward_os_env,
SINGLEQUOTEFUNC=single_quote,
ABSPATHGETTERFUNC=extract_abs_dir_path,
ABSPATHGETTERFUNC=resolve_real_dir_node,
# Setting up temp file parameters - to overcome command line length limits
TEMPFILEARGESCFUNC=tempfile_arg_esc_func,
ROOT_DIR=Dir("#"),