M5Unit-NFC 0.0.3 git rev:59f5362
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
21using MLFSR48 = m5::utility::FibonacciLFSR_Left<48, 5, 6, 7, 9, 13, 19, 21, 23, 24, 29, 31, 33, 34, 36, 38, 39, 43, 48>;
26class Crypto1 : public MLFSR48 {
27public:
28 Crypto1() noexcept : MLFSR48(0)
29 {
30 }
31
32 explicit Crypto1(const uint64_t key48) noexcept : MLFSR48(0)
33 {
34 init(key48);
35 }
36
37 void init(const uint64_t key48) noexcept
38 {
39 _state = state_type_t{};
40 // Change the bit order within the byte to LSB first
41 for (int i = 0; i < 48; ++i) {
42 int byte_index = i >> 3;
43 int bit_index = i & 0x07;
44 int reversed = (byte_index << 3) + (bit_index ^ 7);
45 bool bit = (key48 >> reversed) & 1ULL;
46 _state[i] = bit;
47 }
48 _count = 0;
49 }
50
51 inline uint32_t inject(uint32_t uid, uint32_t Nt, const bool encrypted = false) noexcept
52 {
53 return step32(uid ^ Nt, encrypted);
54 }
55
56 bool step_with(const bool in, const bool enc = false) noexcept
57 {
58 ++_count;
59
60 bool z = filter();
61 (void)step();
62 const bool ext = in ^ (enc ? z : 0);
63 _state[0] = _state[0] ^ ext;
64 return z;
65 }
66
67 uint8_t step8(const uint8_t in, const bool enc = false) noexcept
68 {
69 uint8_t v{};
70 for (uint_fast8_t i = 0; i < 8; ++i) {
71 v |= step_with((in >> i) & 1, enc) << i;
72 }
73 return v;
74 }
75
76 uint32_t step32(const uint32_t in, const bool enc = false) noexcept
77 {
78 uint32_t v{};
79 for (uint32_t i = 0; i < 32; ++i) {
80 bool t = step_with((in >> (i ^ 24)) & 1u, enc);
81 v |= t << (24 ^ i);
82 }
83 return v;
84 }
85
86 static inline uint8_t oddparity8(uint8_t x) noexcept
87 {
88 return !__builtin_parity(x);
89 }
90
91 uint8_t encrypt(uint8_t buf[8], const uint32_t Nr, const uint32_t Ar) noexcept
92 {
93 uint8_t parity{};
94 for (uint_fast8_t i = 0; i < 4; ++i) {
95 const uint8_t v = ((Nr >> ((i ^ 0x03) << 3)) & 0xFF);
96 buf[i] = step8(v) ^ v;
97 const uint8_t z = filter();
98 parity |= static_cast<uint8_t>((z ^ oddparity8(v)) & 0x01) << i;
99 }
100
101 for (uint_fast8_t pos = 4; pos < 8; ++pos) {
102 const uint8_t i = pos - 4;
103 // const uint8_t v = static_cast<uint8_t>(Ar >> (i << 3));
104 const uint8_t v = (Ar >> (i << 3)) & 0xFF;
105 const uint8_t ks = step8(0x00);
106 buf[pos] = ks ^ v;
107 const uint8_t z = filter();
108 parity |= static_cast<uint8_t>((z ^ oddparity8(v)) & 0x01) << pos;
109 }
110 return parity;
111 }
112
113 uint32_t encrypt(uint8_t* out, const uint8_t* in, const uint8_t in_len /* max 32 */)
114 {
115 uint32_t parity{};
116 for (uint_fast8_t i = 0; i < in_len; ++i) {
117 uint8_t ks = step8(0);
118 out[i] = in[i] ^ ks;
119 parity |= ((filter() ^ oddparity8(in[i])) & 1) << i;
120 }
121 return parity;
122 }
123
124 inline bool filter() const noexcept
125 {
126 const state_type_t& s = state();
127 const bool b5 = fb(s[6], s[4], s[2], s[0]);
128 const bool a4 = fa(s[14], s[12], s[10], s[8]);
129 const bool b3 = fb(s[22], s[20], s[18], s[16]);
130 const bool b2 = fb(s[30], s[28], s[26], s[24]);
131 const bool a1 = fa(s[38], s[36], s[34], s[32]);
132 return fc(a1, b2, b3, a4, b5);
133 }
134
135 inline static bool fa(bool a, bool b, bool c, bool d) noexcept
136 {
137 return ((a || b) ^ (a && d)) ^ (c && ((a ^ b) || d));
138 }
139
140 inline static bool fb(bool a, bool b, bool c, bool d) noexcept
141 {
142 return ((a && b) || c) ^ ((a ^ b) && (c || d));
143 }
144
145 inline static bool fc(bool a, bool b, bool c, bool d, bool e) noexcept
146 {
147 return (a || ((b || e) && (d ^ e))) ^ ((a ^ (b && d)) && ((c ^ d) || (b && e)));
148 }
149
150 uint32_t _count{}; // for debug
151};
152
153} // namespace classic
154} // namespace mifare
155} // namespace a
156} // namespace nfc
157} // namespace m5
158
159#endif
Crypto1 for MIFARE Classic.
Definition mifare_classic_crypto1.hpp:26
NFC-A definitions.
NFC-B definitions.
For MIFARE classic.
Top level namespace of M5stack.
For MIFARE.
NFC related definitions.
NFC-V definitions.