subghz_keystore.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. #include "subghz_keystore.h"
  2. #include <furi.h>
  3. #include <furi-hal.h>
  4. #include <storage/storage.h>
  5. #include <lib/toolbox/hex.h>
  6. #include <lib/toolbox/flipper-file.h>
  7. #define SUBGHZ_KEYSTORE_TAG "SubGhzParser"
  8. #define FILE_BUFFER_SIZE 64
  9. #define SUBGHZ_KEYSTORE_FILE_TYPE "Flipper SubGhz Keystore File"
  10. #define SUBGHZ_KEYSTORE_FILE_VERSION 0
  11. #define SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT 1
  12. #define SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE 512
  13. #define SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE (SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE*2)
  14. typedef enum {
  15. SubGhzKeystoreEncryptionNone,
  16. SubGhzKeystoreEncryptionAES256,
  17. } SubGhzKeystoreEncryption;
  18. struct SubGhzKeystore {
  19. SubGhzKeyArray_t data;
  20. };
  21. SubGhzKeystore* subghz_keystore_alloc() {
  22. SubGhzKeystore* instance = furi_alloc(sizeof(SubGhzKeystore));
  23. SubGhzKeyArray_init(instance->data);
  24. return instance;
  25. }
  26. void subghz_keystore_free(SubGhzKeystore* instance) {
  27. furi_assert(instance);
  28. for
  29. M_EACH(manufacture_code, instance->data, SubGhzKeyArray_t) {
  30. string_clear(manufacture_code->name);
  31. manufacture_code->key = 0;
  32. }
  33. SubGhzKeyArray_clear(instance->data);
  34. free(instance);
  35. }
  36. static void subghz_keystore_add_key(SubGhzKeystore* instance, const char* name, uint64_t key, uint16_t type) {
  37. SubGhzKey* manufacture_code = SubGhzKeyArray_push_raw(instance->data);
  38. string_init_set_str(manufacture_code->name, name);
  39. manufacture_code->key = key;
  40. manufacture_code->type = type;
  41. }
  42. static bool subghz_keystore_process_line(SubGhzKeystore* instance, char* line) {
  43. uint64_t key = 0;
  44. uint16_t type = 0;
  45. char skey[17] = {0};
  46. char name[65] = {0};
  47. int ret = sscanf(line, "%16s:%hu:%64s", skey, &type, name);
  48. key = strtoull(skey, NULL, 16);
  49. if (ret == 3) {
  50. subghz_keystore_add_key(instance, name, key, type);
  51. return true;
  52. } else {
  53. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Failed to load line: %s\r\n", line);
  54. return false;
  55. }
  56. }
  57. static void subghz_keystore_mess_with_iv(uint8_t* iv) {
  58. // Please do not share decrypted manufacture keys
  59. // Sharing them will bring some discomfort to legal owners
  60. // And potential legal action against you
  61. // While you reading this code think about your own personal responsibility
  62. asm volatile(
  63. "movs r0, #0x0 \n"
  64. "movs r1, #0x0 \n"
  65. "movs r2, #0x0 \n"
  66. "movs r3, #0x0 \n"
  67. "nani: \n"
  68. "ldrb r1, [r0, %0]\n"
  69. "mov r2, r1 \n"
  70. "add r1, r3 \n"
  71. "mov r3, r2 \n"
  72. "strb r1, [r0, %0]\n"
  73. "adds r0, #0x1 \n"
  74. "cmp r0, #0xF \n"
  75. "bls nani \n"
  76. :
  77. : "r"(iv)
  78. : "r0", "r1", "r2", "r3", "memory");
  79. }
  80. static bool subghz_keystore_read_file(SubGhzKeystore* instance, File* file, uint8_t* iv) {
  81. bool result = true;
  82. char buffer[FILE_BUFFER_SIZE];
  83. char* decrypted_line = furi_alloc(SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE);
  84. char* encrypted_line = furi_alloc(SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE);
  85. size_t encrypted_line_cursor = 0;
  86. if (iv) furi_hal_crypto_store_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv);
  87. size_t ret = 0;
  88. do {
  89. ret = storage_file_read(file, buffer, FILE_BUFFER_SIZE);
  90. for (uint16_t i=0; i < ret; i++) {
  91. if (buffer[i] == '\n' && encrypted_line_cursor > 0) {
  92. // Process line
  93. if(iv) {
  94. // Data alignment check, 32 instead of 16 because of hex encoding
  95. size_t len = strlen(encrypted_line);
  96. if (len % 32 == 0) {
  97. // Inplace hex to bin conversion
  98. for (size_t i=0; i<len; i+=2) {
  99. uint8_t hi_nibble=0;
  100. uint8_t lo_nibble=0;
  101. hex_char_to_hex_nibble(encrypted_line[i], &hi_nibble);
  102. hex_char_to_hex_nibble(encrypted_line[i+1], &lo_nibble);
  103. encrypted_line[i/2] = (hi_nibble<<4) | lo_nibble;
  104. }
  105. len /= 2;
  106. if(furi_hal_crypto_decrypt((uint8_t*)encrypted_line, (uint8_t*)decrypted_line, len)) {
  107. subghz_keystore_process_line(instance, decrypted_line);
  108. } else {
  109. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Decryption failed");
  110. result = false;
  111. break;
  112. }
  113. } else {
  114. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Invalid encrypted data: %s", encrypted_line);
  115. }
  116. } else {
  117. subghz_keystore_process_line(instance, encrypted_line);
  118. }
  119. // reset line buffer
  120. memset(decrypted_line, 0, SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE);
  121. memset(encrypted_line, 0, SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE);
  122. encrypted_line_cursor = 0;
  123. } else if (buffer[i] == '\r' || buffer[i] == '\n') {
  124. // do not add line endings to the buffer
  125. } else {
  126. if (encrypted_line_cursor < SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE) {
  127. encrypted_line[encrypted_line_cursor] = buffer[i];
  128. encrypted_line_cursor++;
  129. } else {
  130. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Malformed file");
  131. result = false;
  132. break;
  133. }
  134. }
  135. }
  136. } while(ret > 0 && result);
  137. if (iv) furi_hal_crypto_store_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT);
  138. free(encrypted_line);
  139. free(decrypted_line);
  140. return result;
  141. }
  142. bool subghz_keystore_load(SubGhzKeystore* instance, const char* file_name) {
  143. furi_assert(instance);
  144. bool result = false;
  145. uint8_t iv[16];
  146. uint32_t version;
  147. SubGhzKeystoreEncryption encryption;
  148. string_t filetype;
  149. string_init(filetype);
  150. Storage* storage = furi_record_open("storage");
  151. FlipperFile* flipper_file = flipper_file_alloc(storage);
  152. do {
  153. if(!flipper_file_open_read(flipper_file, file_name)) {
  154. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to open file for read: %s", file_name);
  155. break;
  156. }
  157. if(!flipper_file_read_header(flipper_file, filetype, &version)) {
  158. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Missing or incorrect header");
  159. break;
  160. }
  161. if(!flipper_file_read_uint32(flipper_file, "Encryption", (uint32_t*)&encryption)) {
  162. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Missing encryption type");
  163. break;
  164. }
  165. if (strcmp(string_get_cstr(filetype), SUBGHZ_KEYSTORE_FILE_TYPE) != 0
  166. || version != SUBGHZ_KEYSTORE_FILE_VERSION) {
  167. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Type or version mismatch");
  168. break;
  169. }
  170. File* file = flipper_file_get_file(flipper_file);
  171. if (encryption == SubGhzKeystoreEncryptionNone) {
  172. result = subghz_keystore_read_file(instance, file, NULL);
  173. }else if (encryption == SubGhzKeystoreEncryptionAES256) {
  174. if(!flipper_file_read_hex_array(flipper_file, "IV", iv, 16)) {
  175. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Missing IV");
  176. break;
  177. }
  178. subghz_keystore_mess_with_iv(iv);
  179. result = subghz_keystore_read_file(instance, file, iv);
  180. } else {
  181. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unknown encryption");
  182. break;
  183. }
  184. } while(0);
  185. flipper_file_close(flipper_file);
  186. flipper_file_free(flipper_file);
  187. furi_record_close("storage");
  188. string_clear(filetype);
  189. return result;
  190. }
  191. bool subghz_keystore_save(SubGhzKeystore* instance, const char* file_name, uint8_t* iv) {
  192. furi_assert(instance);
  193. bool result = false;
  194. Storage* storage = furi_record_open("storage");
  195. char* decrypted_line = furi_alloc(SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE);
  196. char* encrypted_line = furi_alloc(SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE);
  197. FlipperFile* flipper_file = flipper_file_alloc(storage);
  198. do {
  199. if(!flipper_file_new_write(flipper_file, file_name)) {
  200. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to open file for write: %s", file_name);
  201. break;
  202. }
  203. if(!flipper_file_write_header_cstr(flipper_file, SUBGHZ_KEYSTORE_FILE_TYPE, SUBGHZ_KEYSTORE_FILE_VERSION)) {
  204. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to add header");
  205. break;
  206. }
  207. if(!flipper_file_write_uint32(flipper_file, "Encryption", SubGhzKeystoreEncryptionAES256)) {
  208. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to add Encryption");
  209. break;
  210. }
  211. if(!flipper_file_write_hex_array(flipper_file, "IV", iv, 16)) {
  212. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to add IV");
  213. break;
  214. }
  215. subghz_keystore_mess_with_iv(iv);
  216. if(!furi_hal_crypto_store_load_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT, iv)) {
  217. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Unable to load encryption key");
  218. break;
  219. }
  220. File* file = flipper_file_get_file(flipper_file);
  221. size_t encrypted_line_count = 0;
  222. for
  223. M_EACH(
  224. key,
  225. instance->data,
  226. SubGhzKeyArray_t) {
  227. // Wipe buffer before packing
  228. memset(decrypted_line, 0, SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE);
  229. memset(encrypted_line, 0, SUBGHZ_KEYSTORE_FILE_ENCRYPTED_LINE_SIZE);
  230. // Form unecreypted line
  231. int len = snprintf(
  232. decrypted_line, SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE,
  233. "%08lX%08lX:%hu:%s",
  234. (uint32_t)(key->key>>32), (uint32_t)key->key, key->type, string_get_cstr(key->name));
  235. // Verify length and align
  236. furi_assert(len > 0);
  237. if (len % 16 != 0) {
  238. len += (16 - len % 16);
  239. }
  240. furi_assert(len % 16 == 0);
  241. furi_assert(len <= SUBGHZ_KEYSTORE_FILE_DECRYPTED_LINE_SIZE);
  242. // Form encrypted line
  243. if(!furi_hal_crypto_encrypt((uint8_t*)decrypted_line, (uint8_t*)encrypted_line, len)) {
  244. FURI_LOG_E(SUBGHZ_KEYSTORE_TAG, "Encryption failed");
  245. break;
  246. }
  247. // HEX Encode encrypted line
  248. const char xx[]= "0123456789ABCDEF";
  249. for (size_t i=0; i<len; i++) {
  250. size_t cursor = len - i - 1;
  251. size_t hex_cursor = len*2 - i*2 - 1;
  252. encrypted_line[hex_cursor] = xx[encrypted_line[cursor] & 0xF];
  253. encrypted_line[hex_cursor-1] = xx[(encrypted_line[cursor]>>4) & 0xF];
  254. }
  255. storage_file_write(file, encrypted_line, strlen(encrypted_line));
  256. storage_file_write(file, "\n", 1);
  257. encrypted_line_count++;
  258. FURI_LOG_I(SUBGHZ_KEYSTORE_TAG, "Encrypted: `%s` -> `%s`", decrypted_line, encrypted_line);
  259. }
  260. furi_hal_crypto_store_unload_key(SUBGHZ_KEYSTORE_FILE_ENCRYPTION_KEY_SLOT);
  261. result = encrypted_line_count == SubGhzKeyArray_size(instance->data);
  262. } while(0);
  263. flipper_file_close(flipper_file);
  264. flipper_file_free(flipper_file);
  265. free(encrypted_line);
  266. free(decrypted_line);
  267. furi_record_close("storage");
  268. return result;
  269. }
  270. SubGhzKeyArray_t* subghz_keystore_get_data(SubGhzKeystore* instance) {
  271. furi_assert(instance);
  272. return &instance->data;
  273. }