From d36396f35bbb45403deabb32395c75061322eeae Mon Sep 17 00:00:00 2001 From: Zinong Li <131403964+zinongli@users.noreply.github.com> Date: Sun, 30 Jun 2024 14:11:49 -0400 Subject: [PATCH] LFRFID Securakey: Add Support for RKKTH Plain Text Format (#3728) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Create protocol_securakey.c * decode and render done * Support for Radio Key Securakey Support both 26- and 32-bit format Solves issue #2619 * debugs and improvements * Formatting in response to requested changes * fixed wiegand parity bit calculation * format * debug unnecessary assert * LfRfid: swap vendor and protocol names in securakey * fixed manually generated keys issues * fix bit length render error caused by bit length fix * 1.0 * edit the citation in comments * backward compatibility * debug * debug preamble false positives * temporary fix: writing RKKTH causes second to last byte not encoded. unknown reason * slightly more elegant solution to the weird bug * plausible solution, much more elegant * finally fixed it. stupid mistake * clean up and format. ready for new PR Co-authored-by: あく --- lib/lfrfid/protocols/protocol_securakey.c | 322 +++++++++++++--------- 1 file changed, 196 insertions(+), 126 deletions(-) diff --git a/lib/lfrfid/protocols/protocol_securakey.c b/lib/lfrfid/protocols/protocol_securakey.c index 55048a592..81536b771 100644 --- a/lib/lfrfid/protocols/protocol_securakey.c +++ b/lib/lfrfid/protocols/protocol_securakey.c @@ -11,13 +11,15 @@ #include #define TAG "SECURAKEY" -#define SECURAKEY_ENCODED_SIZE_BITS (84) -#define SECURAKEY_PREAMBLE_SIZE_BITS (12) -#define SECURAKEY_ENCODED_FULL_SIZE_BITS \ - (SECURAKEY_ENCODED_SIZE_BITS + SECURAKEY_PREAMBLE_SIZE_BITS) -#define SECURAKEY_ENCODED_FULL_SIZE_BYTE (SECURAKEY_ENCODED_FULL_SIZE_BITS / 8) -#define SECURAKEY_DECODED_DATA_SIZE_BITS \ - (48) // 16-bit for facility code/number, 16-bit for card number, 16-bit for two checksum +#define SECURAKEY_RKKT_ENCODED_FULL_SIZE_BITS (96) +#define SECURAKEY_RKKT_ENCODED_FULL_SIZE_BYTE (12) + +#define SECURAKEY_RKKTH_ENCODED_FULL_SIZE_BITS (64) +#define SECURAKEY_RKKTH_ENCODED_FULL_SIZE_BYTE (8) + +#define SECURAKEY_DECODED_DATA_SIZE_BITS (48) +// RKKT: 16-bit for facility code/number, 16-bit for card number, 16-bit for two checksum +// RKKTH: 16-bit zero padding, 32-bit card number #define SECURAKEY_DECODED_DATA_SIZE_BYTES (SECURAKEY_DECODED_DATA_SIZE_BITS / 8) #define LFRFID_FREQUENCY (125000) #define SECURAKEY_CLOCK_PER_BIT (40) // RF/40 @@ -34,7 +36,8 @@ typedef struct { uint8_t data[SECURAKEY_DECODED_DATA_SIZE_BYTES]; - uint8_t encoded_data[SECURAKEY_ENCODED_FULL_SIZE_BYTE]; + uint8_t RKKT_encoded_data[SECURAKEY_RKKT_ENCODED_FULL_SIZE_BYTE]; + uint8_t RKKTH_encoded_data[SECURAKEY_RKKTH_ENCODED_FULL_SIZE_BYTE]; uint8_t encoded_data_index; bool encoded_polarity; ManchesterState decoder_manchester_state; @@ -55,15 +58,16 @@ uint8_t* protocol_securakey_get_data(ProtocolSecurakey* protocol) { }; static bool protocol_securakey_can_be_decoded(ProtocolSecurakey* protocol) { - // check 11 bits preamble - if(bit_lib_get_bits_16(protocol->encoded_data, 0, SECURAKEY_PREAMBLE_SIZE_BITS) == - 0b011111111100) { - if(bit_lib_get_bits(protocol->encoded_data, 13, 6) == 26 || - bit_lib_get_bits(protocol->encoded_data, 13, 6) == 32) { - return true; - } else { - return false; - } + // check 19 bits preamble + format flag + if(bit_lib_get_bits_32(protocol->RKKT_encoded_data, 0, 19) == 0b0111111111000000000) { + protocol->bit_format = 0; + return true; + } else if(bit_lib_get_bits_32(protocol->RKKT_encoded_data, 0, 19) == 0b0111111111001011010) { + protocol->bit_format = 26; + return true; + } else if(bit_lib_get_bits_32(protocol->RKKT_encoded_data, 0, 19) == 0b0111111111001100000) { + protocol->bit_format = 32; + return true; } else { return false; } @@ -71,7 +75,7 @@ static bool protocol_securakey_can_be_decoded(ProtocolSecurakey* protocol) { static void protocol_securakey_decode(ProtocolSecurakey* protocol) { memset(protocol->data, 0, SECURAKEY_DECODED_DATA_SIZE_BYTES); - // encoded_data looks like this (citation: pm3 repo): + // RKKT_encoded_data looks like this (citation: pm3 repo): // 26-bit format (1-bit even parity bit, 8-bit facility number, 16-bit card number, 1-bit odd parity bit) // preamble ??bitlen reserved EPf fffffffc cccccccc cccccccOP CS? CS2? // 0111111111 0 01011010 0 00000000 0 00000010 0 00110110 0 00111110 0 01100010 0 00001111 0 01100000 0 00000000 0 0000 @@ -80,35 +84,52 @@ static void protocol_securakey_decode(ProtocolSecurakey* protocol) { // preamble ??bitlen reserved EPfffffff fffffffc cccccccc cccccccOP CS? CS2? // 0111111111 0 01100000 0 00000000 0 10000100 0 11001010 0 01011011 0 01010110 0 00010110 0 11100000 0 00000000 0 0000 - // left two 0 paddings in the beginning for easier parsing (00011010 = 011010) - // get facility number (f) - if(bit_lib_get_bits(protocol->encoded_data, 13, 6) == 26) { - FURI_LOG_D(TAG, "26-bit Securakey detected"); - protocol->bit_format = 26; - bit_lib_copy_bits(protocol->data, 8, 1, protocol->encoded_data, 36); - // have to skip one spacer - bit_lib_copy_bits(protocol->data, 9, 7, protocol->encoded_data, 38); - } else if(bit_lib_get_bits(protocol->encoded_data, 13, 6) == 32) { - FURI_LOG_D(TAG, "32-bit Securakey detected"); - protocol->bit_format = 32; - // same two 0 paddings here, otherwise should be bit_lib_copy_bits(protocol->data, 8, 7, protocol->encoded_data, 30); - bit_lib_copy_bits(protocol->data, 2, 7, protocol->encoded_data, 30); - // have to skip one spacer - bit_lib_copy_bits(protocol->data, 9, 7, protocol->encoded_data, 38); + // RKKTH-02 encoded data sometimes look like this + // plaintext format (preamble and 32-bit? card number) + // preamble unknown unknown cccccccc cccccccc cccccccc cccccccc + // 0 1 2 3 4 5 6 + // 0123456789 0 12345678 9 01234567 8 90123456 7 89012345 6 78901234 5 67890123 + // 0111111111 0 00000000 0 00000000 0 00000000 0 00011101 0 00000100 0 01001010 + + if(bit_lib_get_bits(protocol->RKKT_encoded_data, 13, 6) == 0) { + FURI_LOG_D(TAG, "Plaintext RKKTH detected"); + protocol->bit_format = 0; + // get card number (c) + bit_lib_copy_bits(protocol->data, 16, 8, protocol->RKKT_encoded_data, 29); + // skip spacers (0s) + bit_lib_copy_bits(protocol->data, 24, 8, protocol->RKKT_encoded_data, 38); + bit_lib_copy_bits(protocol->data, 32, 8, protocol->RKKT_encoded_data, 47); + bit_lib_copy_bits(protocol->data, 40, 8, protocol->RKKT_encoded_data, 56); + } else { + if(bit_lib_get_bits(protocol->RKKT_encoded_data, 13, 6) == 26) { + FURI_LOG_D(TAG, "26-bit RKKT detected"); + protocol->bit_format = 26; + // left two 0 paddings in the beginning for easier parsing (00011010 = 011010) + // get facility number (f) + bit_lib_copy_bits(protocol->data, 8, 1, protocol->RKKT_encoded_data, 36); + // have to skip one spacer + bit_lib_copy_bits(protocol->data, 9, 7, protocol->RKKT_encoded_data, 38); + } else if(bit_lib_get_bits(protocol->RKKT_encoded_data, 13, 6) == 32) { + FURI_LOG_D(TAG, "32-bit RKKT detected"); + protocol->bit_format = 32; + // same two 0 paddings here, otherwise should be bit_lib_copy_bits(protocol->data, 8, 7, protocol->RKKT_encoded_data, 30); + bit_lib_copy_bits(protocol->data, 2, 7, protocol->RKKT_encoded_data, 30); + // have to skip one spacer + bit_lib_copy_bits(protocol->data, 9, 7, protocol->RKKT_encoded_data, 38); + } + // get card number (c) + bit_lib_copy_bits(protocol->data, 16, 1, protocol->RKKT_encoded_data, 45); + // same skips here + bit_lib_copy_bits(protocol->data, 17, 8, protocol->RKKT_encoded_data, 47); + bit_lib_copy_bits(protocol->data, 25, 7, protocol->RKKT_encoded_data, 56); + + // unsure about CS yet, might as well just save it + // CS1 + bit_lib_copy_bits(protocol->data, 32, 8, protocol->RKKT_encoded_data, 65); + // CS2 + bit_lib_copy_bits(protocol->data, 40, 8, protocol->RKKT_encoded_data, 74); } - // get card number (c) - bit_lib_copy_bits(protocol->data, 16, 1, protocol->encoded_data, 45); - // same skips here - bit_lib_copy_bits(protocol->data, 17, 8, protocol->encoded_data, 47); - bit_lib_copy_bits(protocol->data, 25, 7, protocol->encoded_data, 56); - - // unsure about CS yet, might as well just save it - // CS1 - bit_lib_copy_bits(protocol->data, 32, 8, protocol->encoded_data, 65); - // CS2 - bit_lib_copy_bits(protocol->data, 40, 8, protocol->encoded_data, 74); - // (decoded) data looks like this (pp are zero paddings): // 26-bit format (1-bit EP, 8-bit facility number, 16-bit card number, 1-bit OP) // pppppppp ffffffff cccccccc cccccccc CS1 CS2 @@ -117,10 +138,16 @@ static void protocol_securakey_decode(ProtocolSecurakey* protocol) { // 32-bit format (1-bit EP, 14-bit facility number, 16-bit card number, 1-bit OP) // ppffffff ffffffff cccccccc cccccccc CS1 CS2 // 00000010 01100101 00101101 10101011 00010110 11100000 + + // plaintext format (preamble and 32-bit? card number) + // pppppppp pppppppp cccccccc cccccccc cccccccc cccccccc + // 00000000 00000000 00101011 00011101 00000100 01001010 }; void protocol_securakey_decoder_start(ProtocolSecurakey* protocol) { - memset(protocol->encoded_data, 0, SECURAKEY_ENCODED_FULL_SIZE_BYTE); + // always takes in encoded data as RKKT for simplicity + // this part is feeding decoder which will delineate the format anyway + memset(protocol->RKKT_encoded_data, 0, SECURAKEY_RKKT_ENCODED_FULL_SIZE_BYTE); manchester_advance( protocol->decoder_manchester_state, ManchesterEventReset, @@ -151,7 +178,8 @@ bool protocol_securakey_decoder_feed(ProtocolSecurakey* protocol, bool level, ui bool data_ok = manchester_advance( protocol->decoder_manchester_state, event, &protocol->decoder_manchester_state, &data); if(data_ok) { - bit_lib_push_bit(protocol->encoded_data, SECURAKEY_ENCODED_FULL_SIZE_BYTE, data); + bit_lib_push_bit( + protocol->RKKT_encoded_data, SECURAKEY_RKKT_ENCODED_FULL_SIZE_BYTE, data); if(protocol_securakey_can_be_decoded(protocol)) { protocol_securakey_decode(protocol); result = true; @@ -162,72 +190,89 @@ bool protocol_securakey_decoder_feed(ProtocolSecurakey* protocol, bool level, ui }; void protocol_securakey_render_data(ProtocolSecurakey* protocol, FuriString* result) { - if(bit_lib_get_bits(protocol->data, 0, 8) == 0) { - protocol->bit_format = 26; + if(bit_lib_get_bits_16(protocol->data, 0, 16) == 0) { + protocol->bit_format = 0; + furi_string_printf( + result, + "RKKTH Plaintext format\nCard number: %llu", + bit_lib_get_bits_64(protocol->data, 0, 48)); } else { - protocol->bit_format = 32; + if(bit_lib_get_bits(protocol->data, 0, 8) == 0) { + protocol->bit_format = 26; + } else { + protocol->bit_format = 32; + } + furi_string_printf( + result, + "RKKT %u-bit format\nFacility code: %u\nCard number: %u", + protocol->bit_format, + bit_lib_get_bits_16(protocol->data, 0, 16), + bit_lib_get_bits_16(protocol->data, 16, 16)); } - furi_string_printf( - result, - "%u-bit format\nFacility code: %u\nCard number: %u", - protocol->bit_format, - bit_lib_get_bits_16(protocol->data, 0, 16), - bit_lib_get_bits_16(protocol->data, 16, 16)); }; bool protocol_securakey_encoder_start(ProtocolSecurakey* protocol) { // set all of our encoded_data bits to zeros. - memset(protocol->encoded_data, 0, SECURAKEY_ENCODED_FULL_SIZE_BYTE); - - // write the preamble to the beginning of the encoded_data - bit_lib_set_bits(protocol->encoded_data, 0, 0b01111111, 8); - bit_lib_set_bits(protocol->encoded_data, 8, 0b11001, 5); - - if(bit_lib_get_bits(protocol->data, 0, 8) == 0) { - protocol->bit_format = 26; - // set bit length - bit_lib_set_bits(protocol->encoded_data, 13, protocol->bit_format, 6); - // set even parity & odd parity - if(!bit_lib_test_parity(protocol->data, 8, 12, BitLibParityOdd, 12)) { - bit_lib_set_bit(protocol->encoded_data, 35, 1); - } - if(bit_lib_test_parity(protocol->data, 20, 12, BitLibParityOdd, 12)) { - bit_lib_set_bit(protocol->encoded_data, 63, 1); - } - // write facility number (f) - bit_lib_copy_bits(protocol->encoded_data, 36, 1, protocol->data, 8); - // have to skip one spacer - bit_lib_copy_bits(protocol->encoded_data, 38, 7, protocol->data, 9); - + memset(protocol->RKKTH_encoded_data, 0, SECURAKEY_RKKTH_ENCODED_FULL_SIZE_BYTE); + memset(protocol->RKKT_encoded_data, 0, SECURAKEY_RKKT_ENCODED_FULL_SIZE_BYTE); + if(bit_lib_get_bits_16(protocol->data, 0, 16) == 0) { + // write the preamble to the beginning of the RKKT_encoded_data + bit_lib_set_bits(protocol->RKKTH_encoded_data, 0, 0b01111111, 8); + bit_lib_set_bits(protocol->RKKTH_encoded_data, 8, 0b110, 3); //preamble cont. + // write card number (c) + bit_lib_copy_bits(protocol->RKKTH_encoded_data, 29, 8, protocol->data, 16); + // skip spacers (they are zero already by memset) + bit_lib_copy_bits(protocol->RKKTH_encoded_data, 38, 8, protocol->data, 24); + bit_lib_copy_bits(protocol->RKKTH_encoded_data, 47, 8, protocol->data, 32); + bit_lib_copy_bits(protocol->RKKTH_encoded_data, 56, 8, protocol->data, 40); } else { - protocol->bit_format = 32; - // set bit length - bit_lib_set_bits(protocol->encoded_data, 13, protocol->bit_format, 6); - // set EP & OP - if(!bit_lib_test_parity(protocol->data, 2, 15, BitLibParityOdd, 15)) { - bit_lib_set_bit(protocol->encoded_data, 29, 1); + // write the preamble to the beginning of the RKKT_encoded_data + bit_lib_set_bits(protocol->RKKT_encoded_data, 0, 0b01111111, 8); + bit_lib_set_bits(protocol->RKKT_encoded_data, 8, 0b11001, 5); //preamble cont. + if(bit_lib_get_bits(protocol->data, 0, 8) == 0) { + protocol->bit_format = 26; + // set bit length + bit_lib_set_bits(protocol->RKKT_encoded_data, 13, protocol->bit_format, 6); + // set even parity & odd parity + if(!bit_lib_test_parity(protocol->data, 8, 12, BitLibParityOdd, 12)) { + bit_lib_set_bit(protocol->RKKT_encoded_data, 35, 1); + } + if(bit_lib_test_parity(protocol->data, 20, 12, BitLibParityOdd, 12)) { + bit_lib_set_bit(protocol->RKKT_encoded_data, 63, 1); + } + // write facility number (f) + bit_lib_copy_bits(protocol->RKKT_encoded_data, 36, 1, protocol->data, 8); + // have to skip one spacer + bit_lib_copy_bits(protocol->RKKT_encoded_data, 38, 7, protocol->data, 9); + } else { + protocol->bit_format = 32; + // set bit length + bit_lib_set_bits(protocol->RKKT_encoded_data, 13, protocol->bit_format, 6); + // set EP & OP + if(!bit_lib_test_parity(protocol->data, 2, 15, BitLibParityOdd, 15)) { + bit_lib_set_bit(protocol->RKKT_encoded_data, 29, 1); + } + if(bit_lib_test_parity(protocol->data, 17, 15, BitLibParityOdd, 15)) { + bit_lib_set_bit(protocol->RKKT_encoded_data, 63, 1); + } + // write facility number (f) + bit_lib_copy_bits(protocol->RKKT_encoded_data, 30, 7, protocol->data, 2); + // have to skip one spacer + bit_lib_copy_bits(protocol->RKKT_encoded_data, 38, 7, protocol->data, 3); } - if(bit_lib_test_parity(protocol->data, 17, 15, BitLibParityOdd, 15)) { - bit_lib_set_bit(protocol->encoded_data, 63, 1); - } - // write facility number (f) - bit_lib_copy_bits(protocol->encoded_data, 30, 7, protocol->data, 2); - // have to skip one spacer - bit_lib_copy_bits(protocol->encoded_data, 38, 7, protocol->data, 3); + + // write card number (c) + bit_lib_copy_bits(protocol->RKKT_encoded_data, 45, 1, protocol->data, 16); + // same skips here + bit_lib_copy_bits(protocol->RKKT_encoded_data, 47, 8, protocol->data, 17); + bit_lib_copy_bits(protocol->RKKT_encoded_data, 56, 7, protocol->data, 25); + + // unsure about CS yet might as well just copy it from saved + // CS1 + bit_lib_copy_bits(protocol->RKKT_encoded_data, 65, 8, protocol->data, 32); + // CS2 + bit_lib_copy_bits(protocol->RKKT_encoded_data, 74, 8, protocol->data, 40); } - - // write card number (c) - bit_lib_copy_bits(protocol->encoded_data, 45, 1, protocol->data, 16); - // same skips here - bit_lib_copy_bits(protocol->encoded_data, 47, 8, protocol->data, 17); - bit_lib_copy_bits(protocol->encoded_data, 56, 7, protocol->data, 25); - - // unsure about CS yet might as well just copy it from saved - // CS1 - bit_lib_copy_bits(protocol->encoded_data, 65, 8, protocol->data, 32); - // CS2 - bit_lib_copy_bits(protocol->encoded_data, 74, 8, protocol->data, 40); - // for sending we start at bit 0. protocol->encoded_data_index = 0; protocol->encoded_polarity = true; @@ -235,36 +280,61 @@ bool protocol_securakey_encoder_start(ProtocolSecurakey* protocol) { }; LevelDuration protocol_securakey_encoder_yield(ProtocolSecurakey* protocol) { - bool level = bit_lib_get_bit(protocol->encoded_data, protocol->encoded_data_index); - uint32_t duration = SECURAKEY_CLOCK_PER_BIT / 2; - if(protocol->encoded_polarity) { - protocol->encoded_polarity = false; + if(bit_lib_get_bits_16(protocol->data, 0, 16) == 0) { + bool level = bit_lib_get_bit(protocol->RKKTH_encoded_data, protocol->encoded_data_index); + uint32_t duration = SECURAKEY_CLOCK_PER_BIT / 2; + if(protocol->encoded_polarity) { + protocol->encoded_polarity = false; + } else { + level = !level; + protocol->encoded_polarity = true; + bit_lib_increment_index( + protocol->encoded_data_index, SECURAKEY_RKKTH_ENCODED_FULL_SIZE_BITS); + } + return level_duration_make(level, duration); } else { - level = !level; - protocol->encoded_polarity = true; - bit_lib_increment_index(protocol->encoded_data_index, SECURAKEY_ENCODED_FULL_SIZE_BITS); + bool level = bit_lib_get_bit(protocol->RKKT_encoded_data, protocol->encoded_data_index); + uint32_t duration = SECURAKEY_CLOCK_PER_BIT / 2; + if(protocol->encoded_polarity) { + protocol->encoded_polarity = false; + } else { + level = !level; + protocol->encoded_polarity = true; + bit_lib_increment_index( + protocol->encoded_data_index, SECURAKEY_RKKT_ENCODED_FULL_SIZE_BITS); + } + return level_duration_make(level, duration); } - return level_duration_make(level, duration); }; bool protocol_securakey_write_data(ProtocolSecurakey* protocol, void* data) { + protocol_securakey_encoder_start(protocol); LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; bool result = false; - // Correct protocol data by redecoding - protocol_securakey_encoder_start(protocol); - protocol_securakey_decode(protocol); - protocol_securakey_encoder_start(protocol); // Write T5577 - if(request->write_type == LFRFIDWriteTypeT5577) { - request->t5577.block[0] = - (LFRFID_T5577_MODULATION_MANCHESTER | LFRFID_T5577_BITRATE_RF_40 | - (3 - << LFRFID_T5577_MAXBLOCK_SHIFT)); // we only need 3 32-bit blocks for our 96-bit encoded data - request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32); - request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32); - request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32); - request->t5577.blocks_to_write = 4; - result = true; + if(bit_lib_get_bits_16(protocol->data, 0, 16) == 0) { + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = + (LFRFID_T5577_MODULATION_MANCHESTER | LFRFID_T5577_BITRATE_RF_40 | + (2 + << LFRFID_T5577_MAXBLOCK_SHIFT)); // we only need 2 32-bit blocks for our 64-bit encoded data + request->t5577.block[1] = bit_lib_get_bits_32(protocol->RKKTH_encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->RKKTH_encoded_data, 32, 32); + request->t5577.blocks_to_write = 3; + result = true; + } + } else { + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = + (LFRFID_T5577_MODULATION_MANCHESTER | LFRFID_T5577_BITRATE_RF_40 | + (3 + << LFRFID_T5577_MAXBLOCK_SHIFT)); // we only need 3 32-bit blocks for our 96-bit encoded data + request->t5577.block[1] = bit_lib_get_bits_32(protocol->RKKT_encoded_data, 0, 32); + request->t5577.block[2] = bit_lib_get_bits_32(protocol->RKKT_encoded_data, 32, 32); + request->t5577.block[3] = bit_lib_get_bits_32(protocol->RKKT_encoded_data, 64, 32); + request->t5577.blocks_to_write = 4; + result = true; + } } return result; };