diff --git a/src/FilesCache.cpp b/src/FilesCache.cpp index 7fa2f5fd..151393ea 100644 --- a/src/FilesCache.cpp +++ b/src/FilesCache.cpp @@ -156,8 +156,12 @@ bool FilesCache::setCardCPZ(QByteArray cardCPZ) m_filePath = dataDir.absoluteFilePath(fileName); qint64 m_key = 0; + // The shift must stay 32-bit and wrap at 32 ((i*8) & 31) to derive the + // same key historical x86 builds produced: shifting a 32-bit value by + // >= 32 is undefined behaviour that x86 silently wrapped, while on + // arm64 the compiler turns it into a trap (crash on Apple Silicon). for (int i = 0;i < std::min(8, static_cast(cardCPZ.size()));i++) - m_key += (static_cast(cardCPZ[i]) & 0xFF) << (i * 8); + m_key += (static_cast(cardCPZ[i]) & 0xFF) << ((i * 8) & 31); m_simpleCrypt.setKey(m_key); m_simpleCrypt.setIntegrityProtectionMode(SimpleCrypt::ProtectionHash); diff --git a/src/MPDevice.cpp b/src/MPDevice.cpp index 3e5e1c55..c1c88ddf 100755 --- a/src/MPDevice.cpp +++ b/src/MPDevice.cpp @@ -5414,9 +5414,13 @@ quint64 MPDevice::getUInt64EncryptionKey() quint64 MPDevice::getUInt64EncryptionKeyOld() { qint64 key = 0; + // This legacy key derivation must reproduce what historical x86 builds + // computed: the 32-bit shift by >= 32 was undefined behaviour that x86 + // silently wrapped ((i*8) & 31), while on arm64 the compiler turns the + // unmasked form into a trap (crash on Apple Silicon). for (int i = 0; i < std::min(8, static_cast(m_cardCPZ.size())) ; i++) { - key += (static_cast(m_cardCPZ[i]) & 0xFF) << (i*8); + key += (static_cast(m_cardCPZ[i]) & 0xFF) << ((i*8) & 31); } return key; diff --git a/src/MPDevice_mac.cpp b/src/MPDevice_mac.cpp index c075da95..a9e0792a 100644 --- a/src/MPDevice_mac.cpp +++ b/src/MPDevice_mac.cpp @@ -29,12 +29,22 @@ void _read_report_callback(void *context, uint8_t *report, CFIndex report_length) { - Q_UNUSED(result); Q_UNUSED(sender); Q_UNUSED(report_type); Q_UNUSED(report_id); MPDevice_mac *dev = reinterpret_cast(context); + + // IOKit invokes this callback with an error result (and meaningless + // buffer/length) when the device drops mid-read, e.g. while the BLE + // device re-enumerates its interfaces. Never feed that to the parser. + if (result != kIOReturnSuccess || !report || report_length <= 0) + { + qWarning() << "Ignoring errored HID input report, result:" << result + << "length:" << static_cast(report_length); + return; + } + QByteArray data((const char *)report, report_length); if (dev->isBT()) {