Skip to content

Commit 04fa7a9

Browse files
zinongliskotopes
andauthored
LFRFID: Noralsy Format/Brand (#4090)
* beta version * Working. No parsing yet. No checksum yet. * T5 config caveat * parsings Co-authored-by: あく <alleteam@gmail.com>
1 parent 77445fd commit 04fa7a9

File tree

4 files changed

+240
-0
lines changed

4 files changed

+240
-0
lines changed

lib/lfrfid/protocols/lfrfid_protocols.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "protocol_nexwatch.h"
2121
#include "protocol_securakey.h"
2222
#include "protocol_gproxii.h"
23+
#include "protocol_noralsy.h"
2324

2425
const ProtocolBase* lfrfid_protocols[] = {
2526
[LFRFIDProtocolEM4100] = &protocol_em4100,
@@ -45,4 +46,5 @@ const ProtocolBase* lfrfid_protocols[] = {
4546
[LFRFIDProtocolNexwatch] = &protocol_nexwatch,
4647
[LFRFIDProtocolSecurakey] = &protocol_securakey,
4748
[LFRFIDProtocolGProxII] = &protocol_gproxii,
49+
[LFRFIDProtocolNoralsy] = &protocol_noralsy,
4850
};

lib/lfrfid/protocols/lfrfid_protocols.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ typedef enum {
3232
LFRFIDProtocolNexwatch,
3333
LFRFIDProtocolSecurakey,
3434
LFRFIDProtocolGProxII,
35+
LFRFIDProtocolNoralsy,
3536

3637
LFRFIDProtocolMax,
3738
} LFRFIDProtocol;
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
#include <furi.h>
2+
#include <toolbox/protocols/protocol.h>
3+
#include <toolbox/manchester_decoder.h>
4+
#include <bit_lib/bit_lib.h>
5+
#include "lfrfid_protocols.h"
6+
7+
#define NORALSY_CLOCK_PER_BIT (32)
8+
9+
#define NORALSY_ENCODED_BIT_SIZE (96)
10+
#define NORALSY_ENCODED_BYTE_SIZE ((NORALSY_ENCODED_BIT_SIZE) / 8)
11+
#define NORALSY_PREAMBLE_BIT_SIZE (32)
12+
#define NORALSY_PREAMBLE_BYTE_SIZE ((NORALSY_PREAMBLE_BIT_SIZE) / 8)
13+
#define NORALSY_ENCODED_BYTE_FULL_SIZE ((NORALSY_ENCODED_BIT_SIZE) / 8)
14+
#define NORALSY_DECODED_DATA_SIZE ((NORALSY_ENCODED_BIT_SIZE) / 8)
15+
16+
#define NORALSY_READ_SHORT_TIME (128)
17+
#define NORALSY_READ_LONG_TIME (256)
18+
#define NORALSY_READ_JITTER_TIME (60)
19+
20+
#define NORALSY_READ_SHORT_TIME_LOW (NORALSY_READ_SHORT_TIME - NORALSY_READ_JITTER_TIME)
21+
#define NORALSY_READ_SHORT_TIME_HIGH (NORALSY_READ_SHORT_TIME + NORALSY_READ_JITTER_TIME)
22+
#define NORALSY_READ_LONG_TIME_LOW (NORALSY_READ_LONG_TIME - NORALSY_READ_JITTER_TIME)
23+
#define NORALSY_READ_LONG_TIME_HIGH (NORALSY_READ_LONG_TIME + NORALSY_READ_JITTER_TIME)
24+
25+
#define TAG "NORALSY"
26+
27+
typedef struct {
28+
uint8_t data[NORALSY_ENCODED_BYTE_SIZE];
29+
uint8_t encoded_data[NORALSY_ENCODED_BYTE_SIZE];
30+
31+
uint8_t encoded_data_index;
32+
bool encoded_polarity;
33+
34+
ManchesterState decoder_manchester_state;
35+
} ProtocolNoralsy;
36+
37+
ProtocolNoralsy* protocol_noralsy_alloc(void) {
38+
ProtocolNoralsy* protocol = malloc(sizeof(ProtocolNoralsy));
39+
return (void*)protocol;
40+
}
41+
42+
void protocol_noralsy_free(ProtocolNoralsy* protocol) {
43+
free(protocol);
44+
}
45+
46+
static uint8_t noralsy_chksum(uint8_t* bits, uint8_t len) {
47+
uint8_t sum = 0;
48+
for(uint8_t i = 0; i < len; i += 4)
49+
sum ^= bit_lib_get_bits(bits, i, 4);
50+
return sum & 0x0F;
51+
}
52+
53+
uint8_t* protocol_noralsy_get_data(ProtocolNoralsy* protocol) {
54+
return protocol->data;
55+
}
56+
57+
static void protocol_noralsy_decode(ProtocolNoralsy* protocol) {
58+
bit_lib_copy_bits(protocol->data, 0, NORALSY_ENCODED_BIT_SIZE, protocol->encoded_data, 0);
59+
}
60+
61+
static bool protocol_noralsy_can_be_decoded(ProtocolNoralsy* protocol) {
62+
// check 12 bits preamble
63+
// If necessary, use 0xBB0214FF for 32 bit preamble check
64+
// However, it is not confirmed the 13-16 bit are static.
65+
if(bit_lib_get_bits_16(protocol->encoded_data, 0, 12) != 0b101110110000) return false;
66+
uint8_t calc1 = noralsy_chksum(&protocol->encoded_data[4], 40);
67+
uint8_t calc2 = noralsy_chksum(&protocol->encoded_data[0], 76);
68+
uint8_t chk1 = bit_lib_get_bits(protocol->encoded_data, 72, 4);
69+
uint8_t chk2 = bit_lib_get_bits(protocol->encoded_data, 76, 4);
70+
if(calc1 != chk1 || calc2 != chk2) return false;
71+
72+
return true;
73+
}
74+
75+
void protocol_noralsy_decoder_start(ProtocolNoralsy* protocol) {
76+
memset(protocol->encoded_data, 0, NORALSY_ENCODED_BYTE_FULL_SIZE);
77+
manchester_advance(
78+
protocol->decoder_manchester_state,
79+
ManchesterEventReset,
80+
&protocol->decoder_manchester_state,
81+
NULL);
82+
}
83+
84+
bool protocol_noralsy_decoder_feed(ProtocolNoralsy* protocol, bool level, uint32_t duration) {
85+
bool result = false;
86+
87+
ManchesterEvent event = ManchesterEventReset;
88+
89+
if(duration > NORALSY_READ_SHORT_TIME_LOW && duration < NORALSY_READ_SHORT_TIME_HIGH) {
90+
if(!level) {
91+
event = ManchesterEventShortHigh;
92+
} else {
93+
event = ManchesterEventShortLow;
94+
}
95+
} else if(duration > NORALSY_READ_LONG_TIME_LOW && duration < NORALSY_READ_LONG_TIME_HIGH) {
96+
if(!level) {
97+
event = ManchesterEventLongHigh;
98+
} else {
99+
event = ManchesterEventLongLow;
100+
}
101+
}
102+
103+
if(event != ManchesterEventReset) {
104+
bool data;
105+
bool data_ok = manchester_advance(
106+
protocol->decoder_manchester_state, event, &protocol->decoder_manchester_state, &data);
107+
108+
if(data_ok) {
109+
bit_lib_push_bit(protocol->encoded_data, NORALSY_ENCODED_BYTE_FULL_SIZE, data);
110+
111+
if(protocol_noralsy_can_be_decoded(protocol)) {
112+
protocol_noralsy_decode(protocol);
113+
result = true;
114+
}
115+
}
116+
}
117+
118+
return result;
119+
}
120+
121+
bool protocol_noralsy_encoder_start(ProtocolNoralsy* protocol) {
122+
bit_lib_copy_bits(protocol->encoded_data, 0, NORALSY_ENCODED_BIT_SIZE, protocol->data, 0);
123+
124+
return true;
125+
}
126+
127+
LevelDuration protocol_noralsy_encoder_yield(ProtocolNoralsy* protocol) {
128+
bool level = bit_lib_get_bit(protocol->encoded_data, protocol->encoded_data_index);
129+
uint32_t duration = NORALSY_CLOCK_PER_BIT / 2;
130+
131+
if(protocol->encoded_polarity) {
132+
protocol->encoded_polarity = false;
133+
} else {
134+
level = !level;
135+
136+
protocol->encoded_polarity = true;
137+
bit_lib_increment_index(protocol->encoded_data_index, NORALSY_ENCODED_BIT_SIZE);
138+
}
139+
140+
return level_duration_make(level, duration);
141+
}
142+
143+
bool protocol_noralsy_write_data(ProtocolNoralsy* protocol, void* data) {
144+
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
145+
bool result = false;
146+
147+
// Correct protocol data by redecoding
148+
protocol_noralsy_encoder_start(protocol);
149+
protocol_noralsy_decode(protocol);
150+
151+
protocol_noralsy_encoder_start(protocol);
152+
153+
if(request->write_type == LFRFIDWriteTypeT5577) {
154+
request->t5577.block[0] =
155+
(LFRFID_T5577_MODULATION_MANCHESTER | LFRFID_T5577_BITRATE_RF_32 |
156+
(3 << LFRFID_T5577_MAXBLOCK_SHIFT) | LFRFID_T5577_ST_TERMINATOR);
157+
// In fact, base on the current two dump samples from Iceman server,
158+
// Noralsy are usually T5577s with config = 0x00088C6A
159+
// But the `C` and `A` are not explainable by the ATA5577C datasheet
160+
// and they don't affect reading whatsoever.
161+
// So we are mimicing Proxmark's solution here. Leave those nibbles as zero.
162+
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
163+
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
164+
request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32);
165+
request->t5577.blocks_to_write = 4;
166+
result = true;
167+
}
168+
return result;
169+
}
170+
171+
static void protocol_noralsy_render_data_internal(
172+
ProtocolNoralsy* protocol,
173+
FuriString* result,
174+
bool brief) {
175+
UNUSED(protocol);
176+
uint32_t raw2 = bit_lib_get_bits_32(protocol->data, 32, 32);
177+
uint32_t raw3 = bit_lib_get_bits_32(protocol->data, 64, 32);
178+
uint32_t cardid = ((raw2 & 0xFFF00000) >> 20) << 16;
179+
cardid |= (raw2 & 0xFF) << 8;
180+
cardid |= ((raw3 & 0xFF000000) >> 24);
181+
182+
uint8_t year = (raw2 & 0x000ff000) >> 12;
183+
bool tag_is_gen_z = (year > 0x60);
184+
if(brief) {
185+
furi_string_printf(
186+
result,
187+
"Card ID: %07lx\n"
188+
"Year: %s%02x",
189+
cardid,
190+
tag_is_gen_z ? "19" : "20",
191+
year);
192+
} else {
193+
furi_string_printf(
194+
result,
195+
"Card ID: %07lx\n"
196+
"Year: %s%02x",
197+
cardid,
198+
tag_is_gen_z ? "19" : "20",
199+
year);
200+
}
201+
}
202+
203+
void protocol_noralsy_render_data(ProtocolNoralsy* protocol, FuriString* result) {
204+
protocol_noralsy_render_data_internal(protocol, result, false);
205+
}
206+
207+
void protocol_noralsy_render_brief_data(ProtocolNoralsy* protocol, FuriString* result) {
208+
protocol_noralsy_render_data_internal(protocol, result, true);
209+
}
210+
211+
const ProtocolBase protocol_noralsy = {
212+
.name = "Noralsy",
213+
.manufacturer = "Noralsy",
214+
.data_size = NORALSY_DECODED_DATA_SIZE,
215+
.features = LFRFIDFeatureASK,
216+
.validate_count = 3,
217+
.alloc = (ProtocolAlloc)protocol_noralsy_alloc,
218+
.free = (ProtocolFree)protocol_noralsy_free,
219+
.get_data = (ProtocolGetData)protocol_noralsy_get_data,
220+
.decoder =
221+
{
222+
.start = (ProtocolDecoderStart)protocol_noralsy_decoder_start,
223+
.feed = (ProtocolDecoderFeed)protocol_noralsy_decoder_feed,
224+
},
225+
.encoder =
226+
{
227+
.start = (ProtocolEncoderStart)protocol_noralsy_encoder_start,
228+
.yield = (ProtocolEncoderYield)protocol_noralsy_encoder_yield,
229+
},
230+
.render_data = (ProtocolRenderData)protocol_noralsy_render_data,
231+
.render_brief_data = (ProtocolRenderData)protocol_noralsy_render_brief_data,
232+
.write_data = (ProtocolWriteData)protocol_noralsy_write_data,
233+
};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#pragma once
2+
#include <toolbox/protocols/protocol.h>
3+
4+
extern const ProtocolBase protocol_noralsy;

0 commit comments

Comments
 (0)