M5Unit-NFC 0.1.0 git rev:93745b5
Loading...
Searching...
No Matches
mifare_classic_crypto1.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
10#ifndef M5_UNIT_UNIFIED_NFC_NFC_A_MIFARE_CLASSIC_CRYPTO1_HPP
11#define M5_UNIT_UNIFIED_NFC_NFC_A_MIFARE_CLASSIC_CRYPTO1_HPP
12
13#include <M5Utility.hpp>
14
15namespace m5 {
16namespace nfc {
17namespace a {
18namespace mifare {
19namespace classic {
20
22using MLFSR48 = m5::utility::FibonacciLFSR_Left<48, 5, 6, 7, 9, 13, 19, 21, 23, 24, 29, 31, 33, 34, 36, 38, 39, 43, 48>;
27class Crypto1 : public MLFSR48 {
28public:
30 Crypto1() noexcept : MLFSR48(0)
31 {
32 }
33
38 explicit Crypto1(const uint64_t key48) noexcept : MLFSR48(0)
39 {
40 init(key48);
41 }
42
47 void init(const uint64_t key48) noexcept
48 {
49 _state = state_type_t{};
50 // Change the bit order within the byte to LSB first
51 for (int i = 0; i < 48; ++i) {
52 int byte_index = i >> 3;
53 int bit_index = i & 0x07;
54 int reversed = (byte_index << 3) + (bit_index ^ 7);
55 bool bit = (key48 >> reversed) & 1ULL;
56 _state[i] = bit;
57 }
58 _count = 0;
59 }
60
68 inline uint32_t inject(uint32_t uid, uint32_t Nt, const bool encrypted = false) noexcept
69 {
70 return step32(uid ^ Nt, encrypted);
71 }
72
79 bool step_with(const bool in, const bool enc = false) noexcept
80 {
81 ++_count;
82
83 bool z = filter();
84 (void)step();
85 const bool ext = in ^ (enc ? z : 0);
86 _state[0] = _state[0] ^ ext;
87 return z;
88 }
89
96 uint8_t step8(const uint8_t in, const bool enc = false) noexcept
97 {
98 uint8_t v{};
99 for (uint_fast8_t i = 0; i < 8; ++i) {
100 v |= step_with((in >> i) & 1, enc) << i;
101 }
102 return v;
103 }
104
111 uint32_t step32(const uint32_t in, const bool enc = false) noexcept
112 {
113 uint32_t v{};
114 for (uint32_t i = 0; i < 32; ++i) {
115 bool t = step_with((in >> (i ^ 24)) & 1u, enc);
116 v |= t << (24 ^ i);
117 }
118 return v;
119 }
120
126 static inline uint8_t oddparity8(uint8_t x) noexcept
127 {
128 return !__builtin_parity(x);
129 }
130
138 uint8_t encrypt(uint8_t buf[8], const uint32_t Nr, const uint32_t Ar) noexcept
139 {
140 uint8_t parity{};
141 for (uint_fast8_t i = 0; i < 4; ++i) {
142 const uint8_t v = ((Nr >> ((i ^ 0x03) << 3)) & 0xFF);
143 buf[i] = step8(v) ^ v;
144 const uint8_t z = filter();
145 parity |= static_cast<uint8_t>((z ^ oddparity8(v)) & 0x01) << i;
146 }
147
148 for (uint_fast8_t pos = 4; pos < 8; ++pos) {
149 const uint8_t i = pos - 4;
150 // const uint8_t v = static_cast<uint8_t>(Ar >> (i << 3));
151 const uint8_t v = (Ar >> (i << 3)) & 0xFF;
152 const uint8_t ks = step8(0x00);
153 buf[pos] = ks ^ v;
154 const uint8_t z = filter();
155 parity |= static_cast<uint8_t>((z ^ oddparity8(v)) & 0x01) << pos;
156 }
157 return parity;
158 }
159
167 uint32_t encrypt(uint8_t* out, const uint8_t* in, const uint8_t in_len /* max 32 */)
168 {
169 uint32_t parity{};
170 for (uint_fast8_t i = 0; i < in_len; ++i) {
171 uint8_t ks = step8(0);
172 out[i] = in[i] ^ ks;
173 parity |= ((filter() ^ oddparity8(in[i])) & 1) << i;
174 }
175 return parity;
176 }
177
182 inline bool filter() const noexcept
183 {
184 const state_type_t& s = state();
185 const bool b5 = fb(s[6], s[4], s[2], s[0]);
186 const bool a4 = fa(s[14], s[12], s[10], s[8]);
187 const bool b3 = fb(s[22], s[20], s[18], s[16]);
188 const bool b2 = fb(s[30], s[28], s[26], s[24]);
189 const bool a1 = fa(s[38], s[36], s[34], s[32]);
190 return fc(a1, b2, b3, a4, b5);
191 }
192
201 inline static bool fa(bool a, bool b, bool c, bool d) noexcept
202 {
203 return ((a || b) ^ (a && d)) ^ (c && ((a ^ b) || d));
204 }
205
214 inline static bool fb(bool a, bool b, bool c, bool d) noexcept
215 {
216 return ((a && b) || c) ^ ((a ^ b) && (c || d));
217 }
218
228 inline static bool fc(bool a, bool b, bool c, bool d, bool e) noexcept
229 {
230 return (a || ((b || e) && (d ^ e))) ^ ((a ^ (b && d)) && ((c ^ d) || (b && e)));
231 }
232
233 uint32_t _count{}; // for debug
234};
235
236} // namespace classic
237} // namespace mifare
238} // namespace a
239} // namespace nfc
240} // namespace m5
241
242#endif
Crypto1 for MIFARE Classic.
Definition mifare_classic_crypto1.hpp:27
uint32_t encrypt(uint8_t *out, const uint8_t *in, const uint8_t in_len)
Encrypt a byte buffer.
Definition mifare_classic_crypto1.hpp:167
uint32_t inject(uint32_t uid, uint32_t Nt, const bool encrypted=false) noexcept
Inject UID and card nonce into the cipher state.
Definition mifare_classic_crypto1.hpp:68
static bool fc(bool a, bool b, bool c, bool d, bool e) noexcept
Crypto1 filter helper C.
Definition mifare_classic_crypto1.hpp:228
Crypto1() noexcept
Default ctor (zero-initialized state)
Definition mifare_classic_crypto1.hpp:30
bool step_with(const bool in, const bool enc=false) noexcept
Step the cipher with one input bit.
Definition mifare_classic_crypto1.hpp:79
uint32_t step32(const uint32_t in, const bool enc=false) noexcept
Step the cipher with 32 input bits.
Definition mifare_classic_crypto1.hpp:111
static bool fb(bool a, bool b, bool c, bool d) noexcept
Crypto1 filter helper B.
Definition mifare_classic_crypto1.hpp:214
Crypto1(const uint64_t key48) noexcept
Construct with 48-bit key.
Definition mifare_classic_crypto1.hpp:38
uint8_t step8(const uint8_t in, const bool enc=false) noexcept
Step the cipher with 8 input bits.
Definition mifare_classic_crypto1.hpp:96
bool filter() const noexcept
Crypto1 nonlinear filter.
Definition mifare_classic_crypto1.hpp:182
static bool fa(bool a, bool b, bool c, bool d) noexcept
Crypto1 filter helper A.
Definition mifare_classic_crypto1.hpp:201
static uint8_t oddparity8(uint8_t x) noexcept
Calculate odd parity for one byte.
Definition mifare_classic_crypto1.hpp:126
void init(const uint64_t key48) noexcept
Initialize with 48-bit key.
Definition mifare_classic_crypto1.hpp:47
uint8_t encrypt(uint8_t buf[8], const uint32_t Nr, const uint32_t Ar) noexcept
Encrypt reader nonce and authenticator response.
Definition mifare_classic_crypto1.hpp:138
m5::utility::FibonacciLFSR_Left< 48, 5, 6, 7, 9, 13, 19, 21, 23, 24, 29, 31, 33, 34, 36, 38, 39, 43, 48 > MLFSR48
48-bit LFSR used by Crypto1
Definition mifare_classic_crypto1.hpp:22
NFC-A definitions.
NFC-B definitions.
For MIFARE classic.
Top level namespace of M5Stack.
For MIFARE.
NFC related definitions.
NFC-V definitions.