diff --git a/common/protob/messages-crypto.proto b/common/protob/messages-crypto.proto index 38429790d..4953e6159 100644 --- a/common/protob/messages-crypto.proto +++ b/common/protob/messages-crypto.proto @@ -97,8 +97,8 @@ message ECDHSessionKey { * @next Failure */ message CosiCommit { - repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node - optional bytes data = 2; // Data to be signed + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + optional bytes data = 2 [deprecated=true]; // Data to be signed. Deprecated in 1.10.2, the field is not needed, since CoSi commitments are no longer deterministic. } /** diff --git a/core/.changelog.d/2130.changed b/core/.changelog.d/2130.changed deleted file mode 100644 index 16dd999c3..000000000 --- a/core/.changelog.d/2130.changed +++ /dev/null @@ -1 +0,0 @@ -Remove power-down power-up cycle from touch controller initialization in firmware diff --git a/core/.changelog.d/2230.added b/core/.changelog.d/2230.added deleted file mode 100644 index 7e9b19fa8..000000000 --- a/core/.changelog.d/2230.added +++ /dev/null @@ -1 +0,0 @@ -Add model R emulator diff --git a/core/.changelog.d/2232.added b/core/.changelog.d/2232.added deleted file mode 100644 index 4fb98c8fd..000000000 --- a/core/.changelog.d/2232.added +++ /dev/null @@ -1 +0,0 @@ -Add support for Monero HF15 features. diff --git a/core/.changelog.d/2243.added b/core/.changelog.d/2243.added deleted file mode 100644 index c595a95a2..000000000 --- a/core/.changelog.d/2243.added +++ /dev/null @@ -1 +0,0 @@ -Add basic Trezor Model R hardware support diff --git a/core/.changelog.d/2249.added b/core/.changelog.d/2249.added deleted file mode 100644 index a93105eb3..000000000 --- a/core/.changelog.d/2249.added +++ /dev/null @@ -1 +0,0 @@ -Show the fee rate on the singing confirmation screen. diff --git a/core/.changelog.d/2261.changed b/core/.changelog.d/2261.changed deleted file mode 100644 index 48b6f4ae2..000000000 --- a/core/.changelog.d/2261.changed +++ /dev/null @@ -1 +0,0 @@ -Updated secp256k1-zkp. diff --git a/core/.changelog.d/2284.added b/core/.changelog.d/2284.added deleted file mode 100644 index d6fbe284e..000000000 --- a/core/.changelog.d/2284.added +++ /dev/null @@ -1 +0,0 @@ -Jump and stay in bootloader from firmware through SVC call reverse trampoline. diff --git a/core/.changelog.d/2297.added b/core/.changelog.d/2297.added deleted file mode 100644 index 1ca22a4af..000000000 --- a/core/.changelog.d/2297.added +++ /dev/null @@ -1 +0,0 @@ -Expose raw pixel access to Rust diff --git a/core/.changelog.d/2300.added b/core/.changelog.d/2300.added deleted file mode 100644 index 63c33ae2b..000000000 --- a/core/.changelog.d/2300.added +++ /dev/null @@ -1 +0,0 @@ -Add RGB LED for Model R diff --git a/core/.changelog.d/2313.changed b/core/.changelog.d/2313.changed deleted file mode 100644 index bc3d8084f..000000000 --- a/core/.changelog.d/2313.changed +++ /dev/null @@ -1 +0,0 @@ -Cardano internal refactors diff --git a/core/.changelog.d/2324.added b/core/.changelog.d/2324.added deleted file mode 100644 index c4a38a07c..000000000 --- a/core/.changelog.d/2324.added +++ /dev/null @@ -1 +0,0 @@ -Boardloader capabilities structure diff --git a/core/.changelog.d/2354.added b/core/.changelog.d/2354.added deleted file mode 100644 index b05831806..000000000 --- a/core/.changelog.d/2354.added +++ /dev/null @@ -1 +0,0 @@ -Support for Cardano Babbage era transaction items diff --git a/core/.changelog.d/2354.changed b/core/.changelog.d/2354.changed deleted file mode 100644 index af7c964c8..000000000 --- a/core/.changelog.d/2354.changed +++ /dev/null @@ -1,2 +0,0 @@ -Allow Cardano's `required_signers` in ordinary and multisig transactions -Allow Cardano's `datum_hash` in non-script outputs diff --git a/core/.changelog.d/2355.added b/core/.changelog.d/2355.added deleted file mode 100644 index cb6264b39..000000000 --- a/core/.changelog.d/2355.added +++ /dev/null @@ -1 +0,0 @@ -Add "Show All"/"Show Simple" choice to Cardano transaction signing diff --git a/core/.changelog.d/2380.added b/core/.changelog.d/2380.added deleted file mode 100644 index e646a026f..000000000 --- a/core/.changelog.d/2380.added +++ /dev/null @@ -1 +0,0 @@ -Documentation for embedded C+Rust debugging diff --git a/core/.changelog.d/2394.added b/core/.changelog.d/2394.added deleted file mode 100644 index 49b957304..000000000 --- a/core/.changelog.d/2394.added +++ /dev/null @@ -1 +0,0 @@ -Show thousands separator when displaying large amounts. diff --git a/core/.changelog.d/2415.fixed b/core/.changelog.d/2415.fixed deleted file mode 100644 index a724ef5c1..000000000 --- a/core/.changelog.d/2415.fixed +++ /dev/null @@ -1 +0,0 @@ -Ensure correct order when verifying external inputs in Bitcoin signing. diff --git a/core/.changelog.d/2422.fixed b/core/.changelog.d/2422.fixed deleted file mode 100644 index 1fc900a63..000000000 --- a/core/.changelog.d/2422.fixed +++ /dev/null @@ -1 +0,0 @@ -Fix Decred transaction weight calculation. diff --git a/core/.changelog.d/2433.removed b/core/.changelog.d/2433.removed deleted file mode 100644 index 6daff5d0a..000000000 --- a/core/.changelog.d/2433.removed +++ /dev/null @@ -1 +0,0 @@ -Remove firmware dumping capability. diff --git a/core/.changelog.d/642.changed b/core/.changelog.d/642.changed deleted file mode 100644 index c19556c29..000000000 --- a/core/.changelog.d/642.changed +++ /dev/null @@ -1 +0,0 @@ -Refactor and cleanup of Monero code. diff --git a/core/.changelog.d/642.removed b/core/.changelog.d/642.removed deleted file mode 100644 index 66b75e098..000000000 --- a/core/.changelog.d/642.removed +++ /dev/null @@ -1 +0,0 @@ -Removed support for obsolete Monero hardfork 12 and below diff --git a/core/.changelog.d/973.fixed b/core/.changelog.d/973.fixed deleted file mode 100644 index c03f3f63f..000000000 --- a/core/.changelog.d/973.fixed +++ /dev/null @@ -1 +0,0 @@ -_(Emulator)_ Emulator window will always react to shutdown events, even while waiting for USB packets. diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index a35333d42..8c725e75a 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -4,6 +4,39 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [2.5.2] (17th August 2022) + +### Added +- Add model R emulator [#2230] +- Add support for Monero HF15 features. [#2232] +- Add basic Trezor Model R hardware support [#2243] +- Show the fee rate on the signing confirmation screen. [#2249] +- Jump and stay in bootloader from firmware through SVC call reverse trampoline. [#2284] +- Expose raw pixel access to Rust [#2297] +- Add RGB LED for Model R [#2300] +- Boardloader capabilities structure [#2324] +- Support for Cardano Babbage era transaction items [#2354] +- Add "Show All"/"Show Simple" choice to Cardano transaction signing [#2355] +- Documentation for embedded C+Rust debugging [#2380] +- Show thousands separator when displaying large amounts. [#2394] + +### Changed +- Refactor and cleanup of Monero code. [#642] +- Remove power-down power-up cycle from touch controller initialization in firmware [#2130] +- Updated secp256k1-zkp. [#2261] +- Cardano internal refactors [#2313] +- Allow Cardano's `required_signers` in ordinary and multisig transactions + Allow Cardano's `datum_hash` in non-script outputs [#2354] + +### Removed +- Removed support for obsolete Monero hardfork 12 and below [#642] +- Remove firmware dumping capability. [#2433] + +### Fixed +- _(Emulator)_ Emulator window will always react to shutdown events, even while waiting for USB packets. [#973] +- Ensure correct order when verifying external inputs in Bitcoin signing. [#2415] +- Fix Decred transaction weight calculation. [#2422] + ## 2.5.1 [18th May 2022] @@ -483,10 +516,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#24]: https://github.com/trezor/trezor-firmware/pull/24 [#379]: https://github.com/trezor/trezor-firmware/pull/379 +[#642]: https://github.com/trezor/trezor-firmware/pull/642 [#741]: https://github.com/trezor/trezor-firmware/pull/741 [#800]: https://github.com/trezor/trezor-firmware/pull/800 [#948]: https://github.com/trezor/trezor-firmware/pull/948 [#958]: https://github.com/trezor/trezor-firmware/pull/958 +[#973]: https://github.com/trezor/trezor-firmware/pull/973 [#982]: https://github.com/trezor/trezor-firmware/pull/982 [#1018]: https://github.com/trezor/trezor-firmware/pull/1018 [#1027]: https://github.com/trezor/trezor-firmware/pull/1027 @@ -594,9 +629,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#2077]: https://github.com/trezor/trezor-firmware/pull/2077 [#2100]: https://github.com/trezor/trezor-firmware/pull/2100 [#2114]: https://github.com/trezor/trezor-firmware/pull/2114 +[#2130]: https://github.com/trezor/trezor-firmware/pull/2130 [#2135]: https://github.com/trezor/trezor-firmware/pull/2135 [#2144]: https://github.com/trezor/trezor-firmware/pull/2144 [#2166]: https://github.com/trezor/trezor-firmware/pull/2166 [#2167]: https://github.com/trezor/trezor-firmware/pull/2167 [#2181]: https://github.com/trezor/trezor-firmware/pull/2181 +[#2230]: https://github.com/trezor/trezor-firmware/pull/2230 +[#2232]: https://github.com/trezor/trezor-firmware/pull/2232 [#2239]: https://github.com/trezor/trezor-firmware/pull/2239 +[#2243]: https://github.com/trezor/trezor-firmware/pull/2243 +[#2249]: https://github.com/trezor/trezor-firmware/pull/2249 +[#2261]: https://github.com/trezor/trezor-firmware/pull/2261 +[#2284]: https://github.com/trezor/trezor-firmware/pull/2284 +[#2297]: https://github.com/trezor/trezor-firmware/pull/2297 +[#2300]: https://github.com/trezor/trezor-firmware/pull/2300 +[#2313]: https://github.com/trezor/trezor-firmware/pull/2313 +[#2324]: https://github.com/trezor/trezor-firmware/pull/2324 +[#2354]: https://github.com/trezor/trezor-firmware/pull/2354 +[#2355]: https://github.com/trezor/trezor-firmware/pull/2355 +[#2380]: https://github.com/trezor/trezor-firmware/pull/2380 +[#2394]: https://github.com/trezor/trezor-firmware/pull/2394 +[#2415]: https://github.com/trezor/trezor-firmware/pull/2415 +[#2422]: https://github.com/trezor/trezor-firmware/pull/2422 +[#2433]: https://github.com/trezor/trezor-firmware/pull/2433 diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h index 3aac1d9b3..17fea3cbc 100644 --- a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h @@ -240,6 +240,25 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2( mod_trezorcrypto_ed25519_cosi_combine_signatures_obj, mod_trezorcrypto_ed25519_cosi_combine_signatures); +/// def cosi_commit() -> tuple[bytes, bytes]: +/// """ +/// Generate a nonce and commitment for the CoSi cosigning scheme. +/// """ +STATIC mp_obj_t mod_trezorcrypto_ed25519_cosi_commit() { + vstr_t nonce = {0}; + vstr_t commitment = {0}; + vstr_init_len(&nonce, 32); + vstr_init_len(&commitment, 32); + ed25519_cosi_commit(*(ed25519_secret_key *)nonce.buf, + *(ed25519_public_key *)commitment.buf); + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + tuple->items[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &nonce); + tuple->items[1] = mp_obj_new_str_from_vstr(&mp_type_bytes, &commitment); + return MP_OBJ_FROM_PTR(tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorcrypto_ed25519_cosi_commit_obj, + mod_trezorcrypto_ed25519_cosi_commit); + /// def cosi_sign( /// secret_key: bytes, /// message: bytes, @@ -272,12 +291,15 @@ STATIC mp_obj_t mod_trezorcrypto_ed25519_cosi_sign(size_t n_args, } vstr_t sig = {0}; vstr_init_len(&sig, sizeof(ed25519_cosi_signature)); - ; - ed25519_cosi_sign(msg.buf, msg.len, *(const ed25519_secret_key *)sk.buf, - *(const ed25519_secret_key *)nonce.buf, - *(const ed25519_public_key *)sigR.buf, - *(const ed25519_secret_key *)pk.buf, - *(ed25519_cosi_signature *)sig.buf); + if (0 != ed25519_cosi_sign(msg.buf, msg.len, + *(const ed25519_secret_key *)sk.buf, + *(const ed25519_secret_key *)nonce.buf, + *(const ed25519_public_key *)sigR.buf, + *(const ed25519_secret_key *)pk.buf, + *(ed25519_cosi_signature *)sig.buf)) { + vstr_clear(&sig); + mp_raise_ValueError("Signing failed"); + } return mp_obj_new_str_from_vstr(&mp_type_bytes, &sig); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN( @@ -301,6 +323,8 @@ STATIC const mp_rom_map_elem_t mod_trezorcrypto_ed25519_globals_table[] = { MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_combine_publickeys_obj)}, {MP_ROM_QSTR(MP_QSTR_cosi_combine_signatures), MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_combine_signatures_obj)}, + {MP_ROM_QSTR(MP_QSTR_cosi_commit), + MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_commit_obj)}, {MP_ROM_QSTR(MP_QSTR_cosi_sign), MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_sign_obj)}, }; diff --git a/core/mocks/generated/trezorcrypto/ed25519.pyi b/core/mocks/generated/trezorcrypto/ed25519.pyi index 54d527a1e..451b34682 100644 --- a/core/mocks/generated/trezorcrypto/ed25519.pyi +++ b/core/mocks/generated/trezorcrypto/ed25519.pyi @@ -53,6 +53,13 @@ def cosi_combine_signatures(R: bytes, signatures: list[bytes]) -> bytes: """ +# extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h +def cosi_commit() -> tuple[bytes, bytes]: + """ + Generate a nonce and commitment for the CoSi cosigning scheme. + """ + + # extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h def cosi_sign( secret_key: bytes, diff --git a/core/src/trezor/messages.py b/core/src/trezor/messages.py index 17b6e8f04..b8d6b9aed 100644 --- a/core/src/trezor/messages.py +++ b/core/src/trezor/messages.py @@ -1928,13 +1928,11 @@ if TYPE_CHECKING: class CosiCommit(protobuf.MessageType): address_n: "list[int]" - data: "bytes | None" def __init__( self, *, address_n: "list[int] | None" = None, - data: "bytes | None" = None, ) -> None: pass diff --git a/core/tests/test_trezor.crypto.curve.ed25519_cosi.py b/core/tests/test_trezor.crypto.curve.ed25519_cosi.py index 7a398241e..92d65869b 100644 --- a/core/tests/test_trezor.crypto.curve.ed25519_cosi.py +++ b/core/tests/test_trezor.crypto.curve.ed25519_cosi.py @@ -26,8 +26,7 @@ class TestCryptoEd25519Cosi(unittest.TestCase): nonces = [None] * N Rs = [None] * N for j in range(N): - nonces[j] = ed25519.generate_secret() - Rs[j] = ed25519.publickey(nonces[j]) + nonces[j], Rs[j] = ed25519.cosi_commit() R = ed25519.cosi_combine_publickeys(Rs) diff --git a/crypto/ed25519-donna/ed25519.c b/crypto/ed25519-donna/ed25519.c index e25407a2a..6b7413421 100644 --- a/crypto/ed25519-donna/ed25519.c +++ b/crypto/ed25519-donna/ed25519.c @@ -18,6 +18,7 @@ #include "ed25519.h" #include "ed25519-hash-custom.h" +#include "rand.h" #include "memzero.h" /* @@ -50,16 +51,34 @@ ED25519_FN(ed25519_publickey) (const ed25519_secret_key sk, ed25519_public_key p } void +ED25519_FN(ed25519_cosi_commit) (ed25519_secret_key nonce, ed25519_public_key commitment) { + bignum256modm r = {0}; + ge25519 ALIGN(16) R; + unsigned char extnonce[64] = {0}; + + /* r = random512 mod L */ + random_buffer(extnonce, sizeof(extnonce)); + expand256_modm(r, extnonce, sizeof(extnonce)); + memzero(&extnonce, sizeof(extnonce)); + contract256_modm(nonce, r); + + /* R = rB */ + ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r); + memzero(&r, sizeof(r)); + ge25519_pack(commitment, &R); +} + +int ED25519_FN(ed25519_cosi_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig) { bignum256modm r = {0}, S = {0}, a = {0}; - hash_512bits extsk = {0}, extnonce = {0}, hram = {0}; + hash_512bits extsk = {0}, hram = {0}; ed25519_extsk(extsk, sk); - ed25519_extsk(extnonce, nonce); - /* r = nonce */ - expand256_modm(r, extnonce, 32); - memzero(&extnonce, sizeof(extnonce)); + /* r */ + expand_raw256_modm(r, nonce); + if (!is_reduced256_modm(r)) + return -1; /* S = H(R,A,m).. */ ed25519_hram(hram, R, pk, m, mlen); @@ -77,6 +96,8 @@ ED25519_FN(ed25519_cosi_sign) (const unsigned char *m, size_t mlen, const ed2551 /* S = (r + H(R,A,m)a) mod L */ contract256_modm(sig, S); + + return 0; } void @@ -155,7 +176,7 @@ ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed2551 /* S */ expand_raw256_modm(S, RS + 32); if (!is_reduced256_modm(S)) - return -1; + return -1; /* SB - H(R,A,m)A */ ge25519_double_scalarmult_vartime(&R, &A, hram, S); diff --git a/crypto/ed25519-donna/ed25519.h b/crypto/ed25519-donna/ed25519.h index f01957561..b5fe78950 100644 --- a/crypto/ed25519-donna/ed25519.h +++ b/crypto/ed25519-donna/ed25519.h @@ -35,7 +35,8 @@ void curve25519_scalarmult_basepoint(curve25519_key mypublic, const curve25519_k int ed25519_cosi_combine_publickeys(ed25519_public_key res, CONST ed25519_public_key *pks, size_t n); void ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, CONST ed25519_cosi_signature *sigs, size_t n); -void ed25519_cosi_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key key, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig); +void ed25519_cosi_commit(ed25519_secret_key nonce, ed25519_public_key commitment); +int ed25519_cosi_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key key, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig); #if defined(__cplusplus) } diff --git a/crypto/tests/test_check.c b/crypto/tests/test_check.c index 9a417f493..437e1e75e 100644 --- a/crypto/tests/test_check.c +++ b/crypto/tests/test_check.c @@ -6885,8 +6885,7 @@ START_TEST(test_ed25519_cosi) { /* phase 1: create nonces, commitments (R values) and combine commitments */ for (int j = 0; j < N; j++) { - generate_rfc6979(nonces[j], &rng); - ed25519_publickey(nonces[j], Rs[j]); + ed25519_cosi_commit(nonces[j], Rs[j]); } res = ed25519_cosi_combine_publickeys(R, Rs, N); ck_assert_int_eq(res, 0); @@ -6894,7 +6893,9 @@ START_TEST(test_ed25519_cosi) { MARK_SECRET_DATA(keys, sizeof(keys)); /* phase 2: sign and combine signatures */ for (int j = 0; j < N; j++) { - ed25519_cosi_sign(msg, sizeof(msg), keys[j], nonces[j], R, pk, sigs[j]); + res = ed25519_cosi_sign(msg, sizeof(msg), keys[j], nonces[j], R, pk, + sigs[j]); + ck_assert_int_eq(res, 0); } UNMARK_SECRET_DATA(sigs, sizeof(sigs)); diff --git a/legacy/firmware/.changelog.d/2249.added b/legacy/firmware/.changelog.d/2249.added deleted file mode 100644 index a93105eb3..000000000 --- a/legacy/firmware/.changelog.d/2249.added +++ /dev/null @@ -1 +0,0 @@ -Show the fee rate on the singing confirmation screen. diff --git a/legacy/firmware/.changelog.d/2261.changed b/legacy/firmware/.changelog.d/2261.changed deleted file mode 100644 index 48b6f4ae2..000000000 --- a/legacy/firmware/.changelog.d/2261.changed +++ /dev/null @@ -1 +0,0 @@ -Updated secp256k1-zkp. diff --git a/legacy/firmware/.changelog.d/2394.added b/legacy/firmware/.changelog.d/2394.added deleted file mode 100644 index 49b957304..000000000 --- a/legacy/firmware/.changelog.d/2394.added +++ /dev/null @@ -1 +0,0 @@ -Show thousands separator when displaying large amounts. diff --git a/legacy/firmware/.changelog.d/2422.fixed b/legacy/firmware/.changelog.d/2422.fixed deleted file mode 100644 index da81d2d1d..000000000 --- a/legacy/firmware/.changelog.d/2422.fixed +++ /dev/null @@ -1 +0,0 @@ -Fix rounding in fee rate computation. diff --git a/legacy/firmware/.changelog.d/2433.removed b/legacy/firmware/.changelog.d/2433.removed deleted file mode 100644 index 6daff5d0a..000000000 --- a/legacy/firmware/.changelog.d/2433.removed +++ /dev/null @@ -1 +0,0 @@ -Remove firmware dumping capability. diff --git a/legacy/firmware/CHANGELOG.md b/legacy/firmware/CHANGELOG.md index b7b99f84c..97247e77a 100644 --- a/legacy/firmware/CHANGELOG.md +++ b/legacy/firmware/CHANGELOG.md @@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [1.11.2] (17th August 2022) + +### Added +- Show the fee rate on the signing confirmation screen. [#2249] +- Show thousands separator when displaying large amounts. [#2394] + +### Changed +- Updated secp256k1-zkp. [#2261] + +### Removed +- Remove firmware dumping capability. [#2433] + +### Security +- Fix potential security issues in recovery workflow. +- Fix key extraction vulnerability in Cothority Collective Signing (CoSi). +- Fix nonce bias in CoSi signing. + ## 1.11.1 [18th May 2022] @@ -543,3 +560,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#2144]: https://github.com/trezor/trezor-firmware/pull/2144 [#2181]: https://github.com/trezor/trezor-firmware/pull/2181 [#2239]: https://github.com/trezor/trezor-firmware/pull/2239 +[#2249]: https://github.com/trezor/trezor-firmware/pull/2249 +[#2261]: https://github.com/trezor/trezor-firmware/pull/2261 +[#2394]: https://github.com/trezor/trezor-firmware/pull/2394 +[#2422]: https://github.com/trezor/trezor-firmware/pull/2422 +[#2433]: https://github.com/trezor/trezor-firmware/pull/2433 diff --git a/legacy/firmware/fsm.c b/legacy/firmware/fsm.c index b7a5e723d..756a6a740 100644 --- a/legacy/firmware/fsm.c +++ b/legacy/firmware/fsm.c @@ -44,7 +44,6 @@ #include "protect.h" #include "recovery.h" #include "reset.h" -#include "rfc6979.h" #include "rng.h" #include "secp256k1.h" #include "signing.h" diff --git a/legacy/firmware/fsm_msg_crypto.h b/legacy/firmware/fsm_msg_crypto.h index 595f47dfe..1cdd6d541 100644 --- a/legacy/firmware/fsm_msg_crypto.h +++ b/legacy/firmware/fsm_msg_crypto.h @@ -17,6 +17,10 @@ * along with this library. If not, see . */ +static uint8_t cosi_nonce[32] = {0}; +static uint8_t cosi_commitment[32] = {0}; +static bool cosi_nonce_is_set = false; + void fsm_msgCipherKeyValue(const CipherKeyValue *msg) { CHECK_INITIALIZED @@ -256,8 +260,6 @@ void fsm_msgCosiCommit(const CosiCommit *msg) { CHECK_INITIALIZED - CHECK_PARAM(msg->has_data, _("No data provided")); - CHECK_PIN if (!fsm_checkCosiPath(msg->address_n_count, msg->address_n)) { @@ -265,30 +267,21 @@ void fsm_msgCosiCommit(const CosiCommit *msg) { return; } - layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, - msg->data.size, false); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) return; - uint8_t nonce[32]; - sha256_Raw(msg->data.bytes, msg->data.size, nonce); - rfc6979_state rng; - init_rfc6979(node->private_key, nonce, NULL, &rng); - generate_rfc6979(nonce, &rng); + if (!cosi_nonce_is_set) { + ed25519_cosi_commit(cosi_nonce, cosi_commitment); + cosi_nonce_is_set = true; + } resp->has_commitment = true; resp->has_pubkey = true; resp->commitment.size = 32; resp->pubkey.size = 32; - ed25519_publickey(nonce, resp->commitment.bytes); + memcpy(resp->commitment.bytes, cosi_commitment, sizeof(cosi_commitment)); ed25519_publickey(node->private_key, resp->pubkey.bytes); msg_write(MessageType_MessageType_CosiCommitment, resp); @@ -306,6 +299,12 @@ void fsm_msgCosiSign(const CosiSign *msg) { CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32, _("Invalid global pubkey")); + if (!cosi_nonce_is_set) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("CoSi nonce not set")); + layoutHome(); + return; + } + if (!fsm_checkCosiPath(msg->address_n_count, msg->address_n)) { layoutHome(); return; @@ -313,8 +312,8 @@ void fsm_msgCosiSign(const CosiSign *msg) { CHECK_PIN - layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, - msg->data.size, true); + layoutCosiSign(msg->address_n, msg->address_n_count, msg->data.bytes, + msg->data.size); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -325,18 +324,16 @@ void fsm_msgCosiSign(const CosiSign *msg) { msg->address_n_count, NULL); if (!node) return; - uint8_t nonce[32]; - sha256_Raw(msg->data.bytes, msg->data.size, nonce); - rfc6979_state rng; - init_rfc6979(node->private_key, nonce, NULL, &rng); - generate_rfc6979(nonce, &rng); - resp->signature.size = 32; + cosi_nonce_is_set = false; - ed25519_cosi_sign(msg->data.bytes, msg->data.size, node->private_key, nonce, - msg->global_commitment.bytes, msg->global_pubkey.bytes, - resp->signature.bytes); - - msg_write(MessageType_MessageType_CosiSignature, resp); + if (ed25519_cosi_sign(msg->data.bytes, msg->data.size, node->private_key, + cosi_nonce, msg->global_commitment.bytes, + msg->global_pubkey.bytes, resp->signature.bytes) == 0) { + msg_write(MessageType_MessageType_CosiSignature, resp); + } else { + fsm_sendFailure(FailureType_Failure_FirmwareError, NULL); + } + memzero(cosi_nonce, sizeof(cosi_nonce)); layoutHome(); } diff --git a/legacy/firmware/layout2.c b/legacy/firmware/layout2.c index 48452c056..1334b7e34 100644 --- a/legacy/firmware/layout2.c +++ b/legacy/firmware/layout2.c @@ -1220,18 +1220,13 @@ static inline bool is_slip18(const uint32_t *address_n, (address_n[1] & PATH_UNHARDEN_MASK) <= 9; } -void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, - const uint8_t *data, uint32_t len, bool final_sign) { - char *desc = final_sign ? _("CoSi sign message?") : _("CoSi commit message?"); +void layoutCosiSign(const uint32_t *address_n, size_t address_n_count, + const uint8_t *data, uint32_t len) { + char *desc = _("CoSi sign message?"); char desc_buf[32] = {0}; if (is_slip18(address_n, address_n_count)) { - if (final_sign) { - strlcpy(desc_buf, _("CoSi sign index #?"), sizeof(desc_buf)); - desc_buf[16] = '0' + (address_n[1] & PATH_UNHARDEN_MASK); - } else { - strlcpy(desc_buf, _("CoSi commit index #?"), sizeof(desc_buf)); - desc_buf[18] = '0' + (address_n[1] & PATH_UNHARDEN_MASK); - } + strlcpy(desc_buf, _("CoSi sign index #?"), sizeof(desc_buf)); + desc_buf[16] = '0' + (address_n[1] & PATH_UNHARDEN_MASK); desc = desc_buf; } char str[4][17] = {0}; diff --git a/legacy/firmware/layout2.h b/legacy/firmware/layout2.h index 77966d720..7f88da70f 100644 --- a/legacy/firmware/layout2.h +++ b/legacy/firmware/layout2.h @@ -105,8 +105,8 @@ void layoutNEMTransferPayload(const uint8_t *payload, size_t length, void layoutNEMMosaicDescription(const char *description); void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network); -void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, - const uint8_t *data, uint32_t len, bool final_sign); +void layoutCosiSign(const uint32_t *address_n, size_t address_n_count, + const uint8_t *data, uint32_t len); void layoutConfirmAutoLockDelay(uint32_t delay_ms); void layoutConfirmSafetyChecks(SafetyCheckLevel safety_checks_level); diff --git a/legacy/firmware/protob/messages-crypto.options b/legacy/firmware/protob/messages-crypto.options index 36a80ff1c..c4774819c 100644 --- a/legacy/firmware/protob/messages-crypto.options +++ b/legacy/firmware/protob/messages-crypto.options @@ -6,7 +6,7 @@ CipherKeyValue.iv max_size:16 CipheredKeyValue.value max_size:1024 CosiCommit.address_n max_count:8 -CosiCommit.data max_size:32 +CosiCommit.data type:FT_IGNORE CosiCommitment.commitment max_size:32 CosiCommitment.pubkey max_size:32 diff --git a/legacy/firmware/recovery.c b/legacy/firmware/recovery.c index 317fb2e20..6aae892ef 100644 --- a/legacy/firmware/recovery.c +++ b/legacy/firmware/recovery.c @@ -37,12 +37,12 @@ /* number of words expected in the new seed */ static uint32_t word_count; -/* recovery mode: - * 0: not recovering - * 1: recover by scrambled plain text words - * 2: recover by matrix entry - */ -static int awaiting_word = 0; +/* recovery mode */ +static enum { + RECOVERY_NONE = 0, // recovery not in progress + RECOVERY_SCRAMBLED = 1, // standard recovery by scrambled plain text words + RECOVERY_MATRIX = 2, // advanced recovery by matrix entry +} recovery_mode = RECOVERY_NONE; /* True if we should not write anything back to config * (can be used for testing seed for correctness). @@ -145,7 +145,7 @@ static void format_number(char *dest, int number) { static void recovery_request(void) { WordRequest resp = {0}; memzero(&resp, sizeof(WordRequest)); - if (awaiting_word == 1) { + if (recovery_mode == RECOVERY_SCRAMBLED) { resp.type = WordRequestType_WordRequestType_Plain; } else if (word_index % 4 == 3) { resp.type = WordRequestType_WordRequestType_Matrix6; @@ -217,7 +217,9 @@ static void recovery_done(void) { fsm_sendFailure(FailureType_Failure_DataError, _("Invalid seed, are words in correct order?")); } - awaiting_word = 0; + memzero(words, sizeof(words)); + word_pincode = 0; + recovery_mode = RECOVERY_NONE; layoutHome(); } @@ -476,6 +478,9 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool _dry_run) { if (_word_count != 12 && _word_count != 18 && _word_count != 24) return; + recovery_mode = RECOVERY_NONE; + word_pincode = 0; + word_index = 0; word_count = _word_count; enforce_wordlist = _enforce_wordlist; dry_run = _dry_run; @@ -504,10 +509,9 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, config_setU2FCounter(u2f_counter); } + // Prefer matrix recovery if the host supports it. if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) { - awaiting_word = 2; - word_index = 0; - word_pincode = 0; + recovery_mode = RECOVERY_MATRIX; next_matrix(); } else { for (uint32_t i = 0; i < word_count; i++) { @@ -517,8 +521,7 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, word_order[i] = 0; } random_permute(word_order, 24); - awaiting_word = 1; - word_index = 0; + recovery_mode = RECOVERY_SCRAMBLED; next_word(); } } @@ -527,29 +530,18 @@ static void recovery_scrambledword(const char *word) { int index = -1; if (enforce_wordlist) { // check if word is valid index = mnemonic_find_word(word); - } - if (word_pos == 0) { // fake word - if (strcmp(word, fake_word) != 0) { + if (index < 0) { // not found if (!dry_run) { session_clear(true); } - fsm_sendFailure(FailureType_Failure_ProcessError, - _("Wrong word retyped")); - layoutHome(); + fsm_sendFailure(FailureType_Failure_DataError, + _("Word not found in a wordlist")); + recovery_abort(); return; } - } else { // real word - if (enforce_wordlist) { - if (index < 0) { // not found - if (!dry_run) { - session_clear(true); - } - fsm_sendFailure(FailureType_Failure_DataError, - _("Word not found in a wordlist")); - layoutHome(); - return; - } - } + } + + if (word_pos != 0) { // ignore fake words strlcpy(words[word_pos - 1], word, sizeof(words[word_pos - 1])); } @@ -565,11 +557,11 @@ static void recovery_scrambledword(const char *word) { * for scrambled recovery. */ void recovery_word(const char *word) { - switch (awaiting_word) { - case 2: + switch (recovery_mode) { + case RECOVERY_MATRIX: recovery_digit(word[0]); break; - case 1: + case RECOVERY_SCRAMBLED: recovery_scrambledword(word); break; default: @@ -582,9 +574,11 @@ void recovery_word(const char *word) { /* Abort recovery. */ void recovery_abort(void) { - if (awaiting_word) { + memzero(words, sizeof(words)); + word_pincode = 0; + if (recovery_mode != RECOVERY_NONE) { layoutHome(); - awaiting_word = 0; + recovery_mode = RECOVERY_NONE; } } diff --git a/python/.changelog.d/noissue.removed b/python/.changelog.d/noissue.removed new file mode 100644 index 000000000..5acaf6aa7 --- /dev/null +++ b/python/.changelog.d/noissue.removed @@ -0,0 +1 @@ +Remove DATA parameter from trezorctl cosi commit. diff --git a/python/src/trezorlib/cli/cosi.py b/python/src/trezorlib/cli/cosi.py index 4607e7982..d84189f99 100644 --- a/python/src/trezorlib/cli/cosi.py +++ b/python/src/trezorlib/cli/cosi.py @@ -14,7 +14,8 @@ # You should have received a copy of the License along with this library. # If not, see . -from typing import TYPE_CHECKING +import warnings +from typing import TYPE_CHECKING, Optional import click @@ -35,14 +36,17 @@ def cli() -> None: @cli.command() @click.option("-n", "--address", required=True, help=PATH_HELP) -@click.argument("data") +@click.argument("data_deprecated", required=False) @with_client def commit( - client: "TrezorClient", address: str, data: str + client: "TrezorClient", address: str, data_deprecated: Optional[str] ) -> "messages.CosiCommitment": """Ask device to commit to CoSi signing.""" + if data_deprecated is not None: + warnings.warn("'data' argument is deprecated") + address_n = tools.parse_path(address) - return cosi.commit(client, address_n, bytes.fromhex(data)) + return cosi.commit(client, address_n) @cli.command() diff --git a/python/src/trezorlib/cosi.py b/python/src/trezorlib/cosi.py index fbcf603eb..77786a90f 100644 --- a/python/src/trezorlib/cosi.py +++ b/python/src/trezorlib/cosi.py @@ -14,8 +14,9 @@ # You should have received a copy of the License along with this library. # If not, see . +import warnings from functools import reduce -from typing import TYPE_CHECKING, Iterable, List, Tuple +from typing import TYPE_CHECKING, Iterable, List, Optional, Tuple from . import _ed25519, messages from .tools import expect @@ -141,8 +142,17 @@ def sign_with_privkey( @expect(messages.CosiCommitment) -def commit(client: "TrezorClient", n: "Address", data: bytes) -> "MessageType": - return client.call(messages.CosiCommit(address_n=n, data=data)) +def commit( + client: "TrezorClient", n: "Address", data: Optional[bytes] = None +) -> "MessageType": + if data is not None: + warnings.warn( + "'data' argument is deprecated", + DeprecationWarning, + stacklevel=2, + ) + + return client.call(messages.CosiCommit(address_n=n)) @expect(messages.CosiSignature) diff --git a/tests/device_tests/misc/test_cosi.py b/tests/device_tests/misc/test_cosi.py index 048552e2b..0f7a0cce9 100644 --- a/tests/device_tests/misc/test_cosi.py +++ b/tests/device_tests/misc/test_cosi.py @@ -24,75 +24,87 @@ from trezorlib.tools import parse_path pytestmark = pytest.mark.skip_t2 +DIGEST = sha256(b"this is not a pipe").digest() -def test_cosi_commit(client: Client): - digest = sha256(b"this is a message").digest() - c0 = cosi.commit(client, parse_path("m/10018h/0h"), digest) - c1 = cosi.commit(client, parse_path("m/10018h/1h"), digest) - c2 = cosi.commit(client, parse_path("m/10018h/2h"), digest) +def test_cosi_pubkey(client: Client): + c0 = cosi.commit(client, parse_path("m/10018h/0h")) + c1 = cosi.commit(client, parse_path("m/10018h/1h")) + c2 = cosi.commit(client, parse_path("m/10018h/2h")) assert c0.pubkey != c1.pubkey assert c0.pubkey != c2.pubkey assert c1.pubkey != c2.pubkey - assert c0.commitment != c1.commitment - assert c0.commitment != c2.commitment - assert c1.commitment != c2.commitment - - digestb = sha256(b"this is a different message").digest() - c0b = cosi.commit(client, parse_path("m/10018h/0h"), digestb) - c1b = cosi.commit(client, parse_path("m/10018h/1h"), digestb) - c2b = cosi.commit(client, parse_path("m/10018h/2h"), digestb) +def test_cosi_nonce(client: Client): + # The nonce/commitment must change after each signing. + c0 = cosi.commit(client, parse_path("m/10018h/0h")) + cosi.sign(client, parse_path("m/10018h/0h"), DIGEST, c0.commitment, c0.pubkey) + c1 = cosi.commit(client, parse_path("m/10018h/0h")) + assert c0.commitment != c1.commitment - assert c0.pubkey == c0b.pubkey - assert c1.pubkey == c1b.pubkey - assert c2.pubkey == c2b.pubkey - assert c0.commitment != c0b.commitment - assert c1.commitment != c1b.commitment - assert c2.commitment != c2b.commitment +def test_cosi_sign1(client: Client): + # Single party signature. + commit = cosi.commit(client, parse_path("m/10018h/0h")) + sig = cosi.sign( + client, parse_path("m/10018h/0h"), DIGEST, commit.commitment, commit.pubkey + ) + signature = cosi.combine_sig(commit.commitment, [sig.signature]) + cosi.verify_combined(signature, DIGEST, commit.pubkey) -def test_cosi_sign(client: Client): - digest = sha256(b"this is a message").digest() +def test_cosi_sign2(client: Client): + # Two party signature. + remote_commit = cosi.commit(client, parse_path("m/10018h/1h")) - c0 = cosi.commit(client, parse_path("m/10018h/0h"), digest) - c1 = cosi.commit(client, parse_path("m/10018h/1h"), digest) - c2 = cosi.commit(client, parse_path("m/10018h/2h"), digest) + local_privkey = sha256(b"private key").digest()[:32] + local_pubkey = cosi.pubkey_from_privkey(local_privkey) + local_nonce, local_commitment = cosi.get_nonce(local_privkey, DIGEST, 42) - global_pk = cosi.combine_keys([c0.pubkey, c1.pubkey, c2.pubkey]) - global_R = cosi.combine_keys([c0.commitment, c1.commitment, c2.commitment]) + global_pk = cosi.combine_keys([remote_commit.pubkey, local_pubkey]) + global_R = cosi.combine_keys([remote_commit.commitment, local_commitment]) - # fmt: off - sig0 = cosi.sign(client, parse_path("m/10018h/0h"), digest, global_R, global_pk) - sig1 = cosi.sign(client, parse_path("m/10018h/1h"), digest, global_R, global_pk) - sig2 = cosi.sign(client, parse_path("m/10018h/2h"), digest, global_R, global_pk) - # fmt: on + remote_sig = cosi.sign( + client, parse_path("m/10018h/1h"), DIGEST, global_R, global_pk + ) + local_sig = cosi.sign_with_privkey( + DIGEST, local_privkey, global_pk, local_nonce, global_R + ) + signature = cosi.combine_sig(global_R, [remote_sig.signature, local_sig]) - sig = cosi.combine_sig(global_R, [sig0.signature, sig1.signature, sig2.signature]) + cosi.verify_combined(signature, DIGEST, global_pk) - cosi.verify_combined(sig, digest, global_pk) +def test_cosi_sign3(client: Client): + # Three party signature. + remote_commit = cosi.commit(client, parse_path("m/10018h/2h")) -def test_cosi_compat(client: Client): - digest = sha256(b"this is not a pipe").digest() - remote_commit = cosi.commit(client, parse_path("m/10018h/0h"), digest) + local_privkey1 = sha256(b"private key").digest()[:32] + local_pubkey1 = cosi.pubkey_from_privkey(local_privkey1) + local_nonce1, local_commitment1 = cosi.get_nonce(local_privkey1, DIGEST, 42) - local_privkey = sha256(b"private key").digest()[:32] - local_pubkey = cosi.pubkey_from_privkey(local_privkey) - local_nonce, local_commitment = cosi.get_nonce(local_privkey, digest, 42) + local_privkey2 = sha256(b"private key").digest()[:32] + local_pubkey2 = cosi.pubkey_from_privkey(local_privkey2) + local_nonce2, local_commitment2 = cosi.get_nonce(local_privkey2, DIGEST, 42) - global_pk = cosi.combine_keys([remote_commit.pubkey, local_pubkey]) - global_R = cosi.combine_keys([remote_commit.commitment, local_commitment]) + global_pk = cosi.combine_keys([remote_commit.pubkey, local_pubkey1, local_pubkey2]) + global_R = cosi.combine_keys( + [remote_commit.commitment, local_commitment1, local_commitment2] + ) remote_sig = cosi.sign( - client, parse_path("m/10018h/0h"), digest, global_R, global_pk + client, parse_path("m/10018h/2h"), DIGEST, global_R, global_pk ) - local_sig = cosi.sign_with_privkey( - digest, local_privkey, global_pk, local_nonce, global_R + local_sig1 = cosi.sign_with_privkey( + DIGEST, local_privkey1, global_pk, local_nonce1, global_R + ) + local_sig2 = cosi.sign_with_privkey( + DIGEST, local_privkey2, global_pk, local_nonce2, global_R + ) + signature = cosi.combine_sig( + global_R, [remote_sig.signature, local_sig1, local_sig2] ) - sig = cosi.combine_sig(global_R, [remote_sig.signature, local_sig]) - cosi.verify_combined(sig, digest, global_pk) + cosi.verify_combined(signature, DIGEST, global_pk) diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json index cd7016936..986b666f7 100644 --- a/tests/ui_tests/fixtures.json +++ b/tests/ui_tests/fixtures.json @@ -393,9 +393,11 @@ "T1_ethereum-test_signtx.py::test_signtx_eip1559[unknown_erc20]": "548c1f22918351e9cbcc1e16d8ba67bc2e7460b9a92cfc6c8bfa0a2b063e68da", "T1_ethereum-test_signtx.py::test_signtx_eip1559_access_list": "f6c5f398d4e80fc8f93cf70e9b10de24b9a968db04dc6ea21b28d1a273f04ca1", "T1_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "f6c5f398d4e80fc8f93cf70e9b10de24b9a968db04dc6ea21b28d1a273f04ca1", -"T1_misc-test_cosi.py::test_cosi_commit": "c943c92750d6072a3b272c1a9dca815ee7504293e4c1d85a76d5af9c2e415297", -"T1_misc-test_cosi.py::test_cosi_compat": "dfdc383ac1dd9f1bb63b52c8623d3788491e7a954f6f0374fe0963e823a5e0c5", -"T1_misc-test_cosi.py::test_cosi_sign": "54f589eaca23d0e1a055280920b9a40c7ba7a5b34779270090a8361113af4574", +"T1_misc-test_cosi.py::test_cosi_nonce": "6990c238036b79368fea1dc1e3e8871d7788322bbee7425d14c53623bc8182e8", +"T1_misc-test_cosi.py::test_cosi_pubkey": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", +"T1_misc-test_cosi.py::test_cosi_sign1": "6990c238036b79368fea1dc1e3e8871d7788322bbee7425d14c53623bc8182e8", +"T1_misc-test_cosi.py::test_cosi_sign2": "0852e7433ec54a0ace301b683417107a9805095acd954010b665266503a79f36", +"T1_misc-test_cosi.py::test_cosi_sign3": "d04fca2d97f7117ffc79ae52d192086aba2f9c64e89db27e20a930e9048f1d81", "T1_misc-test_msg_cipherkeyvalue.py::test_decrypt": "a849d9e11e222d1348ce3135680a2a61ed265692adeba4bd48af2fdc65207e61", "T1_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "T1_misc-test_msg_cipherkeyvalue.py::test_encrypt": "e36d5b5db4b3733c9f484b149c0f966b3dd66e8b54e1b5bccf9da5cca7abed91",