unleashed-firmware/lib/lfrfid/protocols/protocol_securakey.c
Zinong Li e7d0afdc50
[LFRFID] Added Support for Securakey Protocol (#3697)
* 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

Co-authored-by: あく <alleteam@gmail.com>
2024-06-13 12:55:51 +01:00

294 lines
12 KiB
C

// The timing parameters and data structure used in this file
// are based on the knowledge found in Proxmark3's firmware:
// https://github.com/RfidResearchGroup/proxmark3/blob/1c52152d30f7744c0336633317ea6640dbcdc796/client/src/cmdlfsecurakey.c
// PM3's repo has mentioned the existence of non-26-or-32-bit formats.
// Those are not supported here for preventing false positives.
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <toolbox/hex.h>
#include <bit_lib/bit_lib.h>
#include "lfrfid_protocols.h"
#include <toolbox/manchester_decoder.h>
#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_DECODED_DATA_SIZE_BYTES (SECURAKEY_DECODED_DATA_SIZE_BITS / 8)
#define LFRFID_FREQUENCY (125000)
#define SECURAKEY_CLOCK_PER_BIT (40) // RF/40
#define SECURAKEY_READ_LONG_TIME \
(1000000 / (LFRFID_FREQUENCY / SECURAKEY_CLOCK_PER_BIT)) // 1000000 micro sec / sec
#define SECURAKEY_READ_SHORT_TIME (SECURAKEY_READ_LONG_TIME / 2)
#define SECURAKEY_READ_JITTER_TIME (SECURAKEY_READ_SHORT_TIME * 40 / 100) // 40% jitter tolerance
#define SECURAKEY_READ_SHORT_TIME_LOW \
(SECURAKEY_READ_SHORT_TIME - \
SECURAKEY_READ_JITTER_TIME) // these are used for manchester decoding
#define SECURAKEY_READ_SHORT_TIME_HIGH (SECURAKEY_READ_SHORT_TIME + SECURAKEY_READ_JITTER_TIME)
#define SECURAKEY_READ_LONG_TIME_LOW (SECURAKEY_READ_LONG_TIME - SECURAKEY_READ_JITTER_TIME)
#define SECURAKEY_READ_LONG_TIME_HIGH (SECURAKEY_READ_LONG_TIME + SECURAKEY_READ_JITTER_TIME)
typedef struct {
uint8_t data[SECURAKEY_DECODED_DATA_SIZE_BYTES];
uint8_t encoded_data[SECURAKEY_ENCODED_FULL_SIZE_BYTE];
uint8_t encoded_data_index;
bool encoded_polarity;
ManchesterState decoder_manchester_state;
uint8_t bit_format;
} ProtocolSecurakey;
ProtocolSecurakey* protocol_securakey_alloc(void) {
ProtocolSecurakey* protocol = malloc(sizeof(ProtocolSecurakey));
return (void*)protocol;
};
void protocol_securakey_free(ProtocolSecurakey* protocol) {
free(protocol);
};
uint8_t* protocol_securakey_get_data(ProtocolSecurakey* protocol) {
return protocol->data;
};
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;
}
} else {
return false;
}
};
static void protocol_securakey_decode(ProtocolSecurakey* protocol) {
memset(protocol->data, 0, SECURAKEY_DECODED_DATA_SIZE_BYTES);
// 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
// 32-bit format (1-bit even parity bit, 14-bit facility number, 16-bit card number, 1-bit odd parity bit)
// 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);
}
// 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
// 00000000 00011011 00011111 00110001 00001111 01100000
// 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
};
void protocol_securakey_decoder_start(ProtocolSecurakey* protocol) {
memset(protocol->encoded_data, 0, SECURAKEY_ENCODED_FULL_SIZE_BYTE);
manchester_advance(
protocol->decoder_manchester_state,
ManchesterEventReset,
&protocol->decoder_manchester_state,
NULL);
};
bool protocol_securakey_decoder_feed(ProtocolSecurakey* protocol, bool level, uint32_t duration) {
bool result = false;
// this is where we do manchester demodulation on already ASK-demoded data
ManchesterEvent event = ManchesterEventReset;
if(duration > SECURAKEY_READ_SHORT_TIME_LOW && duration < SECURAKEY_READ_SHORT_TIME_HIGH) {
if(!level) {
event = ManchesterEventShortHigh;
} else {
event = ManchesterEventShortLow;
}
} else if(duration > SECURAKEY_READ_LONG_TIME_LOW && duration < SECURAKEY_READ_LONG_TIME_HIGH) {
if(!level) {
event = ManchesterEventLongHigh;
} else {
event = ManchesterEventLongLow;
}
}
// append a new bit to the encoded bit stream
if(event != ManchesterEventReset) {
bool data;
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);
if(protocol_securakey_can_be_decoded(protocol)) {
protocol_securakey_decode(protocol);
result = true;
}
}
}
return result;
};
void protocol_securakey_render_data(ProtocolSecurakey* protocol, FuriString* result) {
if(bit_lib_get_bits(protocol->data, 0, 8) == 0) {
protocol->bit_format = 26;
} else {
protocol->bit_format = 32;
}
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);
} 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);
}
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->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;
return true;
};
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;
} else {
level = !level;
protocol->encoded_polarity = true;
bit_lib_increment_index(protocol->encoded_data_index, SECURAKEY_ENCODED_FULL_SIZE_BITS);
}
return level_duration_make(level, duration);
};
bool protocol_securakey_write_data(ProtocolSecurakey* protocol, void* data) {
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;
}
return result;
};
const ProtocolBase protocol_securakey = {
.name = "Radio Key",
.manufacturer = "Securakey",
.data_size = SECURAKEY_DECODED_DATA_SIZE_BYTES,
.features = LFRFIDFeatureASK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_securakey_alloc,
.free = (ProtocolFree)protocol_securakey_free,
.get_data = (ProtocolGetData)protocol_securakey_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_securakey_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_securakey_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_securakey_encoder_start,
.yield = (ProtocolEncoderYield)protocol_securakey_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_securakey_render_data,
.render_brief_data = (ProtocolRenderData)protocol_securakey_render_data,
.write_data = (ProtocolWriteData)protocol_securakey_write_data,
};