Fixes auth (using m5utility 0.0.8)

This commit is contained in:
GOB
2025-11-04 16:08:01 +09:00
parent a4d68191c9
commit cc2ed00c49
4 changed files with 83 additions and 190 deletions
-2
View File
@@ -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()
+73 -15
View File
@@ -12,6 +12,20 @@
#include <M5Utility.hpp>
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<uint8_t>((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<uint8_t>(Ar >> (i << 3));
const uint8_t ks = step8(0x00);
buf[pos] = ks ^ nt_byte;
const uint8_t z = filter();
par |= static_cast<uint8_t>((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<uint8_t>((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<uint8_t>(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<uint8_t>((z ^ oddparity8(nt_byte)) & 0x01) << (7 - pos);
par |= static_cast<uint8_t>((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<uint8_t>((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<uint8_t>((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
+9 -172
View File
@@ -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]{};
+1 -1
View File
@@ -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{};
};