From cc2ed00c490ff6ffcae02773caca5e9ee715596b Mon Sep 17 00:00:00 2001 From: GOB Date: Tue, 4 Nov 2025 16:08:01 +0900 Subject: [PATCH] Fixes auth (using m5utility 0.0.8) --- examples/UnitUnified/Dump/main/Dump.cpp | 2 - src/nfc/a/mifare_crypto1.hpp | 88 ++++++++++-- src/unit/unit_ST25R3916.cpp | 181 ++---------------------- src/unit/unit_ST25R3916.hpp | 2 +- 4 files changed, 83 insertions(+), 190 deletions(-) diff --git a/examples/UnitUnified/Dump/main/Dump.cpp b/examples/UnitUnified/Dump/main/Dump.cpp index 26e9efb..efa88a6 100644 --- a/examples/UnitUnified/Dump/main/Dump.cpp +++ b/examples/UnitUnified/Dump/main/Dump.cpp @@ -67,8 +67,6 @@ void setup() lcd.setCursor(0, 0); lcd.printf("Please put the device and click G0"); M5.Log.printf("Please put the device and click G0\n"); - - heap_caps_check_integrity_all(true); } void loop() diff --git a/src/nfc/a/mifare_crypto1.hpp b/src/nfc/a/mifare_crypto1.hpp index 62533be..41ba7fd 100644 --- a/src/nfc/a/mifare_crypto1.hpp +++ b/src/nfc/a/mifare_crypto1.hpp @@ -12,6 +12,20 @@ #include +namespace m5 { +namespace nfc { +namespace a { +namespace mifare { + +inline uint32_t prng_successor(uint32_t x, uint32_t n) +{ + x = m5::stl::byteswap(x); + while (n--) { + x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; + } + return m5::stl::byteswap(x); +} + using MLFSR48 = m5::utility::FibonacciLFSR_Left<48, 5, 6, 7, 9, 13, 19, 21, 23, 24, 29, 31, 33, 34, 36, 38, 39, 43, 48>; class MifareCrypto1 : public MLFSR48 { public: @@ -24,6 +38,7 @@ public: init(key48); } + #if 0 uint64_t valueLSBFirst() const noexcept { uint64_t v = 0; @@ -34,6 +49,7 @@ public: } return v; } + #endif void init(const uint64_t key48) noexcept { @@ -93,6 +109,29 @@ public: uint8_t encrypt(uint8_t buf[8], const uint32_t Nr, const uint32_t Ar) noexcept { uint8_t par{}; + for (uint_fast8_t i = 0; i < 4; ++i) { + uint8_t v = ((Nr >> ((i ^ 0x03) << 3)) & 0xFF); + buf[i] = step8(v) ^ v; + const uint8_t z = filter(); + par |= static_cast((z ^ oddparity8(v)) & 0x01) << i; + } + + for (uint_fast8_t pos = 4; pos < 8; ++pos) { + const uint8_t i = pos - 4; + const uint8_t nt_byte = static_cast(Ar >> (i << 3)); + const uint8_t ks = step8(0x00); + buf[pos] = ks ^ nt_byte; + const uint8_t z = filter(); + par |= static_cast((z ^ oddparity8(nt_byte)) & 0x01) << pos; + } + return par; + } + + uint8_t encrypt(uint8_t buf[8], const uint32_t Nr, const uint32_t Ar, const uint32_t Nt) noexcept + { + uint8_t par{}; + +#if 1 for (uint_fast8_t i = 0; i < 4; ++i) { uint8_t v = ((Nr >> ((i ^ 0x03) << 3)) & 0xFF); buf[i] = step8(v) ^ v; @@ -100,11 +139,14 @@ public: const uint8_t z = filter(); par |= static_cast((z ^ oddparity8(v)) & 0x01) << i; } + for (uint_fast8_t pos = 4; pos < 8; ++pos) { const uint8_t i = pos - 4; const uint8_t nt_byte = static_cast(Ar >> (i << 3)); - const uint8_t ks = step8(0x00); - buf[pos] = ks ^ nt_byte; + M5_LIB_LOGE("pos[%u]:%02X", pos, nt_byte); + + const uint8_t ks = step8(0x00); + buf[pos] = ks ^ nt_byte; const uint8_t z = filter(); // uint8_t aaa = (z ^ oddparity8(nt_byte)) & 0x01; @@ -112,10 +154,32 @@ public: // par |= static_cast((z ^ oddparity8(nt_byte)) & 0x01) << (7 - pos); par |= static_cast((z ^ oddparity8(nt_byte)) & 0x01) << pos; } +#else + uint32_t nt = prng_successor(Nt, 32); + for (uint_fast8_t i = 0; i < 4; ++i) { + uint8_t v = ((Nr >> ((i ^ 0x03) << 3)) & 0xFF); + buf[i] = step8(v) ^ v; + + const uint8_t z = filter(); + par |= static_cast((z ^ oddparity8(v)) & 0x01) << i; + } + + nt = prng_successor(Nt, 32); + + for (uint_fast8_t pos = 4; pos < 8; ++pos) { + nt = prng_successor(nt, 8); + buf[pos] = step8(0x00) ^ (nt & 0xff); + const uint8_t z = filter(); + // uint8_t aaa = (z ^ oddparity8(nt_byte)) & 0x01; + // M5_LIB_LOGE("pos[%u]: f:%d P:%u", pos, z, aaa); + // par |= static_cast((z ^ oddparity8(nt_byte)) & 0x01) << (7 - pos); + par |= ((z ^ oddparity8(nt & 0xff)) & 0x01) << pos; + } +#endif return par; } - uint32_t encrypt(uint8_t* out, const uint8_t* in, const uint8_t in_len) + uint32_t encrypt(uint8_t* out, const uint8_t* in, const uint8_t in_len /* max 32 */) { uint32_t parity{}; for (uint_fast8_t i = 0; i < in_len; ++i) { @@ -140,31 +204,25 @@ public: inline static bool fa(bool a, bool b, bool c, bool d) noexcept { return ((a || b) ^ (a && d)) ^ (c && ((a ^ b) || d)); - // const uint8_t x = (a << 3) | (b << 2) | (c << 1) | (d << 0); - // return (0xf22cu >> x) & 1u; - // return ((0xD9380u >> x) & 16u); - // return ((0xB48Eu >> x) & 1u) != 0; - // return (0x9E98u >> x) & 1u; } inline static bool fb(bool a, bool b, bool c, bool d) noexcept { return ((a && b) || c) ^ ((a ^ b) && (c || d)); - // const uint8_t x = (a << 3) | (b << 2) | (c << 1) | (d << 0); - // return ((0xD938u >> x) & 1u) != 0; - // return ((0xf22c0 >> x) & 16u); - // return (0x9E98u >> x) & 1u; - // return (0xB48Eu >> x) & 1u; } inline static bool fc(bool a, bool b, bool c, bool d, bool e) noexcept { return (a || ((b || e) && (d ^ e))) ^ ((a ^ (b && d)) && ((c ^ d) || (b && e))); - // const uint8_t x = (a << 4) | (b << 3) | (c << 2) | (d << 1) | (e << 0); - // return ((0xEC57E80Au >> x) & 1u) != 0; } uint64_t _uid{}; uint32_t _count{}; // for debug }; + +} // namespace mifare +} // namespace a +} // namespace nfc +} // namespace m5 + #endif diff --git a/src/unit/unit_ST25R3916.cpp b/src/unit/unit_ST25R3916.cpp index 7fadd26..7085002 100644 --- a/src/unit/unit_ST25R3916.cpp +++ b/src/unit/unit_ST25R3916.cpp @@ -152,40 +152,15 @@ inline bool is_irq32_collision(const uint32_t irq32) return irq32 & I_col32; } -uint32_t suc_k(const uint32_t Nt, const uint32_t k) -{ - m5::utility::FibonacciLFSR_Right<16, 16, 14, 13, 11> tmp(Nt); - for (uint32_t i = 0; i < k; ++i) { - tmp.next32(); - } - return tmp.next32(); -} - void suc_23(const uint32_t Nt, uint32_t& suc2, uint32_t& suc3) { - m5::utility::FibonacciLFSR_Right<16, 16, 14, 13, 11> tmp(Nt); + m5::utility::FibonacciLFSR_Right<32, 16, 14, 13, 11> tmp(Nt); tmp.next32(); tmp.next32(); suc2 = tmp.next32(); suc3 = tmp.next32(); } -uint32_t swap_endian_32(const uint32_t value) -{ - return ((value >> 24) & 0x000000FF) | ((value >> 8) & 0x0000FF00) | ((value << 8) & 0x00FF0000) | - ((value << 24) & 0xFF000000); -} - -uint16_t swap_endian_16(const uint16_t value) -{ - return (value >> 8) | (value << 8); -} - -uint8_t swap_bit_order(const uint8_t byte) -{ - return (byte * 0x0202020202ULL & 0x010884422010ULL) % 0x3ff; -} - uint64_t key_to64(const uint8_t k[6]) { uint64_t v{}; @@ -680,42 +655,17 @@ bool UnitST25R3916::read_block_encrypted(uint8_t* rx, uint16_t& rx_len, const ui { uint8_t cmd[4] = {m5::stl::to_underlying(Command::READ), addr}; m5::utility::CRC16 crc16(0xC6C6, 0x1021, true, true, 0); + // m5::utility::CRC16 crc16(0x6363, 0x1021, false, false, 0); auto crc = crc16.range(cmd, 2); cmd[2] = crc & 0xFF; cmd[3] = crc >> 8; -#if 0 - auto oddparity8 = [](const uint8_t x) -> uint8_t { return !__builtin_parity(x); }; - uint8_t enc_tx[4]{}; - uint8_t parity{}; - for (uint8_t i = 0; i < 4; ++i) { - uint8_t ks = _crypto1.step8(0); - enc_tx[i] = cmd[i] ^ ks; - parity |= ((_crypto1.filter() ^ oddparity8(cmd[i])) & 1) << i; - } -#else uint8_t enc_tx[4]{}; uint32_t parity = _crypto1.encrypt(enc_tx, cmd, sizeof(cmd)); -#endif uint8_t bitstream[5]{}; -#if 0 - uint32_t bitpos = 0; - auto put_bit = [&](uint8_t b) { - uint32_t byte = bitpos >> 3; - uint8_t off = bitpos & 7; - if (b) bitstream[byte] |= (1u << off); - bitpos++; - }; - - for (int i = 0; i < 4; ++i) { - uint8_t v = enc_tx[i]; - for (int k = 0; k < 8; ++k) put_bit((v >> k) & 1u); // LSB→MSB - put_bit((parity >> i) & 1u); - } -#else append_parity(bitstream, sizeof(bitstream), enc_tx, sizeof(enc_tx), parity); -#endif + // Send // M5_LIB_LOGE("Send: parity:%04X cnt:%u", parity, _crypto1._count); // m5::utility::log::dump(cmd, 4, false); @@ -1032,7 +982,6 @@ bool UnitST25R3916::write_register32(const uint16_t reg, const uint32_t v) uint32_t UnitST25R3916::wait_for_interrupt(const uint32_t irq, const uint32_t timeout_ms, bool include_error) { -#if 1 auto timeout_at = m5::utility::millis() + timeout_ms; const uint32_t error_bits = include_error ? 0x0000FF00 : 0; do { @@ -1043,41 +992,14 @@ uint32_t UnitST25R3916::wait_for_interrupt(const uint32_t irq, const uint32_t ti _irq_flags |= v; } } -#if 0 - if (_irq_flags & (irq | error_bits)) { - uint32_t ret = _irq_flags & (irq | error_bits); - _irq_flags = 0; - return ret; - } -#else if (_irq_flags & irq) { uint32_t ret = _irq_flags & irq; _irq_flags = 0; return ret; } -#endif std::this_thread::yield(); } while (m5::utility::millis() <= timeout_at); return I_nre32; // Timeout -#else - auto timeout_at = m5::utility::millis() + timeout_ms; - const uint32_t error_bits = include_error ? 0x0000FF00 : 0; - do { - if (_interrupt_occurred) { - uint32_t v{}; - if (readInterrupts(v)) { - _irq_flags |= v; - } - _interrupt_occurred = false; - } - if (_irq_flags & (irq | error_bits)) { - auto ret = _irq_flags & (irq | error_bits); - _irq_flags = 0; - return ret; - } - } while (m5::utility::millis() <= timeout_at); - return I_nre32; // Timeout -#endif } bool UnitST25R3916::wait_for_FIFO(const uint32_t timeout_ms, const uint16_t required_size) @@ -1264,12 +1186,8 @@ bool UnitST25R3916::mifare_authenticate(const Command cmd, const UID& uid, const return false; } - ///////////////////// - // 4K のデータで prox crypto1 で出力してみる - // 3-pass mutual authentication - // Encrypted? const uint64_t key48 = key_to64(mkey.data()); // Send AUTH command (Plane) and receive token RB (Nt) @@ -1283,8 +1201,8 @@ bool UnitST25R3916::mifare_authenticate(const Command cmd, const UID& uid, const } m5::utility::delayMicroseconds(100); // Wait for AUTH <-> Sebd AB (At least 86.4 us) - // M5_LIB_LOGE("RECV RB:"); - // m5::utility::log::dump(RB, rlen, false); + //M5_LIB_LOGE("RECV RB:"); + //m5::utility::log::dump(RB, rlen, false); // Send encrypt token AB (Nr, Ar) uint8_t tail4[4]{}; @@ -1295,35 +1213,22 @@ bool UnitST25R3916::mifare_authenticate(const Command cmd, const UID& uid, const // const uint32_t Ar = suc_k(swap_endian_32(Nt), 2); // suc2 // const uint32_t suc3 = suc_k(swap_endian_32(Nt), 3); // suc3 uint32_t Ar{}, suc3{}; - suc_23(swap_endian_32(Nt), Ar, suc3); + // suc_23(swap_endian_32(Nt), Ar, suc3); + suc_23(m5::stl::byteswap(Nt), Ar, suc3); uint8_t AB[8 + 1 /*parity*/]{}; M5_LIB_LOGD("Auth:%u mkey:%llX uid:%X Nt:%X Nr:%X Ar:%X", block, key48, u32, Nt, Nr, Ar); _crypto1.init(key48); _crypto1.inject(u32, Nt); + // uint8_t parity = _crypto1.encrypt(AB, Nr, Ar, Nt); uint8_t parity = _crypto1.encrypt(AB, Nr, Ar); AB[8] = parity; // M5_LIB_LOGE("SEND AB:"); uint8_t bitstream[9 /* AB 8bytes + encrypt parity 1(8bits)] */]{0}; -#if 0 - uint32_t bitpos = 0; - auto put_bit = [&](uint8_t b) { - uint32_t byte = bitpos >> 3; - uint8_t off = bitpos & 7; - if (b) bitstream[byte] |= (1u << off); - bitpos++; - }; - for (int i = 0; i < 8; ++i) { - uint8_t v = AB[i]; - for (int k = 0; k < 8; ++k) put_bit((v >> k) & 1u); // LSB→MSB - put_bit((parity >> i) & 1u); - } -#else append_parity(bitstream, sizeof(bitstream), AB, 8, parity); -#endif // m5::utility::log::dump(AB, sizeof(AB), false); // m5::utility::log::dump(bitstream, sizeof(bitstream), false); @@ -1433,79 +1338,11 @@ bool UnitST25R3916::mifare_authenticate(const Command cmd, const UID& uid, const default: break; } - // if (++func > 2) func = 0; + // if (++func > 2) func = 0; -#if 0 - // auto irq = wait_for_interrupt(I_rxs32 | I_rxe32 | I_nre32, TIMEOUT_AUTH2); - -#if 0 - auto irq = wait_for_interrupt(I_txe32, TIMEOUT_AUTH2); - M5_LIB_LOGE(">>>> IRQ:%08X", irq); - if (!is_irq32_txe(irq)) { - M5_LIB_LOGE("Failed to send %08X", irq); - return false; - } - irq = wait_for_interrupt(I_rxs32 | I_rxe32, TIMEOUT_AUTH2); - uint32_t v{}; - readInterrupts(v); - M5_LIB_LOGE(">>>> IRQ:%08X/%08X", irq, v); - -#else - // uint32_t mask{}; - // readMaskInterrupts(mask); - // M5_LIB_LOGE(">>>> mask:%08X", mask); - - uint32_t irq{}; - for (;;) { - if (_interrupt_occurred) { - _interrupt_occurred = false; - uint32_t v{}; - readInterrupts(v); - irq |= v; - if (irq) { - break; - } - } - } -// M5_LIB_LOGE("==>> IRQ:%08X", irq); -#endif - - if (!is_irq32_rxe(irq) && is_irq32_rxs(irq)) { // The I_rxe bit may not be set - auto timeout_at = m5::utility::millis() + TIMEOUT_AUTH2 * 10; - uint16_t bytes{}; - uint8_t bits{}; - // M5_LIB_LOGE(">=== %lu, %lu", m5::utility::millis(), timeout_at); - irq = 0; - do { - if (_interrupt_occurred) { - _interrupt_occurred = false; - uint32_t v{}; - readInterrupts(v); - irq |= v; - // M5_LIB_LOGE(" --> IRQ:%08X", v); - irq = 0; - } - if (v & I_rxe32) { - break; - } - readFIFOSize(bytes, bits); - //M5_LIB_LOGE(" >%u", bytes); - if (bytes >= 4) { - break; - } - std::this_thread::yield(); - } while (m5::utility::millis() <= timeout_at); - } -// M5_LIB_LOGE("<=== %lu", m5::utility::millis()); - -///////////////// -#else if (!wait_for_FIFO(TIMEOUT_AUTH2, 4)) { M5_LIB_LOGE("Timeout"); } -#endif - - // writeSettingsISO14443A(0); // Receive token BA (At) uint8_t BA[4 + 2]{}; diff --git a/src/unit/unit_ST25R3916.hpp b/src/unit/unit_ST25R3916.hpp index 6d8e2be..1063468 100644 --- a/src/unit/unit_ST25R3916.hpp +++ b/src/unit/unit_ST25R3916.hpp @@ -1739,7 +1739,7 @@ protected: private: config_t _cfg{}; uint32_t _irq_flags{}; - MifareCrypto1 _crypto1{}; + m5::nfc::a::mifare::MifareCrypto1 _crypto1{}; bool _encrypted{}; volatile bool _interrupt_occurred{}; };