diff --git a/core/.changelog.d/3256.added b/core/.changelog.d/3256.added new file mode 100644 index 0000000000..90dad1fff0 --- /dev/null +++ b/core/.changelog.d/3256.added @@ -0,0 +1 @@ +Use Optiga as a source of randomness in seed generation for Model R. diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-random.h b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-random.h index 61030ffc40..ecfba7eb22 100644 --- a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-random.h +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-random.h @@ -23,6 +23,10 @@ #include "rand.h" +#if USE_OPTIGA +#include "optiga.h" +#endif + /// package: trezorcrypto.random /// def uniform(n: int) -> int: @@ -40,22 +44,52 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_random_uniform_obj, mod_trezorcrypto_random_uniform); /// import builtins -/// def bytes(len: int) -> builtins.bytes: +/// def bytes(len: int, strong: bool = False) -> builtins.bytes: /// """ -/// Generate random bytes sequence of length len. +/// Generate random bytes sequence of length len. If `strong` is set then +/// maximum sources of entropy are used. /// """ -STATIC mp_obj_t mod_trezorcrypto_random_bytes(mp_obj_t len) { - uint32_t l = trezor_obj_get_uint(len); - if (l > 1024) { +STATIC mp_obj_t mod_trezorcrypto_random_bytes(size_t n_args, + const mp_obj_t *args) { + uint32_t len = trezor_obj_get_uint(args[0]); + if (len > 1024) { mp_raise_ValueError("Maximum requested size is 1024"); } vstr_t vstr = {0}; - vstr_init_len(&vstr, l); - random_buffer((uint8_t *)vstr.buf, l); + vstr_init_len(&vstr, len); +#if USE_OPTIGA + if (n_args > 1 && mp_obj_is_true(args[1])) { + uint8_t *dest = (uint8_t *)vstr.buf; + if (!optiga_random_buffer(dest, len)) { + vstr_clear(&vstr); + mp_raise_msg(&mp_type_RuntimeError, + "Failed to get randomness from Optiga."); + } + + uint8_t buffer[4] = {0}; + while (len > sizeof(buffer)) { + random_buffer(buffer, sizeof(buffer)); + for (int i = 0; i < sizeof(buffer); ++i) { + *dest ^= buffer[i]; + ++dest; + } + len -= sizeof(buffer); + } + + random_buffer(buffer, len); + for (int i = 0; i < len; ++i) { + *dest ^= buffer[i]; + ++dest; + } + } else +#endif + { + random_buffer((uint8_t *)vstr.buf, len); + } return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_random_bytes_obj, - mod_trezorcrypto_random_bytes); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_random_bytes_obj, 1, + 2, mod_trezorcrypto_random_bytes); /// def shuffle(data: list) -> None: /// """ diff --git a/core/embed/trezorhal/optiga.h b/core/embed/trezorhal/optiga.h index 18f916388f..83af3cc022 100644 --- a/core/embed/trezorhal/optiga.h +++ b/core/embed/trezorhal/optiga.h @@ -39,4 +39,6 @@ bool optiga_cert_size(uint8_t index, size_t *cert_size); bool optiga_read_cert(uint8_t index, uint8_t *cert, size_t max_cert_size, size_t *cert_size); +bool optiga_random_buffer(uint8_t *dest, size_t size); + #endif diff --git a/core/embed/trezorhal/optiga/optiga.c b/core/embed/trezorhal/optiga/optiga.c index 5635938256..50e4cfed18 100644 --- a/core/embed/trezorhal/optiga/optiga.c +++ b/core/embed/trezorhal/optiga/optiga.c @@ -18,6 +18,7 @@ */ #include "optiga.h" +#include #include "optiga_commands.h" int optiga_sign(uint8_t index, const uint8_t *digest, size_t digest_size, @@ -89,3 +90,22 @@ bool optiga_read_cert(uint8_t index, uint8_t *cert, size_t max_cert_size, cert, max_cert_size, cert_size); return OPTIGA_SUCCESS == ret; } + +bool optiga_random_buffer(uint8_t *dest, size_t size) { + while (size > OPTIGA_RANDOM_MAX_SIZE) { + if (optiga_get_random(dest, OPTIGA_RANDOM_MAX_SIZE) != OPTIGA_SUCCESS) { + return false; + } + dest += OPTIGA_RANDOM_MAX_SIZE; + size -= OPTIGA_RANDOM_MAX_SIZE; + } + + if (size < OPTIGA_RANDOM_MIN_SIZE) { + static uint8_t buffer[OPTIGA_RANDOM_MIN_SIZE] = {0}; + optiga_result ret = optiga_get_random(buffer, OPTIGA_RANDOM_MIN_SIZE); + memcpy(dest, buffer, size); + return ret == OPTIGA_SUCCESS; + } + + return optiga_get_random(dest, size) == OPTIGA_SUCCESS; +} diff --git a/core/embed/trezorhal/optiga/optiga_commands.c b/core/embed/trezorhal/optiga/optiga_commands.c index 9cee053634..2aa4c12a46 100644 --- a/core/embed/trezorhal/optiga/optiga_commands.c +++ b/core/embed/trezorhal/optiga/optiga_commands.c @@ -338,7 +338,8 @@ optiga_result optiga_set_data_object(uint16_t oid, bool set_metadata, * https://github.com/Infineon/optiga-trust-m/blob/develop/documents/OPTIGA%E2%84%A2%20Trust%20M%20Solution%20Reference%20Manual.md#getrandom */ optiga_result optiga_get_random(uint8_t *random, size_t random_size) { - if (random_size < 8 || random_size > 256) { + if (random_size < OPTIGA_RANDOM_MIN_SIZE || + random_size > OPTIGA_RANDOM_MAX_SIZE) { return OPTIGA_ERR_SIZE; } diff --git a/core/embed/trezorhal/optiga_commands.h b/core/embed/trezorhal/optiga_commands.h index 3d02f8426f..df4f8169aa 100644 --- a/core/embed/trezorhal/optiga_commands.h +++ b/core/embed/trezorhal/optiga_commands.h @@ -125,6 +125,8 @@ typedef struct { #define OPTIGA_ECC_KEY_COUNT 4 #define OPTIGA_CERT_COUNT 4 #define OPTIGA_MAX_METADATA_SIZE 44 +#define OPTIGA_RANDOM_MIN_SIZE 8 +#define OPTIGA_RANDOM_MAX_SIZE 256 #define OPTIGA_ACCESS_CONDITION(ac_id, oid) \ { (const uint8_t[]){ac_id, oid >> 8, oid & 0xff}, 3 } diff --git a/core/embed/trezorhal/unix/optiga.c b/core/embed/trezorhal/unix/optiga.c index 74a297702b..91889965cc 100644 --- a/core/embed/trezorhal/unix/optiga.c +++ b/core/embed/trezorhal/unix/optiga.c @@ -22,6 +22,7 @@ #include "ecdsa.h" #include "nist256p1.h" #include "optiga_common.h" +#include "rand.h" static const uint8_t DEVICE_CERT_CHAIN[] = { 0x30, 0x82, 0x01, 0x90, 0x30, 0x82, 0x01, 0x37, 0xa0, 0x03, 0x02, 0x01, @@ -145,3 +146,8 @@ bool optiga_read_cert(uint8_t index, uint8_t *cert, size_t max_cert_size, *cert_size = sizeof(DEVICE_CERT_CHAIN); return true; } + +bool optiga_random_buffer(uint8_t *dest, size_t size) { + random_buffer(dest, size); + return true; +} diff --git a/core/mocks/generated/trezorcrypto/random.pyi b/core/mocks/generated/trezorcrypto/random.pyi index 78fc9c58b6..bd32605801 100644 --- a/core/mocks/generated/trezorcrypto/random.pyi +++ b/core/mocks/generated/trezorcrypto/random.pyi @@ -10,9 +10,10 @@ import builtins # extmod/modtrezorcrypto/modtrezorcrypto-random.h -def bytes(len: int) -> builtins.bytes: +def bytes(len: int, strong: bool = False) -> builtins.bytes: """ - Generate random bytes sequence of length len. + Generate random bytes sequence of length len. If `strong` is set then + maximum sources of entropy are used. """ diff --git a/core/src/apps/management/reset_device/__init__.py b/core/src/apps/management/reset_device/__init__.py index 0c24fef3fc..7a58f9554d 100644 --- a/core/src/apps/management/reset_device/__init__.py +++ b/core/src/apps/management/reset_device/__init__.py @@ -56,7 +56,7 @@ async def reset_device(msg: ResetDevice) -> Success: raise ProcessError("Failed to set PIN") # generate and display internal entropy - int_entropy = random.bytes(32) + int_entropy = random.bytes(32, True) if __debug__: storage.debug.reset_internal_entropy = int_entropy if msg.display_random: diff --git a/core/src/apps/misc/get_entropy.py b/core/src/apps/misc/get_entropy.py index 75b56e7e92..ae4c41bea2 100644 --- a/core/src/apps/misc/get_entropy.py +++ b/core/src/apps/misc/get_entropy.py @@ -19,6 +19,6 @@ async def get_entropy(msg: GetEntropy) -> Entropy: ) size = min(msg.size, 1024) - entropy = random.bytes(size) + entropy = random.bytes(size, True) return Entropy(entropy=entropy) diff --git a/core/src/trezor/crypto/slip39.py b/core/src/trezor/crypto/slip39.py index baa5bce1e9..304f4bdeef 100644 --- a/core/src/trezor/crypto/slip39.py +++ b/core/src/trezor/crypto/slip39.py @@ -443,9 +443,11 @@ def _split_secret( random_share_count = threshold - 2 - shares = [(i, random.bytes(len(shared_secret))) for i in range(random_share_count)] + shares = [ + (i, random.bytes(len(shared_secret), True)) for i in range(random_share_count) + ] - random_part = random.bytes(len(shared_secret) - _DIGEST_LENGTH_BYTES) + random_part = random.bytes(len(shared_secret) - _DIGEST_LENGTH_BYTES, True) digest = _create_digest(random_part, shared_secret) base_shares = shares + [ diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json index 6eef721b58..7b0ad78aae 100644 --- a/tests/ui_tests/fixtures.json +++ b/tests/ui_tests/fixtures.json @@ -784,11 +784,11 @@ "TR_test_pin.py::test_wipe_code_setup": "2f1d097810aa38ff87acef79133ccc735a9523118a1d83420efb84db21a05d97", "TR_test_recovery.py::test_recovery_bip39": "7f969a6623c767e62e50e246bb67e57fdcc7447b8bdd14155d98a6e6c7675a57", "TR_test_recovery.py::test_recovery_slip39_basic": "c2efcb8016f9fa4771297f535e9eed1dc12d898a07936c9fc047b290705a6def", -"TR_test_reset_bip39.py::test_reset_bip39": "57a37b7b0a2c535fafec929bbb15b95b9bb2387b9a64655de9342ce03e03551a", -"TR_test_reset_slip39_advanced.py::test_reset_slip39_advanced[16of16]": "dda360b15510bf207231d7596a5aaab3082ad9e13cd85624d8c9ee6df40d95ae", -"TR_test_reset_slip39_advanced.py::test_reset_slip39_advanced[2of2]": "c7f2bf8cf3fb70baaf6d5799cd50641a01c71e231b23a0d8eed3b416126bec83", -"TR_test_reset_slip39_basic.py::test_reset_slip39_basic[16of16]": "e0925d33d34b0901ce4794adea1c412f4d073c87606a283b619fc1639973ef9b", -"TR_test_reset_slip39_basic.py::test_reset_slip39_basic[1of1]": "18064813219c189a3bc8fd5c1be52929cccc3be58c91e42f1e0fcbd5caf5dcc3", +"TR_test_reset_bip39.py::test_reset_bip39": "7dee2da63f3d220b4a1466b59da6c89a623d1a55c3d5300efe37761d064435db", +"TR_test_reset_slip39_advanced.py::test_reset_slip39_advanced[16of16]": "0442794f3b952b6362d6569eaf15af002e7af5ccd3fedcf5339a9e75a61cb6e7", +"TR_test_reset_slip39_advanced.py::test_reset_slip39_advanced[2of2]": "83d29833c99068a474c7b1c841cd0a88c92d3fba0e471d5e10dcd0d58b164d7a", +"TR_test_reset_slip39_basic.py::test_reset_slip39_basic[16of16]": "11239923e51327c518bcb6123c8e645b0e34174b1857ff64a2e7cbd49b3bcc21", +"TR_test_reset_slip39_basic.py::test_reset_slip39_basic[1of1]": "b51e9c4b3fc6962c128a75676a0ef5a08d72e69abe825707195fcdaf7b114760", "TR_test_tutorial.py::test_tutorial_again_and_skip": "c611a049ccc584fd69abf55bac3b185e370e0680990afb3139b755fd1f41a19e", "TR_test_tutorial.py::test_tutorial_finish": "1ae785e1ff678241aa18a254ae755a002ccd62550cbbd1dd92fa3cbd53d071b0", "TR_test_tutorial.py::test_tutorial_skip": "00a893066c2578f14ae9ab749791f1dde753b43be460d69a304aaae8704cfe8a" @@ -1794,24 +1794,24 @@ "TR_reset_recovery-test_recovery_slip39_basic.py::test_wrong_nth_word[2]": "92606a46453e87a9c59a89e76568c9aad3009d4f0d15aa53cafd0eeb92885a2a", "TR_reset_recovery-test_recovery_slip39_basic_dryrun.py::test_2of3_dryrun": "95aa55b8fc244bb61c60e602683570711b95f829587e4da469f229cac53a99f7", "TR_reset_recovery-test_recovery_slip39_basic_dryrun.py::test_2of3_invalid_seed_dryrun": "31665a411ee0d7da0f5577a349224ee2a285b34fce5519923bc09e918aed27dc", -"TR_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Bip39-backup_flow_bip39]": "ce9b32e21af32d0375528c5b4372b42b26e1fbd0228898b054a24bf720c9ceba", -"TR_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Slip39_Advanced-bac-f67baa1c": "6cd86f6d80aa8fc5d85f1b0f87c6660b1e22f450e406a7c4b5fcb7b6f98f4093", -"TR_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Slip39_Basic-backup-6348e7fe": "43f81d8e72e41cbeec95cfa35f28637c0af5dd25c51c49239c2d88526a8b3dd6", -"TR_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Bip39-backup_flow_bip39]": "481ef01eac32b443e93b4ad01cf347b7a6fae23cd7ff4294a96f69038dda4acd", -"TR_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Slip39_Advanced-backup-dcbda5cf": "892dd4ca104647a7b10a9a7abe25f414a79459a1256d8caa156d88269d199826", -"TR_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Slip39_Basic-backup_fl-1577de4d": "141bff02439fecde33953519dea921d82e65b580a318800b4062dba4316aebc3", +"TR_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Bip39-backup_flow_bip39]": "f60a5c63c74cafbfda26817acf3a409e05cb3746b916565f3510569754f579a0", +"TR_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Slip39_Advanced-bac-f67baa1c": "6d270737f23bd05874d9a7a7234f42fb5e0cec3769dee0186c3337c7c78b79a8", +"TR_reset_recovery-test_reset_backup.py::test_skip_backup_manual[BackupType.Slip39_Basic-backup-6348e7fe": "809e150906fc39a019d96c88107032ab36a02796ebe6fb5c05075530a1109f60", +"TR_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Bip39-backup_flow_bip39]": "fd5655cdfe6e76fd15ef57712c4ba0439ce20ef37f4ce0e540c1109f924e084c", +"TR_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Slip39_Advanced-backup-dcbda5cf": "a485b1ec23a04252daf716bde35a344984e538b297d86edd85a2ad30ed3e3a0a", +"TR_reset_recovery-test_reset_backup.py::test_skip_backup_msg[BackupType.Slip39_Basic-backup_fl-1577de4d": "ce97ecddf443af2f99d4de0403ad83f4db1d9b3db9c0f58cc429d68165785212", "TR_reset_recovery-test_reset_bip39_t2.py::test_already_initialized": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_reset_recovery-test_reset_bip39_t2.py::test_failed_pin": "6b4f02ba25b4199d426a8238bb28fff6bfbeabe1f921352a19b3d651921a4b2b", -"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_device": "c9ae1b520663693155b17be4cc69c45f18026fcaa67934a974852bebe1474019", -"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_device_192": "1c8dc7da58fca6d5e4519ee250517a6263ba46f04c72d496b52b130d80dfddcc", -"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_device_pin": "7d196f117fd495b8b87b65e7181fee3019a7298c79e97fda44c46321ab9919a1", -"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_failed_check": "95ab7a3593621b7595e7d7945e73e4a7c475d37bafb61410336765dd32b4dc83", -"TR_reset_recovery-test_reset_recovery_bip39.py::test_reset_recovery": "7473c5202491021ffc0347665f495a07734c4ab52217058ce744683b96b179dd", -"TR_reset_recovery-test_reset_recovery_slip39_advanced.py::test_reset_recovery": "0e127d30feeea33985959bb531174cd5c4e1e59481c11c92bc6a5e97a77811d2", -"TR_reset_recovery-test_reset_recovery_slip39_basic.py::test_reset_recovery": "70766853f7bc80d743de6fd1c99ac7111cbb243626379f71539f20efe0f7f8c8", -"TR_reset_recovery-test_reset_slip39_advanced.py::test_reset_device_slip39_advanced": "4e9173dd4894e1094e7f121cc898668f2c4f834ac3613e39cf0c3e2a75c3b424", -"TR_reset_recovery-test_reset_slip39_basic.py::test_reset_device_slip39_basic": "02b8ef44d443b557457628c21f4ad0d15d4acc1d65f14efefe889055067053b9", -"TR_reset_recovery-test_reset_slip39_basic.py::test_reset_device_slip39_basic_256": "1cc4431bd4e7ce4851a86fafdcfd75f5acce3fa4a6f18aaaafb3c2906ac364cc", +"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_device": "ca712743e8937bc7db6265810964d20d292f8166315fd9c30c9a3b5ae82ab6c9", +"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_device_192": "189b6effb1666f250bec4813028f8af24407c08e6be14287dca563db1c04afd6", +"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_device_pin": "b236293539ac37adb87fb07bfa6de5b4079ded32c437eb79f3fa58fd73a781bd", +"TR_reset_recovery-test_reset_bip39_t2.py::test_reset_failed_check": "e3f1151b8480d47c00d10073fab067096f252a7982abe828f3208efb2aa6220b", +"TR_reset_recovery-test_reset_recovery_bip39.py::test_reset_recovery": "daccf2d9264bd4776a9d2201494e5b41f2960ad7ceaa5090eabe640009af88eb", +"TR_reset_recovery-test_reset_recovery_slip39_advanced.py::test_reset_recovery": "29c42c776be9cdba7a47a4df4454480e0fce21131692d4ebdd9d1ac2d343380a", +"TR_reset_recovery-test_reset_recovery_slip39_basic.py::test_reset_recovery": "d6c56240ad61f1aeaf28c5de0aafa2970bbb37a7b55d01890a4fcd3dbb1db633", +"TR_reset_recovery-test_reset_slip39_advanced.py::test_reset_device_slip39_advanced": "19492556256195acbab3865f663cb3127d1bfb8a7d27b2000b870d082f8575a3", +"TR_reset_recovery-test_reset_slip39_basic.py::test_reset_device_slip39_basic": "e79608b2335fba3da5b52a896e4ce0095acb5305688993617e09329b8220087b", +"TR_reset_recovery-test_reset_slip39_basic.py::test_reset_device_slip39_basic_256": "a573066d7bedd8318c412de713743bdf3ac50775a634c7ee55435fd37e3a2987", "TR_ripple-test_get_address.py::test_ripple_get_address": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ripple-test_get_address.py::test_ripple_get_address_other": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", "TR_ripple-test_sign_tx.py::test_ripple_sign_invalid_fee": "8c801bd0142e5c1ad4aad50b34c7debb1b8f17a2e0a87eb7f95531b9fd15e095", @@ -1915,9 +1915,9 @@ "TR_test_msg_applysettings.py::test_safety_checks": "83080cba06af0a9c47ff0316a38096a17d21fcd7034b7878db9b4e6f9c01ad06", "TR_test_msg_backup_device.py::test_backup_bip39": "a765ee7fbf3e763d7fbfee248d7afe159e1986975e1d94635a50631828e6695b", "TR_test_msg_backup_device.py::test_backup_slip39_advanced[click_info]": "b6e34f1ccd560f41f3b33b4755e900089797898a66c8fdfd28d9f61274e873f4", -"TR_test_msg_backup_device.py::test_backup_slip39_advanced[no_click_info]": "ef0eaf62ca8e071a696b34b794541930e6a85b7008d3d414406a714e81f93431", +"TR_test_msg_backup_device.py::test_backup_slip39_advanced[no_click_info]": "d03ec76ae176f4a7dfd3f4df83fdecd8dfd1ef29bec85e5c21e3ec97937b970b", "TR_test_msg_backup_device.py::test_backup_slip39_basic[click_info]": "b6e34f1ccd560f41f3b33b4755e900089797898a66c8fdfd28d9f61274e873f4", -"TR_test_msg_backup_device.py::test_backup_slip39_basic[no_click_info]": "22c4d375b8ac2f7bcc2c65c5260eb3e72e4ee20524fa65d9457ba41fe61f1111", +"TR_test_msg_backup_device.py::test_backup_slip39_basic[no_click_info]": "9df6f18e33ff9412f0817dc2f0da2b96b1df4fed0252fbe09e1ee0f521dcba47", "TR_test_msg_backup_device.py::test_interrupt_backup_fails": "1139f673473fbf725b2ee52d4965917c6a72676e69b073707f40b556a48f4b79", "TR_test_msg_backup_device.py::test_no_backup_fails": "60c13acb4f8e40ee32f9d01415cbcbd75ffcd6a4015003d93562e84c3901a62f", "TR_test_msg_backup_device.py::test_no_backup_show_entropy_fails": "f49c8d846c2d56a575f0ad49463845ba641b02656783e4fcfc67d74e8fa671dd",