// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // MP C foundation module, supports LCD, backlight, keypad and other devices as they are added #include "py/builtin.h" #include "py/obj.h" #include "py/runtime.h" #include #include #include #include "bufhelper.h" /* ADC related includes */ #include "adc.h" // LCD related includes #include "backlight.h" #include "lcd-sharp-ls018B7dh02.h" #include "spi.h" // Keypad related includes #include "keypad-adp-5587.h" #include "py/objstr.h" #include "ring_buffer.h" // Camera related includes #include "camera-ovm7690.h" #include "image_conversion.h" // QR related incldues #include "quirc_internal.h" // Main module includes #include "modfoundation.h" // BIP39 includes #include "bip39_utils.h" // QRCode includes #include "qrcode.h" #include "adc.h" #include "busy_bar.h" #include "dispatch.h" #include "display.h" #include "flash.h" #include "frequency.h" #include "fwheader.h" #include "firmware-keys.h" #include "gpio.h" #include "pprng.h" #include "se.h" #include "stm32h7xx_hal.h" #include "utils.h" #include "sha256.h" #include "se-config.h" #include "pins.h" #include "uECC.h" #include "hash.h" /* lcd class object, expand as needed with instance related details */ typedef struct _mp_obj_lcd_t { mp_obj_base_t base; const spi_t* spi; } mp_obj_lcd_t; /* Backlight class object */ typedef struct _mp_obj_backlight_t { mp_obj_base_t base; } mp_obj_backlight_t; /* keypad class object */ typedef struct _mp_obj_keypad_t { mp_obj_base_t base; } mp_obj_keypad_t; /* Camera class object */ typedef struct _mp_obj_camera_t { mp_obj_base_t base; } mp_obj_camera_t; /* Board Revision object */ typedef struct _mp_obj_boardrev_t { mp_obj_base_t base; } mp_obj_boardrev_t; /* Power Monitor object */ typedef struct _mp_obj_powermon_t { mp_obj_base_t base; uint16_t current; uint16_t voltage; } mp_obj_powermon_t; /* Noise Output object */ typedef struct _mp_obj_noise_t { mp_obj_base_t base; } mp_obj_noise_t; /* QR decoder class object */ typedef struct _mp_obj_QR_t { mp_obj_base_t base; struct quirc quirc; unsigned int width; unsigned int height; } mp_obj_QR_t; /* Internal flash class object */ typedef struct _mp_obj_SettingsFlash_t { mp_obj_base_t base; } mp_obj_SettingsFlash_t; /* System class object */ typedef struct _mp_obj_System_t { mp_obj_base_t base; } mp_obj_System_t; /* bip39 class object */ typedef struct _mp_obj_bip39_t { mp_obj_base_t base; } mp_obj_bip39_t; /* QRCode class object */ typedef struct _mp_obj_QRCode_t { mp_obj_base_t base; QRCode code; } mp_obj_QRCode_t; // Defines #define QR_IMAGE_SIZE (396 * 330) #define VIEWFINDER_IMAGE_SIZE ((240 * 240) / 8) #define SETTINGS_FLASH_START 0x81E0000 #define SETTINGS_FLASH_SIZE 0x20000 #define SETTINGS_FLASH_END (SETTINGS_FLASH_START + SETTINGS_FLASH_SIZE - 1) // Forward prototypes void turbo(bool enable); /*============================================================================= * Start of keypad class *=============================================================================*/ STATIC mp_obj_t keypad_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) { mp_obj_keypad_t* keypad = m_new_obj(mp_obj_keypad_t); keypad->base.type = type; keypad_init(); return MP_OBJ_FROM_PTR(keypad); } STATIC mp_obj_t keypad_get_keycode(mp_obj_t self) { uint8_t buf[1]; if (ring_buffer_dequeue(&buf[0]) == 0) { return mp_const_none; } // printf("keypad.get_keycode() 2: %d\n", buf[0]); return mp_obj_new_int_from_uint(buf[0]); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(keypad_get_keycode_obj, keypad_get_keycode); STATIC mp_obj_t keypad___del__(mp_obj_t self) { return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(keypad___del___obj, keypad___del__); STATIC const mp_rom_map_elem_t keypad_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) }, { MP_ROM_QSTR(MP_QSTR_get_keycode), MP_ROM_PTR(&keypad_get_keycode_obj) }, { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&keypad___del___obj) }, }; STATIC MP_DEFINE_CONST_DICT(keypad_locals_dict, keypad_locals_dict_table); const mp_obj_type_t keypad_type = { { &mp_type_type }, .name = MP_QSTR_Keypad, .make_new = keypad_make_new, .locals_dict = (void*)&keypad_locals_dict, }; /* End of Keypad class code */ /*============================================================================= * Start of LCD class *=============================================================================*/ void lcd_obj_print(const mp_print_t* print, mp_obj_t self_in, mp_print_kind_t kind) { mp_printf(print, "foundation obj print"); } /* Instantiation */ /// def __init__(self, mode: int, key: bytes, iv: bytes = None) -> None: /// ''' /// Initialize LCD object context. Return a MP LCD object /// ''' STATIC mp_obj_t lcd_obj_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) { mp_obj_lcd_t* lcd = m_new_obj(mp_obj_lcd_t); lcd->base.type = &lcd_type; lcd->spi = &spi_obj[0]; // lcd_init(false); return MP_OBJ_FROM_PTR(lcd); } /* LCD object methods follow */ STATIC mp_obj_t m_lcd_clear(mp_obj_t self_in, mp_obj_t invert_obj) { uint8_t invert = mp_obj_get_int(invert_obj); lcd_clear(invert); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(m_lcd_clear_obj, m_lcd_clear); STATIC mp_obj_t m_lcd_update(mp_obj_t self_in, mp_obj_t lcd_data) { mp_uint_t interrupt_state; mp_buffer_info_t data_info; // Get the buffer info from the passed in object mp_get_buffer_raise(lcd_data, &data_info, MP_BUFFER_READ); interrupt_state = PASSPORT_KEYPAD_BEGIN_ATOMIC_SECTION(); lcd_update(data_info.buf, true); PASSPORT_KEYPAD_END_ATOMIC_SECTION(interrupt_state); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(m_lcd_update_obj, m_lcd_update); STATIC mp_obj_t foundation___del__(mp_obj_t self) { lcd_deinit(); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(foundation___del___obj, foundation___del__); /* End of LCD object methods */ /* * Class Locals Dictionary table for LCD class */ STATIC const mp_rom_map_elem_t lcd_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&m_lcd_clear_obj) }, { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&m_lcd_update_obj) }, }; STATIC MP_DEFINE_CONST_DICT(lcd_locals_dict, lcd_locals_dict_table); const mp_obj_type_t lcd_type = { { &mp_type_type }, .name = MP_QSTR_LCD, .print = lcd_obj_print, .make_new = lcd_obj_make_new, .locals_dict = (mp_obj_dict_t*)&lcd_locals_dict, }; /* End of setup for LCD class */ /*============================================================================= * Start of backlight class *=============================================================================*/ STATIC mp_obj_t backlight_obj_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) { mp_obj_backlight_t* backlight = m_new_obj(mp_obj_backlight_t); backlight->base.type = &backlight_type; backlight_minimal_init(); return MP_OBJ_FROM_PTR(backlight); } /* LCD object methods follow */ STATIC mp_obj_t m_backlight_intensity(mp_obj_t self_in, mp_obj_t intensity_obj) { uint16_t intensity = mp_obj_get_int(intensity_obj); backlight_intensity(intensity); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(m_backlight_intensity_obj, m_backlight_intensity); /* * Class Locals Dictionary table for Backlight class */ STATIC const mp_rom_map_elem_t backlight_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_intensity), MP_ROM_PTR(&m_backlight_intensity_obj) }, }; STATIC MP_DEFINE_CONST_DICT(backlight_locals_dict, backlight_locals_dict_table); const mp_obj_type_t backlight_type = { { &mp_type_type }, .name = MP_QSTR_Backlight, // .print = lcd_obj_print, .make_new = backlight_obj_make_new, .locals_dict = (mp_obj_dict_t*)&backlight_locals_dict, }; /* End of setup for Backlight class */ /*============================================================================= * Start of Camera class *=============================================================================*/ STATIC mp_obj_t camera_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) { mp_obj_camera_t* o = m_new_obj(mp_obj_camera_t); o->base.type = type; return MP_OBJ_FROM_PTR(o); } /// def enable(self, data: buffer) -> None /// ''' /// Turn on the camera in preparation for calling snapshot(). /// ''' STATIC mp_obj_t camera_enable(mp_obj_t self) { camera_on(); return mp_const_none; } /// def disable(self, data: buffer) -> None /// ''' /// Turn off the camera. /// ''' STATIC mp_obj_t camera_disable(mp_obj_t self) { camera_off(); return mp_const_none; } /// def snapshot(self, image: buffer) -> BoolG /// ''' /// Start a snapshot and wait for it to finish, then convert and copy it into the provided image buffers. /// ''' STATIC mp_obj_t camera_snapshot_(size_t n_args, const mp_obj_t* args) { mp_buffer_info_t qr_image_info; mp_get_buffer_raise(args[1], &qr_image_info, MP_BUFFER_WRITE); uint16_t qr_w = mp_obj_get_int(args[2]); uint16_t qr_h = mp_obj_get_int(args[3]); if (qr_image_info.len != qr_w * qr_h) { printf("ERROR: QR buffer w/h not consistent with buffer size!\n"); return mp_const_false; } if (qr_image_info.len != QR_IMAGE_SIZE) { printf("ERROR: QR buffer is the wrong size!\n"); return mp_const_false; } mp_buffer_info_t viewfinder_image_info; mp_get_buffer_raise(args[4], &viewfinder_image_info, MP_BUFFER_WRITE); uint16_t viewfinder_w = mp_obj_get_int(args[5]); uint16_t viewfinder_h = mp_obj_get_int(args[6]); if (viewfinder_image_info.len != viewfinder_w * viewfinder_h / 8) { printf("ERROR: Viewfinder buffer w/h not consistent with buffer size!\n"); return mp_const_false; } if (viewfinder_w > qr_w || viewfinder_h > qr_h) { // Viewfinder can't be larger than base image printf("ERROR: Viewfinder buffer is larger than QR buffer!\n"); return mp_const_false; } if (camera_snapshot() < 0) { return mp_const_false; } uint16_t* rgb565 = camera_get_frame_buffer(); //uint32_t start = HAL_GetTick(); convert_rgb565_to_grayscale_and_mono( rgb565, qr_image_info.buf, qr_w, qr_h, viewfinder_image_info.buf, viewfinder_w, viewfinder_h); //uint32_t end = HAL_GetTick(); //printf("conversion: %lums\n", end - start); return mp_const_true; } STATIC mp_obj_t camera_get_line_data(mp_obj_t self_in, mp_obj_t line, mp_obj_t _line_num) { // Get the buffer info from the passed in object mp_buffer_info_t line_info; mp_get_buffer_raise(line, &line_info, MP_BUFFER_WRITE); int line_num = mp_obj_get_int(_line_num); if (line_num < 0 || line_num >= CAMERA_HEIGHT || line_info.len < CAMERA_WIDTH * 2) { printf("line_num = %d line_info.len = %u\n", line_num, line_info.len); return mp_const_false; } uint16_t* rgb565 = camera_get_frame_buffer(); uint32_t pixels_per_line = CAMERA_WIDTH; memcpy(line_info.buf, rgb565 + (line_num * pixels_per_line), pixels_per_line * 2); // Two bytes per pixel return mp_const_true; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(camera_enable_obj, camera_enable); STATIC MP_DEFINE_CONST_FUN_OBJ_1(camera_disable_obj, camera_disable); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(camera_snapshot_obj, 7, 7, camera_snapshot_); STATIC MP_DEFINE_CONST_FUN_OBJ_3(camera_get_line_data_obj, camera_get_line_data); STATIC mp_obj_t camera___del__(mp_obj_t self) { // mp_obj_camera_t *o = MP_OBJ_TO_PTR(self); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(camera___del___obj, camera___del__); STATIC const mp_rom_map_elem_t camera_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) }, { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&camera_enable_obj) }, { MP_ROM_QSTR(MP_QSTR_disable), MP_ROM_PTR(&camera_disable_obj) }, { MP_ROM_QSTR(MP_QSTR_snapshot), MP_ROM_PTR(&camera_snapshot_obj) }, { MP_ROM_QSTR(MP_QSTR_get_line_data), MP_ROM_PTR(&camera_get_line_data_obj) }, { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&camera___del___obj) }, }; STATIC MP_DEFINE_CONST_DICT(camera_locals_dict, camera_locals_dict_table); STATIC const mp_obj_type_t camera_type = { { &mp_type_type }, .name = MP_QSTR_camera, .make_new = camera_make_new, .locals_dict = (void*)&camera_locals_dict, }; /* End of setup for Camera class */ /*============================================================================= * Start of Power Monitor class *=============================================================================*/ STATIC mp_obj_t mod_foundation_powermon_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) { mp_obj_powermon_t* powermon = m_new_obj(mp_obj_powermon_t); powermon->base.type = type; return MP_OBJ_FROM_PTR(powermon); } STATIC mp_obj_t mod_foundation_powermon_read(mp_obj_t self) { int ret; uint16_t current = 0; uint16_t voltage = 0; mp_obj_t tuple[2]; mp_obj_powermon_t* pPowerMon = (mp_obj_powermon_t*)self; ret = adc_read_powermon(¤t, &voltage); if (ret < 0) { tuple[0] = mp_const_none; tuple[1] = mp_const_none; return mp_obj_new_tuple(2, tuple); } pPowerMon->current = current; pPowerMon->voltage = voltage; tuple[0] = mp_obj_new_int_from_uint(current); tuple[1] = mp_obj_new_int_from_uint(voltage); return mp_obj_new_tuple(2, tuple); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_powermon_read_obj, mod_foundation_powermon_read); STATIC mp_obj_t mod_foundation_powermon___del__(mp_obj_t self) { return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_powermon___del___obj, mod_foundation_powermon___del__); STATIC const mp_rom_map_elem_t mod_foundation_powermon_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) }, { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mod_foundation_powermon_read_obj) }, { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_foundation_powermon___del___obj) }, }; STATIC MP_DEFINE_CONST_DICT(mod_foundation_powermon_locals_dict, mod_foundation_powermon_locals_dict_table); const mp_obj_type_t powermon_type = { { &mp_type_type }, .name = MP_QSTR_PMon, .make_new = mod_foundation_powermon_make_new, .locals_dict = (void*)&mod_foundation_powermon_locals_dict, }; /* End of power monitor class */ /*============================================================================= * Start of Board Revision class *=============================================================================*/ STATIC mp_obj_t mod_foundation_boardrev_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) { mp_obj_boardrev_t* boardrev = m_new_obj(mp_obj_boardrev_t); boardrev->base.type = type; return MP_OBJ_FROM_PTR(boardrev); } STATIC mp_obj_t mod_foundation_boardrev_read(mp_obj_t self) { HAL_StatusTypeDef ret; uint16_t board_rev = 0; ret = adc_read_boardrev(&board_rev); if (ret < 0) { return mp_const_none; } return mp_obj_new_int_from_uint(board_rev); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_boardrev_read_obj, mod_foundation_boardrev_read); STATIC mp_obj_t mod_foundation_boardrev___del__(mp_obj_t self) { return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_boardrev___del___obj, mod_foundation_boardrev___del__); STATIC const mp_rom_map_elem_t mod_foundation_boardrev_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) }, { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mod_foundation_boardrev_read_obj) }, { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_foundation_boardrev___del___obj) }, }; STATIC MP_DEFINE_CONST_DICT(mod_foundation_boardrev_locals_dict, mod_foundation_boardrev_locals_dict_table); const mp_obj_type_t boardrev_type = { { &mp_type_type }, .name = MP_QSTR_Bdrev, .make_new = mod_foundation_boardrev_make_new, .locals_dict = (void*)&mod_foundation_boardrev_locals_dict, }; /* End of board revision class */ /*============================================================================= * Start of Noise Output class *=============================================================================*/ STATIC mp_obj_t mod_foundation_noise_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) { mp_obj_noise_t* noise = m_new_obj(mp_obj_noise_t); noise->base.type = type; /* * Need to enable the noise amp enables. */ adc_enable_noise(); return MP_OBJ_FROM_PTR(noise); } STATIC mp_obj_t mod_foundation_noise_read(mp_obj_t self) { HAL_StatusTypeDef ret; uint32_t noise1 = 0; uint32_t noise2 = 0; mp_obj_t tuple[2]; ret = adc_read_noise_inputs(&noise1, &noise2); if (ret < 0) { tuple[0] = mp_const_none; tuple[1] = mp_const_none; return mp_obj_new_tuple(2, tuple); } tuple[0] = mp_obj_new_int_from_uint(noise1); tuple[1] = mp_obj_new_int_from_uint(noise2); return mp_obj_new_tuple(2, tuple); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_noise_read_obj, mod_foundation_noise_read); bool get_random_uint16(uint16_t* result) { HAL_StatusTypeDef ret; uint32_t noise1 = 0; uint32_t noise2 = 0; uint16_t r = 0; for (int i = 0; i < 4; i++) { r = r << 4; HAL_Delay(1); ret = adc_read_noise_inputs(&noise1, &noise2); if (ret < 0) { return false; } r ^= noise1 ^ noise2; } *result = r; return true; } // Flags to select which entroy sources to combine #define AVALANCHE_SOURCE 1 #define MCU_RNG_SOURCE 2 #define SE_RNG_SOURCE 4 #define ALS_SOURCE 8 // Function to combine multiple sources of randomness together STATIC mp_obj_t mod_foundation_noise_random_bytes(mp_obj_t self, const mp_obj_t buf, mp_obj_t _sources) { mp_buffer_info_t buf_info; mp_get_buffer_raise(buf, &buf_info, MP_BUFFER_WRITE); // Buffer must be at least 4 bytes - if less is needed, caller can extract 1-3 bytes from a 4-byte buffer. if (buf_info.len < 4) { return false; } // Need to be fast for this turbo(true); int sources = mp_obj_get_int(_sources); // printf("sources = 0x%02x buf_info.len=%d\n", sources, buf_info.len); if (!(sources & AVALANCHE_SOURCE) && !(sources & MCU_RNG_SOURCE) && !(sources & SE_RNG_SOURCE)) { // printf("Bad sources, so picking Avalanche!\n"); // Ensure we always use at least one high entropy source even if caller made a mistake. // If you just want als value, you can read it separately. sources |= AVALANCHE_SOURCE; } if (sources & AVALANCHE_SOURCE) { uint8_t* pbuf8 = (uint8_t*)buf_info.buf; for (int i = 0; i < buf_info.len;) { uint8_t sample[2]; bool result = get_random_uint16((uint16_t*)sample); if (!result) { turbo(false); // printf("failed to get Avalanche sample!\n"); return mp_const_false; } // printf("AVALANCHE SAMPLE: 0x%02x%02x\n", sample[0], sample[1]); if (i < buf_info.len) { pbuf8[i] = sample[0]; i++; } if (i < buf_info.len) { pbuf8[i] = sample[1]; i++; } } } // MCU RNG if (sources & MCU_RNG_SOURCE) { // printf("Using MCU source\n"); uint32_t* pbuf32 = (uint32_t*)buf_info.buf; // NOTE: We don't sample and mixin additional entropy into the final 1-3 bytes if buffer size // is not a multiple of 4 bytes. for (int i = 0; i < buf_info.len / 4; i++) { uint32_t sample = rng_sample(); // printf("MCU SAMPLE: 0x%08lx\n", sample); // XOR in the sample *(pbuf32 + i) ^= sample; } } // Secure Element RNG if (sources & SE_RNG_SOURCE) { uint8_t* pbuf8 = (uint8_t*)buf_info.buf; uint8_t* pbuf8_end = pbuf8 + buf_info.len; uint8_t num_in[20], sample[32]; memset(num_in, 0, 20); for (int i = 0; i < buf_info.len / 32; i++) { int rc = se_pick_nonce(num_in, sample); if (rc < 0) { se_show_error(); turbo(false); return mp_const_false; } // uint32_t* s = (uint32_t*)sample; // printf("SE SAMPLE: 0x%08lx %08lx %08lx %08lx\n", *s, *(s+1), *(s+2), *(s+3)); // Mixin the sample values - don't overflow output buffer xor_mixin(pbuf8, sample, MIN(pbuf8_end - pbuf8, 32)); pbuf8 += 32; } } // printf("1 buf: "); // uint8_t* pbuf8 = (uint8_t*)buf_info.buf; // for (int i=0; i None: /// ''' /// Initialize QR context. /// ''' STATIC mp_obj_t QR_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) { mp_obj_QR_t* o = m_new_obj(mp_obj_QR_t); o->base.type = type; if (n_args != 3) { printf("ERROR: QR called with wrong number of arguments!"); return mp_const_none; } o->width = mp_obj_get_int(args[0]); o->height = mp_obj_get_int(args[1]); mp_buffer_info_t image_info; mp_get_buffer_raise(args[2], &image_info, MP_BUFFER_READ); unsigned int expected_image_len = o->width * o->height; if (image_info.len != expected_image_len) { printf("ERROR: Invalid buffer size for this decoder. Expected %u\n", expected_image_len); return mp_const_none; } if (quirc_init(&o->quirc, o->width, o->height, image_info.buf) < 0) { printf("ERROR: Unable to initialize quirc!\n"); return mp_const_none; } return MP_OBJ_FROM_PTR(o); } struct quirc_code code; struct quirc_data data; //#define QR_DEBUG /// def find_qr_codes(self, image: image) -> array of strings: /// ''' /// Find QR codes in image. /// ''' STATIC mp_obj_t QR_find_qr_codes(mp_obj_t self) { mp_obj_QR_t* o = MP_OBJ_TO_PTR(self); #ifdef QR_DEBUG printf("find_qr_codes: %u, %u\n", o->width, o->height); #endif // Prepare to decode quirc_begin(&o->quirc, NULL, NULL); #ifdef QR_DEBUG printf("w=%u, h=%u\n", o->width, o->height); #endif // This triggers the decoding of the image we just gave quirc quirc_end(&o->quirc); // Let's see if we got any results int num_codes = quirc_count(&o->quirc); #ifdef QR_DEBUG printf("num_codes=%d\n", num_codes); #endif if (num_codes == 0) { #ifdef QR_DEBUG printf("No codes found\n"); #endif return mp_const_none; } // Extract the first code found only, even if multiple were found quirc_extract(&o->quirc, 0, &code); #ifdef QR_DEBUG printf("quirc_extract() done\n"); #endif // Decoding stage quirc_decode_error_t err = quirc_decode(&code, &data); if (err) { printf("ERROR: Decode failed: %s\n", quirc_strerror(err)); return mp_const_none; } else { #ifdef QR_DEBUG printf("Data: %s\n", data.payload); #endif } // Return the payload as the function result // const char* payload = mp_obj_str_get_str(data.payload); // printf("Data: %s\n", payload); vstr_t vstr; int code_len = strlen((const char*)data.payload); vstr_init(&vstr, code_len + 1); vstr_add_strn(&vstr, (const char*)data.payload, code_len); // Can append to vstr if necessary return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(QR_find_qr_codes_obj, QR_find_qr_codes); STATIC mp_obj_t QR___del__(mp_obj_t self) { mp_obj_QR_t* o = MP_OBJ_TO_PTR(self); quirc_destroy(&o->quirc); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(QR___del___obj, QR___del__); STATIC const mp_rom_map_elem_t QR_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) }, { MP_ROM_QSTR(MP_QSTR_find_qr_codes), MP_ROM_PTR(&QR_find_qr_codes_obj) }, { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&QR___del___obj) }, }; STATIC MP_DEFINE_CONST_DICT(QR_locals_dict, QR_locals_dict_table); STATIC const mp_obj_type_t QR_type = { { &mp_type_type }, .name = MP_QSTR_QR, .make_new = QR_make_new, .locals_dict = (void*)&QR_locals_dict, }; /* End of setup for QR decoder class */ /*============================================================================= * Start of SettingsFlash class *=============================================================================*/ /// def __init__(self, mode: int, key: bytes, iv: bytes = None) -> boolean: /// ''' /// Initialize SettingsFlash context. /// ''' STATIC mp_obj_t SettingsFlash_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) { mp_obj_SettingsFlash_t* o = m_new_obj(mp_obj_SettingsFlash_t); o->base.type = type; return MP_OBJ_FROM_PTR(o); } // #define FLASH_DEBUG /// def write(self, dest_addr, data) -> boolean /// ''' /// Write data to internal flash /// ''' STATIC mp_obj_t SettingsFlash_write(mp_obj_t self, mp_obj_t dest_addr, mp_obj_t data) { uint32_t flash_addr = mp_obj_get_int(dest_addr); mp_buffer_info_t data_info; mp_get_buffer_raise(data, &data_info, MP_BUFFER_READ); if (flash_addr < SETTINGS_FLASH_START || flash_addr + data_info.len - 1 > SETTINGS_FLASH_END || data_info.len % 4 != 0) { #ifdef FLASH_DEBUG printf("ERROR: SettingsFlash_write: bad parameters: flash_addr=0x%08lx\nSETTINGS_FLASH_START=0x%08x\nSETTINGS_FLASH_END=0x%08x\ndata_info.len=0x%04x\n", flash_addr, SETTINGS_FLASH_START, SETTINGS_FLASH_END, data_info.len); #endif return mp_const_false; } #ifdef FLASH_DEBUG printf("SettingsFlash_write: %u bytes to 0x%08lx\n", data_info.len, flash_addr); // for (uint32_t i=0; i boolean /// ''' /// Erase all of flash (H7 doesn't provide facility to erase less than the whole 128K) /// ''' STATIC mp_obj_t SettingsFlash_erase(mp_obj_t self) { #ifdef FLASH_DEBUG printf("SettingsFlash_erase()\n"); #endif // NOTE: This function doesn't return any error/success info flash_erase(SETTINGS_FLASH_START, SETTINGS_FLASH_SIZE / 4); return mp_const_true; } STATIC MP_DEFINE_CONST_FUN_OBJ_3(SettingsFlash_write_obj, SettingsFlash_write); STATIC MP_DEFINE_CONST_FUN_OBJ_1(SettingsFlash_erase_obj, SettingsFlash_erase); STATIC mp_obj_t SettingsFlash___del__(mp_obj_t self) { return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(SettingsFlash___del___obj, SettingsFlash___del__); STATIC const mp_rom_map_elem_t SettingsFlash_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&SettingsFlash_write_obj) }, { MP_ROM_QSTR(MP_QSTR_erase), MP_ROM_PTR(&SettingsFlash_erase_obj) }, { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&SettingsFlash___del___obj) }, }; STATIC MP_DEFINE_CONST_DICT(SettingsFlash_locals_dict, SettingsFlash_locals_dict_table); STATIC const mp_obj_type_t SettingsFlash_type = { { &mp_type_type }, .name = MP_QSTR_SettingsFlash, .make_new = SettingsFlash_make_new, .locals_dict = (void*)&SettingsFlash_locals_dict, }; /* End of setup for internal flash class */ /*============================================================================= * Start of System class *=============================================================================*/ /// def __init__(self, mode: int, key: bytes, iv: bytes = None) -> boolean: /// ''' /// Initialize System context. /// ''' STATIC mp_obj_t System_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) { mp_obj_System_t* o = m_new_obj(mp_obj_System_t); o->base.type = type; return MP_OBJ_FROM_PTR(o); } #define SYSTEM_DEBUG /// def reset(self) -> None /// ''' /// Perform a warm reset of the system (should be mostly the same as turning it off and then on) /// ''' STATIC mp_obj_t System_reset(mp_obj_t self) { passport_reset(); return mp_const_none; } /// def shutdown(self) -> None /// ''' /// Shutdown power to the Passport /// ''' STATIC mp_obj_t System_shutdown(mp_obj_t self) { // We clear the memory display and then shutdown display_clean_shutdown(); return mp_const_none; } /// def dispatch(self, command: int, buf: bytes, len: int, arg2: int, ) -> array of strings: /// ''' /// Dispatch system function by command number. This is a carry-over from the old firewall /// code. We can probably switch this to direct function calls instead. The only benefit is /// that this gives us a nice single point to handle RDP level 2 checks and other security checks. /// ''' STATIC mp_obj_t System_dispatch(size_t n_args, const mp_obj_t* args) { int8_t command = mp_obj_get_int(args[1]); uint16_t arg2 = mp_obj_get_int(args[3]); int result; turbo(true); if (args[2] == mp_const_none) { result = se_dispatch(command, NULL, 0, arg2, 0, 0); } else { mp_buffer_info_t buf_info; // Use MP_BUFFER_WRITE below so any updates are copied back up mp_get_buffer_raise(args[2], &buf_info, MP_BUFFER_WRITE); result = se_dispatch(command, buf_info.buf, buf_info.len, arg2, 0, 0); } turbo(false); return mp_obj_new_int(result); } /// def show_busy_bar(self) -> None /// ''' /// Start displaying the busy bar animation for long-running processes /// Also, enable turbo mode since if we need to wait, speed it almost certainly helpful. /// ''' STATIC mp_obj_t System_show_busy_bar(mp_obj_t self) { turbo(true); busy_bar_start(); return mp_const_none; } /// def hide_busy_bar(self) -> None /// ''' /// Stop showing the busy bar and disable turbo mode /// ''' STATIC mp_obj_t System_hide_busy_bar(mp_obj_t self) { busy_bar_stop(); turbo(false); return mp_const_none; } #define SECRETS_FLASH_START 0x81C0000 #define SECRETS_FLASH_SIZE 0x20000 /// def System_get_software_info(self) -> None /// ''' /// Get version, timestamp & hash of the firmware and bootloader as a tuple /// ''' STATIC mp_obj_t System_get_software_info(mp_obj_t self) { passport_firmware_header_t* fwhdr = (passport_firmware_header_t*)FW_HDR; mp_obj_t tuple[4]; // Firmware version tuple[0] = mp_obj_new_str_copy( &mp_type_str, (const uint8_t*)fwhdr->info.fwversion, strlen((const char*)fwhdr->info.fwversion)); // Firmware date tuple[1] = mp_obj_new_int_from_uint(fwhdr->info.timestamp); uint32_t boot_counter = 0; se_get_counter(&boot_counter, 1); tuple[2] = mp_obj_new_int_from_uint(boot_counter); // User-signed firmware? tuple[3] = (fwhdr->signature.pubkey1 == FW_USER_KEY) ? mp_const_true : mp_const_false; return mp_obj_new_tuple(4, tuple); } /// def System_progress_bar(self, progress) -> None /// ''' /// Draw a progress bar to the specified amount (0-1.0) /// ''' STATIC mp_obj_t System_progress_bar(mp_obj_t self, mp_obj_t _progress) { int8_t progress = mp_obj_get_int(_progress); display_progress_bar( PROGRESS_BAR_MARGIN, PROGRESS_BAR_Y, SCREEN_WIDTH - (PROGRESS_BAR_MARGIN * 2), PROGRESS_BAR_HEIGHT, progress); // Showing just the lines that changed is much faster and avoids full-screen flicker display_show_lines(PROGRESS_BAR_Y, PROGRESS_BAR_Y + PROGRESS_BAR_HEIGHT); return mp_const_none; } /// def System_read_ambient(self) -> None /// ''' /// Read the ambient light sensor and bucket it to a level from 0-100 /// ''' STATIC mp_obj_t System_read_ambient(mp_obj_t self) { uint16_t millivolts; adc_read_als(&millivolts); millivolts = MIN(millivolts, 3200); // printf("millivolts = %u\n", millivolts); int level = millivolts / 32; return mp_obj_new_int(level); } uint8_t turbo_count = 0; void turbo(bool enable) { if (enable) { if (turbo_count == 0) { frequency_turbo(true); } turbo_count++; } else { if (turbo_count == 0) { // printf("ERROR: Tried to disable turbo mode when it was not already enabled!\n"); return; } if (turbo_count == 1) { frequency_turbo(false); } turbo_count--; } } /// def System_turbo(self, progress) -> None /// ''' /// Enable or disable turbo mode (fastest MCU frequency) /// ''' STATIC mp_obj_t System_turbo(mp_obj_t self, mp_obj_t _enable) { bool enable = mp_obj_is_true(_enable); turbo(enable); // printf("%s: %lu, %lu, %lu, %lu, %lu\n", enable ? "enable" : "disabled", HAL_RCC_GetSysClockFreq(), SystemCoreClock, HAL_RCC_GetHCLKFreq(), // HAL_RCC_GetPCLK1Freq(), HAL_RCC_GetPCLK2Freq()); return mp_const_none; } /// def System_sha256(self, buffer, digest) -> None /// ''' /// Perform a sha256 hash on the given data (bytearray) /// ''' STATIC mp_obj_t System_sha256(mp_obj_t self, mp_obj_t data, mp_obj_t digest) { mp_buffer_info_t data_info; mp_get_buffer_raise(data, &data_info, MP_BUFFER_READ); mp_buffer_info_t digest_info; mp_get_buffer_raise(digest, &digest_info, MP_BUFFER_WRITE); SHA256_CTX ctx; sha256_init(&ctx); sha256_update(&ctx, (void *)data_info.buf, data_info.len); sha256_final(&ctx, digest_info.buf); return mp_const_none; } // Simple header verification bool verify_header(passport_firmware_header_t *hdr) { if (hdr->info.magic != FW_HEADER_MAGIC) goto fail; if (hdr->info.timestamp == 0) goto fail; if (hdr->info.fwversion[0] == 0x0) goto fail; if (hdr->info.fwlength < FW_HEADER_SIZE) goto fail; if ((hdr->signature.pubkey1 != FW_USER_KEY) && (hdr->signature.pubkey1 > FW_MAX_PUB_KEYS)) goto fail; if (hdr->signature.pubkey1 != FW_USER_KEY) { if (hdr->signature.pubkey2 > FW_MAX_PUB_KEYS) goto fail; } return true; fail: return false; } /// def System_validate_firmware_header(self, header) -> None /// ''' /// Validate the given firmware header bytes as a potential candidate to be installed. /// ''' STATIC mp_obj_t System_validate_firmware_header(mp_obj_t self, mp_obj_t header) { mp_buffer_info_t header_info; mp_get_buffer_raise(header, &header_info, MP_BUFFER_READ); // Existing header passport_firmware_header_t* fwhdr = (passport_firmware_header_t*)FW_HDR; // New header passport_firmware_header_t* new_fwhdr = (passport_firmware_header_t*)header_info.buf; mp_obj_t tuple[3]; bool is_valid = verify_header(header_info.buf); if (is_valid) { // Ensure they are not trying to install an older version of firmware, but allow // a reinstall of the same version. Also allow installation of user firmware regardless of // timestamp and then allow installing a Foundation-signed build. if ((new_fwhdr->signature.pubkey1 != FW_USER_KEY && fwhdr->signature.pubkey1 != FW_USER_KEY ) && (new_fwhdr->info.timestamp < fwhdr->info.timestamp)) { tuple[0] = mp_const_false; tuple[1] = mp_obj_new_str_copy(&mp_type_str, (const uint8_t*)new_fwhdr->info.fwversion, strlen((const char*)new_fwhdr->info.fwversion)); // Include an error string vstr_t vstr; vstr_init(&vstr, 80); char* msg = "The selected firmware is older than the currently installed firmware and cannot be installed.\n\nCurrent Version:\n "; vstr_add_strn(&vstr, (const char*)msg, strlen(msg)); vstr_add_strn(&vstr, (const char*)fwhdr->info.fwdate, strlen((const char*)new_fwhdr->info.fwdate)); msg = "\n\nSelected Version:\n "; vstr_add_strn(&vstr, (const char*)msg, strlen(msg)); vstr_add_strn(&vstr, (const char*)new_fwhdr->info.fwdate, strlen((const char*)new_fwhdr->info.fwdate)); tuple[2] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr); return mp_obj_new_tuple(3, tuple); } } else { // Invalid header tuple[0] = mp_const_false; tuple[1] = mp_obj_new_str_copy(&mp_type_str, (const uint8_t*)new_fwhdr->info.fwversion, strlen((const char*)new_fwhdr->info.fwversion)); // Include an error string vstr_t vstr; vstr_init(&vstr, 80); char* msg = "The selected firmware header is invalid and cannot be installed."; vstr_add_strn(&vstr, (const char*)msg, strlen(msg)); tuple[2] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr); return mp_obj_new_tuple(3, tuple); } // is_valid tuple[0] = mp_const_true; // Firmware version tuple[1] = mp_obj_new_str_copy(&mp_type_str, (const uint8_t*)new_fwhdr->info.fwversion, strlen((const char*)new_fwhdr->info.fwversion)); // No error message tuple[2] = mp_const_none; return mp_obj_new_tuple(3, tuple); } /// def System_set_user_firmware_pubkey(self, pubkey) -> None /// ''' /// Set the user firmware public key so the user can install custom firmware /// ''' STATIC mp_obj_t System_set_user_firmware_pubkey(mp_obj_t self, mp_obj_t pubkey) { uint8_t pin_hash[32]; mp_buffer_info_t pubkey_info; mp_get_buffer_raise(pubkey, &pubkey_info, MP_BUFFER_READ); // uint8_t* p = (uint8_t*)pubkey_info.buf; // printf("WRITE: len=%d pubkey=%02x%02x%02x%02x...\n",pubkey_info.len, p[0], p[1], p[2], p[3]); pinAttempt_t pa_args; pa_args.magic_value = PA_MAGIC_V1; memcpy(&pa_args.cached_main_pin, g_cached_main_pin, sizeof(g_cached_main_pin)); // Get the hash that proves user knows the PIN int rv = pin_cache_restore(&pa_args, pin_hash); if (rv) { return mp_const_false; } // printf("pin hash=%02x%02x%02x%02x...", pin_hash[0], pin_hash[1], pin_hash[2],pin_hash[3]); rv = se_encrypted_write(KEYNUM_user_fw_pubkey, KEYNUM_pin_hash, pin_hash, pubkey_info.buf, pubkey_info.len); // printf("rv=%d\n", rv); return rv == 0 ? mp_const_true : mp_const_false; } /// def System_get_user_firmware_pubkey(self, pubkey) -> None /// ''' /// Get the user firmware public key /// ''' STATIC mp_obj_t System_get_user_firmware_pubkey(mp_obj_t self, mp_obj_t pubkey) { uint8_t buf[72]; mp_buffer_info_t pubkey_info; mp_get_buffer_raise(pubkey, &pubkey_info, MP_BUFFER_READ); if (pubkey_info.len < 64) { return mp_const_false; } se_pair_unlock(); int rv = se_read_data_slot(KEYNUM_user_fw_pubkey, buf, sizeof(buf)); if (rv == 0) { memcpy(pubkey_info.buf, buf, 64); return mp_const_true; } return mp_const_false; } /// def System_supply_chain_challenge(self, challenge, response) -> None /// ''' /// Perform the supply chain challenge (HMAC) /// ''' STATIC mp_obj_t System_supply_chain_challenge(mp_obj_t self, mp_obj_t challenge, mp_obj_t response) { mp_buffer_info_t challenge_info; mp_get_buffer_raise(challenge, &challenge_info, MP_BUFFER_READ); mp_buffer_info_t response_info; mp_get_buffer_raise(response, &response_info, MP_BUFFER_WRITE); se_pair_unlock(); int rc = se_hmac32(KEYNUM_supply_chain, challenge_info.buf, response_info.buf); if (rc == 0) { return mp_const_true; } return mp_const_false; } uint8_t supply_chain_validation_server_pubkey[64] = { 0x75, 0xF6, 0xCD, 0xDB, 0x93, 0x49, 0x59, 0x9D, 0x4B, 0xB2, 0xDF, 0x82, 0xBC, 0xF9, 0x8E, 0x85, 0x45, 0x6C, 0xFB, 0xE2, 0x87, 0x57, 0xFF, 0x77, 0x5D, 0xB0, 0x4C, 0xAE, 0x70, 0x1B, 0xDC, 0x00, 0x53, 0x4E, 0x0C, 0x70, 0x01, 0x90, 0x6C, 0x6F, 0xFB, 0xA6, 0x15, 0xAF, 0xDB, 0x67, 0xDE, 0xF9, 0x46, 0x96, 0x4B, 0xB4, 0x39, 0xD0, 0x02, 0x3E, 0xF6, 0x59, 0xF5, 0x80, 0xBB, 0x31, 0x11, 0x3E }; /// def System_verify_supply_chain_server_signature(self, hash, signature) -> None /// ''' /// Verify server signature /// ''' STATIC mp_obj_t System_verify_supply_chain_server_signature(mp_obj_t self, mp_obj_t hash, mp_obj_t signature) { mp_buffer_info_t hash_info; mp_get_buffer_raise(hash, &hash_info, MP_BUFFER_READ); mp_buffer_info_t signature_info; mp_get_buffer_raise(signature, &signature_info, MP_BUFFER_READ); int rc = uECC_verify(supply_chain_validation_server_pubkey, hash_info.buf, hash_info.len, signature_info.buf, uECC_secp256k1()); return rc == 0 ? mp_const_false : mp_const_true; } #define SHA256_BLOCK_LENGTH 64 #define SHA256_DIGEST_LENGTH 32 void _hmac_sha256(uint8_t* key, uint32_t key_len, uint8_t* msg, uint32_t msg_len, uint8_t* hmac) { uint8_t i_key_pad[SHA256_BLOCK_LENGTH]; memset(i_key_pad, 0, SHA256_BLOCK_LENGTH); memcpy(i_key_pad, key, key_len); uint8_t o_key_pad[SHA256_BLOCK_LENGTH]; for (int i = 0; i < SHA256_BLOCK_LENGTH; i++) { o_key_pad[i] = i_key_pad[i] ^ 0x5c; i_key_pad[i] ^= 0x36; } // First hash SHA256_CTX ctx; sha256_init(&ctx); sha256_update(&ctx, i_key_pad, SHA256_BLOCK_LENGTH); memset(i_key_pad, 0, SHA256_BLOCK_LENGTH); // Add the data sha256_update(&ctx, msg, msg_len); // Hash sha256_final(&ctx, hmac); // Second hash sha256_init(&ctx); sha256_update(&ctx, o_key_pad, SHA256_BLOCK_LENGTH); sha256_update(&ctx, hmac, SHA256_DIGEST_LENGTH); sha256_final(&ctx, hmac); } /// def System_hmac_sha256(self, key, msg, hmac) -> None /// ''' /// Calculate an hmac using the given key and data /// ''' STATIC mp_obj_t System_hmac_sha256(size_t n_args, const mp_obj_t* args) { mp_buffer_info_t key_info; mp_get_buffer_raise(args[1], &key_info, MP_BUFFER_READ); // uint8_t* pkey = (uint8_t*)key_info.buf; // printf("key: 0x%02x 0x%02x 0x%02x 0x%02x (len=%d)\n", pkey[0], pkey[1], pkey[2], pkey[3], key_info.len); mp_buffer_info_t msg_info; mp_get_buffer_raise(args[2], &msg_info, MP_BUFFER_READ); // uint8_t* pmsg = (uint8_t*)msg_info.buf; // printf("msg: 0x%02x 0x%02x 0x%02x 0x%02x (len=%d)\n", pmsg[0], pmsg[1], pmsg[2], pmsg[3], msg_info.len); mp_buffer_info_t hmac_info; mp_get_buffer_raise(args[3], &hmac_info, MP_BUFFER_WRITE); // printf("hmac:(len=%d)\n", hmac_info.len); _hmac_sha256(key_info.buf, key_info.len, msg_info.buf, msg_info.len, hmac_info.buf); return mp_const_none; } #define MAX_SERIAL_NUMBER_LEN 20 /// def System_get_serial_number(self) -> None /// ''' /// Get the serial number /// ''' STATIC mp_obj_t System_get_serial_number(mp_obj_t self) { char serial[MAX_SERIAL_NUMBER_LEN]; get_serial_number(serial, MAX_SERIAL_NUMBER_LEN); return mp_obj_new_str_copy(&mp_type_str, (const uint8_t*)serial, strlen(serial)); } /// def System_get_device_hash(self, hash) -> None /// ''' /// Get the device hash /// ''' STATIC mp_obj_t System_get_device_hash(mp_obj_t self, mp_obj_t hash) { mp_buffer_info_t hash_info; mp_get_buffer_raise(hash, &hash_info, MP_BUFFER_WRITE); get_device_hash(hash_info.buf); return mp_const_none; } /// def System_get_backup_pw_hash(self, hash) -> None /// ''' /// Get the hash to use as the "entropy" for the backup password. /// It's based on the device hash plus the seed. /// ''' STATIC mp_obj_t System_get_backup_pw_hash(mp_obj_t self, mp_obj_t hash) { uint8_t device_hash[32]; mp_buffer_info_t hash_info; mp_get_buffer_raise(hash, &hash_info, MP_BUFFER_WRITE); get_device_hash(device_hash); pinAttempt_t pin_attempt; memset(&pin_attempt, 0, sizeof(pinAttempt_t)); pin_fetch_secret(&pin_attempt); SHA256_CTX ctx; sha256_init(&ctx); sha256_update(&ctx, (void *)device_hash, 32); sha256_update(&ctx, (void *)pin_attempt.secret, SE_SECRET_LEN); sha256_final(&ctx, hash_info.buf); // Double SHA sha256_init(&ctx); sha256_update(&ctx, (void *)hash_info.buf, 32); sha256_final(&ctx, hash_info.buf); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(System_reset_obj, System_reset); STATIC MP_DEFINE_CONST_FUN_OBJ_1(System_shutdown_obj, System_shutdown); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(System_dispatch_obj, 4, 4, System_dispatch); STATIC MP_DEFINE_CONST_FUN_OBJ_1(System_show_busy_bar_obj, System_show_busy_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_1(System_hide_busy_bar_obj, System_hide_busy_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_1(System_get_software_info_obj, System_get_software_info); STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_progress_bar_obj, System_progress_bar); STATIC MP_DEFINE_CONST_FUN_OBJ_1(System_read_ambient_obj, System_read_ambient); STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_turbo_obj, System_turbo); STATIC MP_DEFINE_CONST_FUN_OBJ_3(System_sha256_obj, System_sha256); STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_validate_firmware_header_obj, System_validate_firmware_header); STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_set_user_firmware_pubkey_obj, System_set_user_firmware_pubkey); STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_get_user_firmware_pubkey_obj, System_get_user_firmware_pubkey); STATIC MP_DEFINE_CONST_FUN_OBJ_3(System_supply_chain_challenge_obj, System_supply_chain_challenge); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(System_hmac_sha256_obj, 4, 4, System_hmac_sha256); STATIC MP_DEFINE_CONST_FUN_OBJ_3(System_verify_supply_chain_server_signature_obj, System_verify_supply_chain_server_signature); STATIC MP_DEFINE_CONST_FUN_OBJ_1(System_get_serial_number_obj, System_get_serial_number); STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_get_device_hash_obj, System_get_device_hash); STATIC MP_DEFINE_CONST_FUN_OBJ_2(System_get_backup_pw_hash_obj, System_get_backup_pw_hash); STATIC mp_obj_t System___del__(mp_obj_t self) { return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(System___del___obj, System___del__); STATIC const mp_rom_map_elem_t System_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) }, { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&System_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_shutdown), MP_ROM_PTR(&System_shutdown_obj) }, { MP_ROM_QSTR(MP_QSTR_dispatch), MP_ROM_PTR(&System_dispatch_obj) }, { MP_ROM_QSTR(MP_QSTR_show_busy_bar), MP_ROM_PTR(&System_show_busy_bar_obj) }, { MP_ROM_QSTR(MP_QSTR_hide_busy_bar), MP_ROM_PTR(&System_hide_busy_bar_obj) }, { MP_ROM_QSTR(MP_QSTR_get_software_info), MP_ROM_PTR(&System_get_software_info_obj) }, { MP_ROM_QSTR(MP_QSTR_progress_bar), MP_ROM_PTR(&System_progress_bar_obj) }, { MP_ROM_QSTR(MP_QSTR_read_ambient), MP_ROM_PTR(&System_read_ambient_obj) }, { MP_ROM_QSTR(MP_QSTR_turbo), MP_ROM_PTR(&System_turbo_obj) }, { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&System_sha256_obj) }, { MP_ROM_QSTR(MP_QSTR_validate_firmware_header), MP_ROM_PTR(&System_validate_firmware_header_obj) }, { MP_ROM_QSTR(MP_QSTR_set_user_firmware_pubkey), MP_ROM_PTR(&System_set_user_firmware_pubkey_obj) }, { MP_ROM_QSTR(MP_QSTR_get_user_firmware_pubkey), MP_ROM_PTR(&System_get_user_firmware_pubkey_obj) }, { MP_ROM_QSTR(MP_QSTR_supply_chain_challenge), MP_ROM_PTR(&System_supply_chain_challenge_obj) }, { MP_ROM_QSTR(MP_QSTR_verify_supply_chain_server_signature), MP_ROM_PTR(&System_verify_supply_chain_server_signature_obj) }, { MP_ROM_QSTR(MP_QSTR_hmac_sha256), MP_ROM_PTR(&System_hmac_sha256_obj) }, { MP_ROM_QSTR(MP_QSTR_get_serial_number), MP_ROM_PTR(&System_get_serial_number_obj) }, { MP_ROM_QSTR(MP_QSTR_get_device_hash), MP_ROM_PTR(&System_get_device_hash_obj) }, { MP_ROM_QSTR(MP_QSTR_get_backup_pw_hash), MP_ROM_PTR(&System_get_backup_pw_hash_obj) }, { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&System___del___obj) }, }; STATIC MP_DEFINE_CONST_DICT(System_locals_dict, System_locals_dict_table); STATIC const mp_obj_type_t System_type = { { &mp_type_type }, .name = MP_QSTR_System, .make_new = System_make_new, .locals_dict = (void*)&System_locals_dict, }; /* End of setup for System class */ /*============================================================================= * Start of bip39 class *=============================================================================*/ extern word_info_t bip39_word_info[]; extern word_info_t bytewords_word_info[]; // TODO: Restructure this so bip39 and bytewords are separate /// def __init__(self, mode: int, key: bytes, iv: bytes = None) -> boolean: /// ''' /// Initialize System context. /// ''' STATIC mp_obj_t bip39_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) { mp_obj_bip39_t* o = m_new_obj(mp_obj_bip39_t); o->base.type = type; return MP_OBJ_FROM_PTR(o); } #define MATCHES_LEN 80 /// def get_words_matching_prefix(self, prefix, max_matches, word_list) -> None /// ''' /// Return a comma-separated list of BIP39 seed words that match the given keypad /// digits prefix (e.g., '222'). /// ''' STATIC mp_obj_t bip39_get_words_matching_prefix(size_t n_args, const mp_obj_t* args) { mp_check_self(mp_obj_is_str_or_bytes(args[1])); GET_STR_DATA_LEN(args[1], prefix_str, prefix_len); int max_matches = mp_obj_get_int(args[2]); // Must be "bip39" or "bytewords" mp_check_self(mp_obj_is_str_or_bytes(args[3])); GET_STR_DATA_LEN(args[3], word_list_str, word_list_len); const word_info_t* word_info = NULL; uint32_t num_words = 0; if (strcmp("bip39", (char*)word_list_str) == 0) { word_info = bip39_word_info; num_words = 2048; } else if (strcmp("bytewords", (char*)word_list_str) == 0) { word_info = bytewords_word_info; num_words = 256; } else { return mp_const_none; } char matches[MATCHES_LEN]; get_words_matching_prefix((char*)prefix_str, matches, MATCHES_LEN, max_matches, word_info, num_words); // Return the string vstr_t vstr; int matches_len = strlen((const char*)matches); vstr_init(&vstr, matches_len + 1); vstr_add_strn(&vstr, (const char*)matches, matches_len); return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bip39_get_words_matching_prefix_obj, 4, 4, bip39_get_words_matching_prefix); #include "bip39.h" /// def mnemonic_to_entropy(self) -> None /// ''' /// Call trezorcrypto's mnemonic_to_entropy() C function since it's not exposed through their /// Python interface. /// ''' STATIC mp_obj_t bip39_mnemonic_to_entropy(mp_obj_t self, mp_obj_t mnemonic, mp_obj_t entropy) { mp_check_self(mp_obj_is_str_or_bytes(mnemonic)); GET_STR_DATA_LEN(mnemonic, mnemonic_str, mnemonic_len); mp_buffer_info_t entropy_info; mp_get_buffer_raise(entropy, &entropy_info, MP_BUFFER_WRITE); int len = mnemonic_to_entropy((const char*)mnemonic_str, entropy_info.buf); return mp_obj_new_int(len); } STATIC MP_DEFINE_CONST_FUN_OBJ_3(bip39_mnemonic_to_entropy_obj, bip39_mnemonic_to_entropy); STATIC mp_obj_t bip39___del__(mp_obj_t self) { return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bip39___del___obj, bip39___del__); STATIC const mp_rom_map_elem_t bip39_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) }, { MP_ROM_QSTR(MP_QSTR_get_words_matching_prefix), MP_ROM_PTR(&bip39_get_words_matching_prefix_obj) }, { MP_ROM_QSTR(MP_QSTR_mnemonic_to_entropy), MP_ROM_PTR(&bip39_mnemonic_to_entropy_obj) }, { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&bip39___del___obj) }, }; STATIC MP_DEFINE_CONST_DICT(bip39_locals_dict, bip39_locals_dict_table); STATIC const mp_obj_type_t bip39_type = { { &mp_type_type }, .name = MP_QSTR_bip39, .make_new = bip39_make_new, .locals_dict = (void*)&bip39_locals_dict, }; /* End of setup for bip39 class */ /*============================================================================= * Start of QRCode class - renders QR codes to a buffer passed down from MP *=============================================================================*/ // We only have versions here that can be rendered on Pasport's display uint16_t version_capacity_alphanumeric[] = { 25, // 1 47, // 2 77, // 3 114, // 4 154, // 5 195, // 6 224, // 7 279, // 8 335, // 9 395, // 10 468, // 11 535, // 12 619, // 13 667, // 14 758, // 15 854, // 16 938, // 17 1046, // 18 1153, // 19 1249, // 20 1352, // 21 1460, // 22 1588, // 23 1704 // 24 }; uint16_t version_capacity_binary[] = { 17, // 1 32, // 2 53, // 3 78, // 4 106, // 5 134, // 6 154, // 7 192, // 8 230, // 9 271, // 10 321, // 11 367, // 12 425, // 13 458, // 14 520, // 15 586, // 16 644, // 17 718, // 18 792, // 19 858, // 20 929, // 21 1003, // 22 1091, // 23 1171 // 24 }; /// def __init__(self, mode: int, key: bytes, iv: bytes = None) -> boolean: /// ''' /// Initialize QRCode context. /// ''' STATIC mp_obj_t QRCode_make_new(const mp_obj_type_t* type, size_t n_args, size_t n_kw, const mp_obj_t* args) { mp_obj_QRCode_t* o = m_new_obj(mp_obj_QRCode_t); o->base.type = type; return MP_OBJ_FROM_PTR(o); } QRCode qrcode; #define QRCODE_DEBUG /// def render(self) -> None /// ''' /// Render a QR code with the given data, version and ecc level /// ''' STATIC mp_obj_t QRCode_render(size_t n_args, const mp_obj_t* args) { mp_check_self(mp_obj_is_str_or_bytes(args[1])); GET_STR_DATA_LEN(args[1], text_str, text_len); // printf("text_str=%s text_len=%d\n", text_str, text_len); uint8_t version = mp_obj_get_int(args[2]); uint8_t ecc = mp_obj_get_int(args[3]); mp_buffer_info_t output_info; mp_get_buffer_raise(args[4], &output_info, MP_BUFFER_WRITE); uint8_t result = qrcode_initBytes(&qrcode, (uint8_t*)output_info.buf, version, ecc, (uint8_t*)text_str, text_len); return result == 0 ? mp_const_false : mp_const_true; } /// def fit_to_version(self) -> None /// ''' /// Return the QR code version that best fits this data (assumes ECC level 0 for now) /// ''' STATIC mp_obj_t QRCode_fit_to_version(mp_obj_t self, mp_obj_t data_size, mp_obj_t is_alphanumeric) { uint16_t size = mp_obj_get_int(data_size); uint16_t is_alpha = mp_obj_get_int(is_alphanumeric); uint16_t *lookup_table = is_alpha ? version_capacity_alphanumeric : version_capacity_binary; int num_entries = sizeof(version_capacity_alphanumeric) / sizeof(uint16_t); for (int i = 0; i < num_entries; i++) { if (lookup_table[i] >= size) { return mp_obj_new_int(i + 1); } } // Data is too big return mp_obj_new_int(0); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(QRCode_render_obj, 5, 5, QRCode_render); STATIC MP_DEFINE_CONST_FUN_OBJ_3(QRCode_fit_to_version_obj, QRCode_fit_to_version); STATIC mp_obj_t QRCode___del__(mp_obj_t self) { return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(QRCode___del___obj, QRCode___del__); STATIC const mp_rom_map_elem_t QRCode_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) }, { MP_ROM_QSTR(MP_QSTR_render), MP_ROM_PTR(&QRCode_render_obj) }, { MP_ROM_QSTR(MP_QSTR_fit_to_version), MP_ROM_PTR(&QRCode_fit_to_version_obj) }, { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&QRCode___del___obj) }, }; STATIC MP_DEFINE_CONST_DICT(QRCode_locals_dict, QRCode_locals_dict_table); STATIC const mp_obj_type_t QRCode_type = { { &mp_type_type }, .name = MP_QSTR_QRCode, .make_new = QRCode_make_new, .locals_dict = (void*)&QRCode_locals_dict, }; /* End of setup for QRCode class */ /* * Add additional class local dictionary table and data structure here * And add the Class name and MP_ROM_PTR() to the globals table * below */ /* Module Global configuration */ /* Define all properties of the module. * Table entries are key/value pairs of the attribute name (a string) * and the MicroPython object reference. * All identifiers and strings are written as MP_QSTR_xxx and will be * optimized to word-sized integers by the build system (interned strings). */ STATIC const mp_rom_map_elem_t foundation_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation) }, { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&foundation___del___obj) }, { MP_ROM_QSTR(MP_QSTR_Backlight), MP_ROM_PTR(&backlight_type) }, { MP_ROM_QSTR(MP_QSTR_Keypad), MP_ROM_PTR(&keypad_type) }, { MP_ROM_QSTR(MP_QSTR_LCD), MP_ROM_PTR(&lcd_type) }, { MP_ROM_QSTR(MP_QSTR_Camera), MP_ROM_PTR(&camera_type) }, { MP_ROM_QSTR(MP_QSTR_Boardrev), MP_ROM_PTR(&boardrev_type) }, { MP_ROM_QSTR(MP_QSTR_Powermon), MP_ROM_PTR(&powermon_type) }, { MP_ROM_QSTR(MP_QSTR_Noise), MP_ROM_PTR(&noise_type) }, { MP_ROM_QSTR(MP_QSTR_QR), MP_ROM_PTR(&QR_type) }, { MP_ROM_QSTR(MP_QSTR_SettingsFlash), MP_ROM_PTR(&SettingsFlash_type) }, { MP_ROM_QSTR(MP_QSTR_System), MP_ROM_PTR(&System_type) }, { MP_ROM_QSTR(MP_QSTR_bip39), MP_ROM_PTR(&bip39_type) }, { MP_ROM_QSTR(MP_QSTR_QRCode), MP_ROM_PTR(&QRCode_type) }, }; STATIC MP_DEFINE_CONST_DICT(foundation_module_globals, foundation_module_globals_table); /* Define module object. */ const mp_obj_module_t foundation_user_cmodule = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&foundation_module_globals, }; MP_REGISTER_MODULE(MP_QSTR_foundation, foundation_user_cmodule, PASSPORT_FOUNDATION_ENABLED);