13constexpr uint8_t kPcbBlockKindMask = 0xC0;
14constexpr uint8_t kPcbIBlock = 0x00;
15constexpr uint8_t kPcbRBlock = 0x80;
16constexpr uint8_t kPcbSBlock = 0xC0;
19constexpr uint8_t kPcbINs = 0x40;
20constexpr uint8_t kPcbIMore = 0x20;
21constexpr uint8_t kPcbIReservedMask = 0x1F;
24constexpr uint8_t kPcbRNr = 0x10;
25constexpr uint8_t kPcbRErrMask = 0x03;
26constexpr uint8_t kPcbRReservedMask = 0x2C;
29constexpr uint8_t kPcbSSubtypeMask = 0x3F;
33uint8_t
t1_lrc(
const uint8_t *buf,
size_t len) {
35 for (
size_t i = 0; i < len; ++i) {
41uint16_t
t1_crc(
const uint8_t *buf,
size_t len) {
44 uint16_t crc = 0xFFFF;
45 for (
size_t i = 0; i < len; ++i) {
46 crc ^=
static_cast<uint16_t
>(buf[i]) << 8;
47 for (
int bit = 0; bit < 8; ++bit) {
49 crc =
static_cast<uint16_t
>((crc << 1) ^ 0x1021);
51 crc =
static_cast<uint16_t
>(crc << 1);
59 bool use_crc,
size_t out_cap,
size_t *out_len) {
60 const size_t edc_len = use_crc ? 2 : 1;
61 if (prologue_and_inf_len + edc_len > out_cap) {
65 uint16_t crc =
t1_crc(out, prologue_and_inf_len);
66 out[prologue_and_inf_len] =
static_cast<uint8_t
>((crc >> 8) & 0xFF);
67 out[prologue_and_inf_len + 1] =
static_cast<uint8_t
>(crc & 0xFF);
69 out[prologue_and_inf_len] =
t1_lrc(out, prologue_and_inf_len);
71 *out_len = prologue_and_inf_len + edc_len;
76 const uint8_t *inf, uint8_t inf_len,
78 uint8_t *out,
size_t out_cap,
size_t *out_len) {
84 const size_t prologue = 3;
85 if (prologue + inf_len > out_cap) {
89 uint8_t pcb = kPcbIBlock;
90 if (ns) pcb |= kPcbINs;
91 if (more) pcb |= kPcbIMore;
97 memcpy(out + prologue, inf, inf_len);
100 return append_edc(out, prologue + inf_len, use_crc, out_cap, out_len);
105 uint8_t *out,
size_t out_cap,
size_t *out_len) {
108 if (
static_cast<uint8_t
>(err) > 0x02)
return T1_ERR_PCB;
112 uint8_t pcb = kPcbRBlock;
113 if (nr) pcb |= kPcbRNr;
114 pcb |=
static_cast<uint8_t
>(err);
120 return append_edc(out, 3, use_crc, out_cap, out_len);
124 const uint8_t *inf, uint8_t inf_len,
126 uint8_t *out,
size_t out_cap,
size_t *out_len) {
130 if (
static_cast<uint8_t
>(subtype) & ~kPcbSSubtypeMask)
return T1_ERR_PCB;
132 const size_t prologue = 3;
133 if (prologue + inf_len > out_cap) {
138 out[1] =
static_cast<uint8_t
>(kPcbSBlock |
static_cast<uint8_t
>(subtype));
141 memcpy(out + prologue, inf, inf_len);
144 return append_edc(out, prologue + inf_len, use_crc, out_cap, out_len);
153 const uint8_t len_byte = buf[2];
156 const size_t edc_len = use_crc ? 2 : 1;
157 const size_t expected_total =
static_cast<size_t>(3) + len_byte + edc_len;
158 if (buf_len < expected_total)
return T1_ERR_LEN;
162 uint16_t expected =
t1_crc(buf, 3 + len_byte);
163 uint16_t got =
static_cast<uint16_t
>((buf[3 + len_byte] << 8) | buf[3 + len_byte + 1]);
164 out->
edc_ok = (expected == got);
166 uint8_t expected =
t1_lrc(buf, 3 + len_byte);
167 out->
edc_ok = (expected == buf[3 + len_byte]);
174 out->
inf = (len_byte > 0) ? buf + 3 :
nullptr;
176 const uint8_t pcb = out->
pcb;
177 const uint8_t kind_bits = pcb & kPcbBlockKindMask;
179 if ((pcb & 0x80) == 0) {
181 if (pcb & kPcbIReservedMask)
return T1_ERR_PCB;
183 out->
i_ns = (pcb & kPcbINs) ? 1 : 0;
184 out->
i_more = (pcb & kPcbIMore) != 0;
185 }
else if (kind_bits == kPcbRBlock) {
186 if (pcb & kPcbRReservedMask)
return T1_ERR_PCB;
189 out->
r_nr = (pcb & kPcbRNr) ? 1 : 0;
Decoded block. INF points into the buffer supplied to t1_block_decode.
static t1_status_t append_edc(uint8_t *out, size_t prologue_and_inf_len, bool use_crc, size_t out_cap, size_t *out_len)
t1_status_t t1_block_encode_r(uint8_t nad, uint8_t nr, t1_r_error_t err, bool use_crc, uint8_t *out, size_t out_cap, size_t *out_len)
Encode an R-block.
t1_status_t t1_block_encode_s(uint8_t nad, t1_s_subtype_t subtype, const uint8_t *inf, uint8_t inf_len, bool use_crc, uint8_t *out, size_t out_cap, size_t *out_len)
Encode an S-block.
uint16_t t1_crc(const uint8_t *buf, size_t len)
Compute the ISO/IEC 13239 CRC-16 of a buffer (polynomial 0x1021, initial value 0xFFFF,...
uint8_t t1_lrc(const uint8_t *buf, size_t len)
Compute the longitudinal redundancy check (LRC) of a buffer.
t1_status_t t1_block_encode_i(uint8_t nad, uint8_t ns, bool more, const uint8_t *inf, uint8_t inf_len, bool use_crc, uint8_t *out, size_t out_cap, size_t *out_len)
Encode an I-block.
t1_status_t t1_block_decode(const uint8_t *buf, size_t buf_len, bool use_crc, t1_block_t *out)
Decode a T=1 block.
#define T1_LEN_RESERVED
Reserved LEN value; must not appear on the wire.
#define T1_INF_MAX
ISO 7816-3 T=1 block-format encoder / decoder.
t1_s_subtype_t
S-block subtype (PCB bits 5-0).
t1_r_error_t
R-block error indicator (PCB bits 1-0).
t1_status_t
Result of t1_block_decode / t1_block_encode.