diff --git a/core/SConscript.firmware b/core/SConscript.firmware
index 30f683bdb5..ff48a5ae25 100644
--- a/core/SConscript.firmware
+++ b/core/SConscript.firmware
@@ -200,6 +200,7 @@ SOURCE_MOD += [
# rust mods
SOURCE_MOD += [
'embed/extmod/rustmods/modtrezorproto.c',
+ 'embed/extmod/rustmods/modtrezorstoragedevice.c',
]
if UI2:
SOURCE_MOD += [
diff --git a/core/SConscript.unix b/core/SConscript.unix
index 92cf8da7fd..6fd22655c9 100644
--- a/core/SConscript.unix
+++ b/core/SConscript.unix
@@ -197,6 +197,7 @@ SOURCE_MOD += [
# rust mods
SOURCE_MOD += [
'embed/extmod/rustmods/modtrezorproto.c',
+ 'embed/extmod/rustmods/modtrezorstoragedevice.c',
]
if UI2:
SOURCE_MOD += [
diff --git a/core/embed/extmod/rustmods/modtrezorstoragedevice.c b/core/embed/extmod/rustmods/modtrezorstoragedevice.c
new file mode 100644
index 0000000000..c9916d4c30
--- /dev/null
+++ b/core/embed/extmod/rustmods/modtrezorstoragedevice.c
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "py/runtime.h"
+
+#if MICROPY_PY_TREZORSTORAGEDEVICE
+
+#include "librust.h"
+
+
+/// def is_version_stored() -> bool:
+/// """Whether version is in storage."""
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_storagedevice_is_version_stored_obj,
+ storagedevice_is_version_stored);
+
+// /// def get_version() -> bool:
+// /// """Get from storage."""
+// STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorutils_storagedevice_get_version_obj,
+// storagedevice_get_version);
+
+/// def set_version(version: bytes) -> bool:
+/// """Save to storage."""
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorutils_storagedevice_set_version_obj,
+ storagedevice_set_version);
+
+
+STATIC const mp_rom_map_elem_t mp_module_trezorstoragedevice_globals_table[] = {
+ {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorstoragedevice)},
+
+ {MP_ROM_QSTR(MP_QSTR_is_version_stored),
+ MP_ROM_PTR(&mod_trezorutils_storagedevice_is_version_stored_obj)},
+ // {MP_ROM_QSTR(MP_QSTR_get_version),
+ // MP_ROM_PTR(&mod_trezorutils_storagedevice_get_version_obj)},
+ {MP_ROM_QSTR(MP_QSTR_set_version),
+ MP_ROM_PTR(&mod_trezorutils_storagedevice_set_version_obj)},
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_trezorstoragedevice_globals,
+ mp_module_trezorstoragedevice_globals_table);
+
+const mp_obj_module_t mp_module_trezorstoragedevice = {
+ .base = {&mp_type_module},
+ .globals = (mp_obj_dict_t *)&mp_module_trezorstoragedevice_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_trezorstoragedevice, mp_module_trezorstoragedevice,
+ MICROPY_PY_TREZORSTORAGEDEVICE);
+
+#endif // MICROPY_PY_TREZORSTORAGEDEVICE
diff --git a/core/embed/firmware/mpconfigport.h b/core/embed/firmware/mpconfigport.h
index c123c91a0d..a9637d92ca 100644
--- a/core/embed/firmware/mpconfigport.h
+++ b/core/embed/firmware/mpconfigport.h
@@ -155,6 +155,7 @@
#define MICROPY_PY_TREZORCONFIG (1)
#define MICROPY_PY_TREZORCRYPTO (1)
+#define MICROPY_PY_TREZORSTORAGEDEVICE (1)
#define MICROPY_PY_TREZORIO (1)
#define MICROPY_PY_TREZORUI (1)
#define MICROPY_PY_TREZORUTILS (1)
diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs
index 70e7e90ebe..7d3f8ba3a8 100644
--- a/core/embed/rust/build.rs
+++ b/core/embed/rust/build.rs
@@ -6,6 +6,7 @@ fn main() {
generate_qstr_bindings();
generate_micropython_bindings();
generate_trezorhal_bindings();
+ generate_storagedevice_bindings();
#[cfg(feature = "test")]
link_core_objects();
}
@@ -234,6 +235,31 @@ fn generate_trezorhal_bindings() {
.unwrap();
}
+fn generate_storagedevice_bindings() {
+ // TODO: how to avoid defining `storage.h` in this directory
+ // (somehow specifying its location)
+ // core/vendor/trezor-storage/storage.h
+
+ let out_path = env::var("OUT_DIR").unwrap();
+
+ // Tell cargo to invalidate the built crate whenever the header changes.
+ println!("cargo:rerun-if-changed=storage.h");
+
+ let bindings = prepare_bindings()
+ .header("storage.h")
+ // storage
+ .allowlist_function("storage_set")
+ .allowlist_function("storage_delete")
+ .allowlist_function("storage_get");
+
+ // Write the bindings to a file in the OUT_DIR.
+ bindings
+ .generate()
+ .expect("Unable to generate bindings")
+ .write_to_file(PathBuf::from(out_path).join("storage.rs"))
+ .unwrap();
+}
+
fn is_firmware() -> bool {
let target = env::var("TARGET").unwrap();
target.starts_with("thumbv7")
diff --git a/core/embed/rust/librust.h b/core/embed/rust/librust.h
index 375923e321..d73e746ce9 100644
--- a/core/embed/rust/librust.h
+++ b/core/embed/rust/librust.h
@@ -9,6 +9,10 @@ mp_obj_t protobuf_decode(mp_obj_t buf, mp_obj_t def,
mp_obj_t protobuf_len(mp_obj_t obj);
mp_obj_t protobuf_encode(mp_obj_t buf, mp_obj_t obj);
+mp_obj_t storagedevice_is_version_stored();
+// mp_obj_t storagedevice_get_version();
+mp_obj_t storagedevice_set_version(mp_obj_t key);
+
#ifdef TREZOR_EMULATOR
mp_obj_t protobuf_debug_msg_type();
mp_obj_t protobuf_debug_msg_def_type();
@@ -18,4 +22,4 @@ extern mp_obj_module_t mp_module_trezorui2;
#ifdef TREZOR_EMULATOR
mp_obj_t ui_debug_layout_type();
-#endif
\ No newline at end of file
+#endif
diff --git a/core/embed/rust/src/lib.rs b/core/embed/rust/src/lib.rs
index a825dc7b07..1f5c3f1be1 100644
--- a/core/embed/rust/src/lib.rs
+++ b/core/embed/rust/src/lib.rs
@@ -5,6 +5,7 @@
#![allow(dead_code)]
mod error;
+mod storagedevice;
#[macro_use]
mod micropython;
mod protobuf;
diff --git a/core/embed/rust/src/storagedevice/mod.rs b/core/embed/rust/src/storagedevice/mod.rs
new file mode 100644
index 0000000000..800a6bb37a
--- /dev/null
+++ b/core/embed/rust/src/storagedevice/mod.rs
@@ -0,0 +1 @@
+mod storagedevice;
diff --git a/core/embed/rust/src/storagedevice/storagedevice.rs b/core/embed/rust/src/storagedevice/storagedevice.rs
new file mode 100644
index 0000000000..b48c6a355e
--- /dev/null
+++ b/core/embed/rust/src/storagedevice/storagedevice.rs
@@ -0,0 +1,114 @@
+use crate::{
+ micropython::{buffer::Buffer, obj::Obj},
+ trezorhal::secbool,
+ util,
+};
+
+use core::convert::{TryFrom, TryInto};
+
+// TODO: transfer this into a struct with field specifying data type and
+// max_length
+const APP_DEVICE: u16 = 0x01;
+
+const DEVICE_ID: u16 = 0x01;
+const _VERSION: u16 = 0x02;
+const _MNEMONIC_SECRET: u16 = 0x03;
+const _LANGUAGE: u16 = 0x04;
+const _LABEL: u16 = 0x05;
+const _USE_PASSPHRASE: u16 = 0x06;
+const _HOMESCREEN: u16 = 0x07;
+const _NEEDS_BACKUP: u16 = 0x08;
+const _FLAGS: u16 = 0x09;
+const U2F_COUNTER: u16 = 0x0A;
+const _PASSPHRASE_ALWAYS_ON_DEVICE: u16 = 0x0B;
+const _UNFINISHED_BACKUP: u16 = 0x0C;
+const _AUTOLOCK_DELAY_MS: u16 = 0x0D;
+const _NO_BACKUP: u16 = 0x0E;
+const _BACKUP_TYPE: u16 = 0x0F;
+const _ROTATION: u16 = 0x10;
+const _SLIP39_IDENTIFIER: u16 = 0x11;
+const _SLIP39_ITERATION_EXPONENT: u16 = 0x12;
+const _SD_SALT_AUTH_KEY: u16 = 0x13;
+const INITIALIZED: u16 = 0x14;
+const _SAFETY_CHECK_LEVEL: u16 = 0x15;
+const _EXPERIMENTAL_FEATURES: u16 = 0x16;
+
+extern "C" {
+ // storage.h
+ fn storage_has(key: u16) -> secbool::Secbool;
+ fn storage_delete(key: u16) -> secbool::Secbool;
+ fn storage_get(
+ key: u16,
+ // val: *mut cty::c_void,
+ // val: *mut BufferMut,
+ val: *mut u8,
+ max_len: u16,
+ len: *mut u16,
+ ) -> secbool::Secbool;
+ // fn storage_set(key: u16, val: *const cty::c_void, len: u16) ->
+ // secbool::Secbool;
+ fn storage_set(key: u16, val: Buffer, len: u16) -> secbool::Secbool;
+}
+
+#[no_mangle]
+pub extern "C" fn storagedevice_is_version_stored() -> Obj {
+ let block = || {
+ let key: u16 = 0x0102;
+ let result = storagedevice_storage_has(key);
+ Ok(result.into())
+ };
+ unsafe { util::try_or_raise(block) }
+}
+
+// #[no_mangle]
+// pub extern "C" fn storagedevice_get_version() -> Obj {
+// let block = || {
+// let key: u16 = 0x0102;
+// let result = storagedevice_storage_get(key);
+// Ok(result.into())
+// };
+// unsafe { util::try_or_raise(block) }
+// }
+
+#[no_mangle]
+pub extern "C" fn storagedevice_set_version(version: Obj) -> Obj {
+ let block = || {
+ let value = Buffer::try_from(version)?;
+
+ let key: u16 = 0x0102;
+ let result = storagedevice_storage_set(key, value);
+ Ok(result.into())
+ };
+ unsafe { util::try_or_raise(block) }
+}
+
+// pub fn storagedevice_storage_get(key: u16) -> BufferMut {
+// const MAX_LEN: usize = 300;
+// // let mut buf: [u8; MAX_LEN] = [0; MAX_LEN];
+// let mut buf: BufferMut;
+// let mut len: u16 = 0;
+// unsafe { storage_get(key, &mut buf as *mut _, MAX_LEN as u16, &mut len as
+// *mut _) }; buf[..len as usize] as BufferMut
+// }
+
+pub fn storagedevice_storage_set(key: u16, value: Buffer) -> bool {
+ let len = value.len();
+ match unsafe { storage_set(key, value, len as u16) } {
+ secbool::TRUE => true,
+ _ => false,
+ }
+}
+
+pub fn storagedevice_storage_has(key: u16) -> bool {
+ match unsafe { storage_has(key) } {
+ secbool::TRUE => true,
+ _ => false,
+ }
+}
+
+pub fn storagedevice_storage_delete(key: u16) -> bool {
+ match unsafe { storage_delete(key) } {
+ secbool::TRUE => true,
+ _ => false,
+ }
+}
diff --git a/core/embed/rust/src/trezorhal/secbool.rs b/core/embed/rust/src/trezorhal/secbool.rs
index 74ddda57c9..892cbf43b7 100644
--- a/core/embed/rust/src/trezorhal/secbool.rs
+++ b/core/embed/rust/src/trezorhal/secbool.rs
@@ -1,2 +1,3 @@
pub const TRUE: u32 = 0xAAAA_AAAA;
pub const FALSE: u32 = 0x0000_0000;
+pub type Secbool = u32;
diff --git a/core/embed/rust/storage.h b/core/embed/rust/storage.h
new file mode 100644
index 0000000000..2c89659823
--- /dev/null
+++ b/core/embed/rust/storage.h
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef __STORAGE_H__
+#define __STORAGE_H__
+
+#include
+#include
+#include "secbool.h"
+
+// The length of the external salt in bytes.
+#define EXTERNAL_SALT_SIZE 32
+
+// If the top bit of APP is set, then the value is not encrypted.
+#define FLAG_PUBLIC 0x80
+
+// If the top two bits of APP are set, then the value is not encrypted and it
+// can be written even when the storage is locked.
+#define FLAGS_WRITE 0xC0
+
+// The maximum value of app_id which is the six least significant bits of APP.
+#define MAX_APPID 0x3F
+
+// The PIN value corresponding to an empty PIN.
+extern const uint8_t *PIN_EMPTY;
+#define PIN_EMPTY_LEN 0
+
+typedef secbool (*PIN_UI_WAIT_CALLBACK)(uint32_t wait, uint32_t progress,
+ const char *message);
+
+void storage_init(PIN_UI_WAIT_CALLBACK callback, const uint8_t *salt,
+ const uint16_t salt_len);
+void storage_wipe(void);
+secbool storage_is_unlocked(void);
+void storage_lock(void);
+secbool storage_unlock(const uint8_t *pin, size_t pin_len,
+ const uint8_t *ext_salt);
+secbool storage_has_pin(void);
+secbool storage_pin_fails_increase(void);
+uint32_t storage_get_pin_rem(void);
+secbool storage_change_pin(const uint8_t *oldpin, size_t oldpin_len,
+ const uint8_t *newpin, size_t newpin_len,
+ const uint8_t *old_ext_salt,
+ const uint8_t *new_ext_salt);
+void storage_ensure_not_wipe_code(const uint8_t *pin, size_t pin_len);
+secbool storage_has_wipe_code(void);
+secbool storage_change_wipe_code(const uint8_t *pin, size_t pin_len,
+ const uint8_t *ext_salt,
+ const uint8_t *wipe_code,
+ size_t wipe_code_len);
+secbool storage_has(const uint16_t key);
+secbool storage_get(const uint16_t key, void *val, const uint16_t max_len,
+ uint16_t *len);
+secbool storage_set(const uint16_t key, const void *val, const uint16_t len);
+secbool storage_delete(const uint16_t key);
+secbool storage_set_counter(const uint16_t key, const uint32_t count);
+secbool storage_next_counter(const uint16_t key, uint32_t *count);
+
+#endif
diff --git a/core/embed/unix/mpconfigport.h b/core/embed/unix/mpconfigport.h
index 82e7baa442..c0770b382a 100644
--- a/core/embed/unix/mpconfigport.h
+++ b/core/embed/unix/mpconfigport.h
@@ -198,6 +198,7 @@ extern const struct _mp_print_t mp_stderr_print;
#define MICROPY_PY_TREZORCONFIG (1)
#define MICROPY_PY_TREZORCRYPTO (1)
+#define MICROPY_PY_TREZORSTORAGEDEVICE (1)
#define MICROPY_PY_TREZORIO (1)
#define MICROPY_PY_TREZORUI (1)
#define MICROPY_PY_TREZORUTILS (1)
diff --git a/core/mocks/generated/trezorstoragedevice.pyi b/core/mocks/generated/trezorstoragedevice.pyi
new file mode 100644
index 0000000000..764ca6d134
--- /dev/null
+++ b/core/mocks/generated/trezorstoragedevice.pyi
@@ -0,0 +1,11 @@
+from typing import *
+
+
+# extmod/rustmods/modtrezorstoragedevice.c
+def is_version_stored() -> bool:
+ """Whether version is in storage."""
+
+
+# extmod/rustmods/modtrezorstoragedevice.c
+def set_version(version: bytes) -> bool:
+ """Save to storage."""
diff --git a/core/src/storage/__init__.py b/core/src/storage/__init__.py
index 2539c2f6d4..cfe04ef614 100644
--- a/core/src/storage/__init__.py
+++ b/core/src/storage/__init__.py
@@ -1,9 +1,11 @@
from storage import cache, common, device
from trezor import config
+import trezorstoragedevice
+
def set_current_version() -> None:
- device.set_version(common.STORAGE_VERSION_CURRENT)
+ trezorstoragedevice.set_version(common.STORAGE_VERSION_CURRENT)
def wipe() -> None:
@@ -19,7 +21,7 @@ def init_unlocked() -> None:
# In FWs <= 2.3.1 'version' denoted whether the device is initialized or not.
# In 2.3.2 we have introduced a new field 'initialized' for that.
- if device.is_version_stored() and not device.is_initialized():
+ if trezorstoragedevice.is_version_stored() and not device.is_initialized():
common.set_bool(common.APP_DEVICE, device.INITIALIZED, True, public=True)
diff --git a/core/src/storage/device.py b/core/src/storage/device.py
index eaf489511b..828f9605ea 100644
--- a/core/src/storage/device.py
+++ b/core/src/storage/device.py
@@ -5,6 +5,8 @@ from ubinascii import hexlify
import storage.cache
from storage import common
+import trezorstoragedevice
+
if TYPE_CHECKING:
from trezor.enums import BackupType
from typing_extensions import Literal
@@ -60,16 +62,16 @@ AUTOLOCK_DELAY_MAXIMUM = 0x2000_0000 # ~6 days
SD_SALT_AUTH_KEY_LEN_BYTES = const(16)
-def is_version_stored() -> bool:
- return bool(common.get(_NAMESPACE, _VERSION))
+# def is_version_stored() -> bool:
+# return bool(common.get(_NAMESPACE, _VERSION))
def get_version() -> bytes | None:
return common.get(_NAMESPACE, _VERSION)
-def set_version(version: bytes) -> None:
- common.set(_NAMESPACE, _VERSION, version)
+# def set_version(version: bytes) -> None:
+# common.set(_NAMESPACE, _VERSION, version)
def is_initialized() -> bool:
@@ -163,7 +165,7 @@ def store_mnemonic_secret(
needs_backup: bool = False,
no_backup: bool = False,
) -> None:
- set_version(common.STORAGE_VERSION_CURRENT)
+ trezorstoragedevice.set_version(common.STORAGE_VERSION_CURRENT)
common.set(_NAMESPACE, _MNEMONIC_SECRET, secret)
common.set_uint8(_NAMESPACE, _BACKUP_TYPE, backup_type)
common.set_true_or_delete(_NAMESPACE, _NO_BACKUP, no_backup)