Coverage Report

Created: 2025-10-10 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-crc.c
Line
Count
Source
1
/*
2
 * Copyright 2017 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
0
#define G_LOG_DOMAIN "FuCommon"
8
9
#include "config.h"
10
11
#include "fu-common.h"
12
#include "fu-crc-private.h"
13
#include "fu-mem.h"
14
15
const struct {
16
  FuCrcKind kind;
17
  guint bitwidth;
18
  guint32 poly;
19
  guint32 init;
20
  gboolean reflected;
21
  guint32 xorout;
22
} crc_map[] = {
23
    {FU_CRC_KIND_UNKNOWN, 32, 0x00000000, 0x00000000, TRUE, 0xFFFFFFFF},
24
    {FU_CRC_KIND_B32_STANDARD, 32, 0x04C11DB7, 0xFFFFFFFF, TRUE, 0xFFFFFFFF},
25
    {FU_CRC_KIND_B32_BZIP2, 32, 0x04C11DB7, 0xFFFFFFFF, FALSE, 0xFFFFFFFF},
26
    {FU_CRC_KIND_B32_JAMCRC, 32, 0x04C11DB7, 0xFFFFFFFF, TRUE, 0x00000000},
27
    {FU_CRC_KIND_B32_MPEG2, 32, 0x04C11DB7, 0xFFFFFFFF, FALSE, 0x00000000},
28
    {FU_CRC_KIND_B32_POSIX, 32, 0x04C11DB7, 0x00000000, FALSE, 0xFFFFFFFF},
29
    {FU_CRC_KIND_B32_SATA, 32, 0x04C11DB7, 0x52325032, FALSE, 0x00000000},
30
    {FU_CRC_KIND_B32_XFER, 32, 0x000000AF, 0x00000000, FALSE, 0x00000000},
31
    {FU_CRC_KIND_B32_C, 32, 0x1EDC6F41, 0xFFFFFFFF, TRUE, 0xFFFFFFFF},
32
    {FU_CRC_KIND_B32_D, 32, 0xA833982B, 0xFFFFFFFF, TRUE, 0xFFFFFFFF},
33
    {FU_CRC_KIND_B32_Q, 32, 0x814141AB, 0x00000000, FALSE, 0x00000000},
34
    {FU_CRC_KIND_B16_XMODEM, 16, 0x1021, 0x0000, FALSE, 0x0000},
35
    {FU_CRC_KIND_B16_KERMIT, 16, 0x1021, 0x0000, TRUE, 0x0000},
36
    {FU_CRC_KIND_B16_USB, 16, 0x8005, 0xFFFF, TRUE, 0xFFFF},
37
    {FU_CRC_KIND_B16_UMTS, 16, 0x8005, 0x0000, FALSE, 0x0000},
38
    {FU_CRC_KIND_B16_TMS37157, 16, 0x1021, 0x89ec, TRUE, 0x0000},
39
    {FU_CRC_KIND_B16_BNR, 16, 0x8005, 0xFFFF, FALSE, 0x0000},
40
    {FU_CRC_KIND_B8_WCDMA, 8, 0x9B, 0x00, TRUE, 0x00},
41
    {FU_CRC_KIND_B8_TECH_3250, 8, 0x1D, 0xFF, TRUE, 0x00},
42
    {FU_CRC_KIND_B8_STANDARD, 8, 0x07, 0x00, FALSE, 0x00},
43
    {FU_CRC_KIND_B8_SAE_J1850, 8, 0x1D, 0xFF, FALSE, 0xFF},
44
    {FU_CRC_KIND_B8_ROHC, 8, 0x07, 0xFF, TRUE, 0x00},
45
    {FU_CRC_KIND_B8_OPENSAFETY, 8, 0x2F, 0x00, FALSE, 0x00},
46
    {FU_CRC_KIND_B8_NRSC_5, 8, 0x31, 0xFF, FALSE, 0x00},
47
    {FU_CRC_KIND_B8_MIFARE_MAD, 8, 0x1D, 0xC7, FALSE, 0x00},
48
    {FU_CRC_KIND_B8_MAXIM_DOW, 8, 0x31, 0x00, TRUE, 0x00},
49
    {FU_CRC_KIND_B8_LTE, 8, 0x9B, 0x00, FALSE, 0x00},
50
    {FU_CRC_KIND_B8_I_CODE, 8, 0x1D, 0xFD, FALSE, 0x00},
51
    {FU_CRC_KIND_B8_ITU, 8, 0x07, 0x00, FALSE, 0x55},
52
    {FU_CRC_KIND_B8_HITAG, 8, 0x1D, 0xFF, FALSE, 0x00},
53
    {FU_CRC_KIND_B8_GSM_B, 8, 0x49, 0x00, FALSE, 0xFF},
54
    {FU_CRC_KIND_B8_GSM_A, 8, 0x1D, 0x00, FALSE, 0x00},
55
    {FU_CRC_KIND_B8_DVB_S2, 8, 0xD5, 0x00, FALSE, 0x00},
56
    {FU_CRC_KIND_B8_DARC, 8, 0x39, 0x00, TRUE, 0x00},
57
    {FU_CRC_KIND_B8_CDMA2000, 8, 0x9B, 0xFF, FALSE, 0x00},
58
    {FU_CRC_KIND_B8_BLUETOOTH, 8, 0xA7, 0x00, TRUE, 0x00},
59
    {FU_CRC_KIND_B8_AUTOSAR, 8, 0x2F, 0xFF, FALSE, 0xFF},
60
};
61
62
static guint8
63
fu_crc_reflect8(guint8 data)
64
105M
{
65
105M
  guint8 val = 0;
66
950M
  for (guint8 bit = 0; bit < 8; bit++) {
67
844M
    if (data & 0x01)
68
283M
      FU_BIT_SET(val, 7 - bit);
69
844M
    data = (data >> 1);
70
844M
  }
71
105M
  return val;
72
105M
}
73
74
static guint32
75
fu_crc_reflect(guint32 data, guint bitwidth)
76
4.82k
{
77
4.82k
  guint32 val = 0;
78
159k
  for (guint bit = 0; bit < bitwidth; bit++) {
79
154k
    if (data & 0x01)
80
78.8k
      val |= 1ul << ((bitwidth - 1) - bit);
81
154k
    data = (data >> 1);
82
154k
  }
83
4.82k
  return val;
84
4.82k
}
85
86
/**
87
 * fu_crc8_step:
88
 * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B8_MAXIM_DOW
89
 * @buf: memory buffer
90
 * @bufsz: size of @buf
91
 * @crc: initial CRC value
92
 *
93
 * Computes the cyclic redundancy check section value for the given memory buffer.
94
 *
95
 * NOTE: When all data has been added, you should call fu_crc8_done() to return the final value.
96
 *
97
 * Returns: CRC value
98
 *
99
 * Since: 2.0.0
100
 **/
101
guint8
102
fu_crc8_step(FuCrcKind kind, const guint8 *buf, gsize bufsz, guint8 crc)
103
0
{
104
0
  const guint bitwidth = sizeof(crc) * 8;
105
106
0
  g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0);
107
0
  g_return_val_if_fail(crc_map[kind].bitwidth == 8, 0x0);
108
109
0
  for (gsize i = 0; i < bufsz; ++i) {
110
0
    crc ^= crc_map[kind].reflected ? fu_crc_reflect8(buf[i]) : buf[i];
111
0
    for (guint8 bit = 0; bit < 8; bit++) {
112
0
      if (crc & (1ul << (bitwidth - 1))) {
113
0
        crc = (crc << 1) ^ crc_map[kind].poly;
114
0
      } else {
115
0
        crc = (crc << 1);
116
0
      }
117
0
    }
118
0
  }
119
0
  return crc;
120
0
}
121
122
/**
123
 * fu_crc8_done:
124
 * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B8_MAXIM_DOW
125
 * @crc: initial CRC value
126
 *
127
 * Returns the finished cyclic redundancy check value.
128
 *
129
 * Returns: CRC value
130
 *
131
 * Since: 2.0.0
132
 **/
133
guint8
134
fu_crc8_done(FuCrcKind kind, guint8 crc)
135
0
{
136
0
  g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0);
137
0
  g_return_val_if_fail(crc_map[kind].bitwidth == 8, 0x0);
138
0
  crc = crc_map[kind].reflected ? fu_crc_reflect(crc, crc_map[kind].bitwidth) : crc;
139
0
  return crc ^ crc_map[kind].xorout;
140
0
}
141
142
/**
143
 * fu_crc8:
144
 * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B8_MAXIM_DOW
145
 * @buf: memory buffer
146
 * @bufsz: size of @buf
147
 *
148
 * Returns the cyclic redundancy check value for the given memory buffer.
149
 *
150
 * Returns: CRC value
151
 *
152
 * Since: 2.0.0
153
 **/
154
guint8
155
fu_crc8(FuCrcKind kind, const guint8 *buf, gsize bufsz)
156
0
{
157
0
  g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0);
158
0
  g_return_val_if_fail(crc_map[kind].bitwidth == 8, 0x0);
159
0
  return fu_crc8_done(kind, fu_crc8_step(kind, buf, bufsz, crc_map[kind].init));
160
0
}
161
162
/**
163
 * fu_crc8_bytes:
164
 * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B8_MAXIM_DOW
165
 * @blob: a #GBytes
166
 *
167
 * Returns the cyclic redundancy check value for the given memory buffer.
168
 *
169
 * Returns: CRC value
170
 *
171
 * Since: 2.0.2
172
 **/
173
guint8
174
fu_crc8_bytes(FuCrcKind kind, GBytes *blob)
175
0
{
176
0
  g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0);
177
0
  g_return_val_if_fail(blob != NULL, 0x0);
178
0
  return fu_crc8(kind, g_bytes_get_data(blob, NULL), g_bytes_get_size(blob));
179
0
}
180
181
/**
182
 * fu_crc16_step:
183
 * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B16_XMODEM
184
 * @buf: memory buffer
185
 * @bufsz: size of @buf
186
 * @crc: initial CRC value
187
 *
188
 * Computes the cyclic redundancy check section value for the given memory buffer.
189
 *
190
 * NOTE: When all data has been added, you should call fu_crc16_done() to return the final value.
191
 *
192
 * Returns: CRC value
193
 *
194
 * Since: 2.0.0
195
 **/
196
guint16
197
fu_crc16_step(FuCrcKind kind, const guint8 *buf, gsize bufsz, guint16 crc)
198
0
{
199
0
  const guint bitwidth = sizeof(crc) * 8;
200
201
0
  g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0);
202
0
  g_return_val_if_fail(crc_map[kind].bitwidth == 16, 0x0);
203
204
0
  for (gsize i = 0; i < bufsz; ++i) {
205
0
    guint16 tmp = crc_map[kind].reflected ? fu_crc_reflect8(buf[i]) : buf[i];
206
0
    crc ^= tmp << (bitwidth - 8);
207
0
    for (guint8 bit = 0; bit < 8; bit++) {
208
0
      if (crc & (1ul << (bitwidth - 1))) {
209
0
        crc = (crc << 1) ^ crc_map[kind].poly;
210
0
      } else {
211
0
        crc = (crc << 1);
212
0
      }
213
0
    }
214
0
  }
215
0
  return crc;
216
0
}
217
218
/**
219
 * fu_crc16_done:
220
 * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B16_XMODEM
221
 * @crc: initial CRC value
222
 *
223
 * Returns the finished cyclic redundancy check value.
224
 *
225
 * Returns: CRC value
226
 *
227
 * Since: 2.0.0
228
 **/
229
guint16
230
fu_crc16_done(FuCrcKind kind, guint16 crc)
231
0
{
232
0
  g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0);
233
0
  g_return_val_if_fail(crc_map[kind].bitwidth == 16, 0x0);
234
0
  crc = crc_map[kind].reflected ? fu_crc_reflect(crc, crc_map[kind].bitwidth) : crc;
235
0
  return crc ^ crc_map[kind].xorout;
236
0
}
237
238
/**
239
 * fu_crc16:
240
 * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B16_XMODEM
241
 * @buf: memory buffer
242
 * @bufsz: size of @buf
243
 *
244
 * Returns the cyclic redundancy check value for the given memory buffer.
245
 *
246
 * Returns: CRC value
247
 *
248
 * Since: 2.0.0
249
 **/
250
guint16
251
fu_crc16(FuCrcKind kind, const guint8 *buf, gsize bufsz)
252
0
{
253
0
  g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0);
254
0
  g_return_val_if_fail(crc_map[kind].bitwidth == 16, 0x0);
255
0
  return fu_crc16_done(kind, fu_crc16_step(kind, buf, bufsz, crc_map[kind].init));
256
0
}
257
258
/**
259
 * fu_crc16_bytes:
260
 * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B16_XMODEM
261
 * @blob: a #GBytes
262
 *
263
 * Returns the cyclic redundancy check value for the given memory buffer.
264
 *
265
 * Returns: CRC value
266
 *
267
 * Since: 2.0.2
268
 **/
269
guint16
270
fu_crc16_bytes(FuCrcKind kind, GBytes *blob)
271
0
{
272
0
  g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0);
273
0
  g_return_val_if_fail(blob != NULL, 0x0);
274
0
  return fu_crc16(kind, g_bytes_get_data(blob, NULL), g_bytes_get_size(blob));
275
0
}
276
277
/**
278
 * fu_crc32_step:
279
 * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B32_STANDARD
280
 * @buf: memory buffer
281
 * @bufsz: size of @buf
282
 * @crc: initial CRC value
283
 *
284
 * Computes the cyclic redundancy check section value for the given memory buffer.
285
 *
286
 * NOTE: When all data has been added, you should call fu_crc32_done() to return the final value.
287
 *
288
 * Returns: CRC value
289
 *
290
 * Since: 2.0.0
291
 **/
292
guint32
293
fu_crc32_step(FuCrcKind kind, const guint8 *buf, gsize bufsz, guint32 crc)
294
5.13k
{
295
5.13k
  const guint bitwidth = sizeof(crc) * 8;
296
297
5.13k
  g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0);
298
5.13k
  g_return_val_if_fail(crc_map[kind].bitwidth == 32, 0x0);
299
300
105M
  for (gsize i = 0; i < bufsz; ++i) {
301
105M
    guint32 tmp = crc_map[kind].reflected ? fu_crc_reflect8(buf[i]) : buf[i];
302
105M
    crc ^= tmp << (bitwidth - 8);
303
950M
    for (guint8 bit = 0; bit < 8; bit++) {
304
844M
      if (crc & (1ul << (bitwidth - 1))) {
305
405M
        crc = (crc << 1) ^ crc_map[kind].poly;
306
438M
      } else {
307
438M
        crc = (crc << 1);
308
438M
      }
309
844M
    }
310
105M
  }
311
5.13k
  return crc;
312
5.13k
}
313
314
/**
315
 * fu_crc32_done:
316
 * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B32_STANDARD
317
 * @crc: initial CRC value
318
 *
319
 * Returns the finished cyclic redundancy check value.
320
 *
321
 * Returns: CRC value
322
 *
323
 * Since: 2.0.0
324
 **/
325
guint32
326
fu_crc32_done(FuCrcKind kind, guint32 crc)
327
4.82k
{
328
4.82k
  g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0);
329
4.82k
  g_return_val_if_fail(crc_map[kind].bitwidth == 32, 0x0);
330
4.82k
  crc = crc_map[kind].reflected ? fu_crc_reflect(crc, crc_map[kind].bitwidth) : crc;
331
4.82k
  return crc ^ crc_map[kind].xorout;
332
4.82k
}
333
334
/**
335
 * fu_crc32:
336
 * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B32_STANDARD
337
 * @buf: memory buffer
338
 * @bufsz: size of @buf
339
 *
340
 * Returns the cyclic redundancy check value for the given memory buffer.
341
 *
342
 * Returns: CRC value
343
 *
344
 * Since: 2.0.0
345
 **/
346
guint32
347
fu_crc32(FuCrcKind kind, const guint8 *buf, gsize bufsz)
348
1.99k
{
349
1.99k
  g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0);
350
1.99k
  g_return_val_if_fail(crc_map[kind].bitwidth == 32, 0x0);
351
1.99k
  return fu_crc32_done(kind, fu_crc32_step(kind, buf, bufsz, crc_map[kind].init));
352
1.99k
}
353
354
/**
355
 * fu_crc32_bytes:
356
 * @kind: a #FuCrcKind, typically %FU_CRC_KIND_B32_STANDARD
357
 * @blob: a #GBytes
358
 *
359
 * Returns the cyclic redundancy check value for the given memory buffer.
360
 *
361
 * Returns: CRC value
362
 *
363
 * Since: 2.0.2
364
 **/
365
guint32
366
fu_crc32_bytes(FuCrcKind kind, GBytes *blob)
367
696
{
368
696
  g_return_val_if_fail(kind < FU_CRC_KIND_LAST, 0x0);
369
696
  g_return_val_if_fail(blob != NULL, 0x0);
370
696
  return fu_crc32(kind, g_bytes_get_data(blob, NULL), g_bytes_get_size(blob));
371
696
}
372
373
/**
374
 * fu_crc_find:
375
 * @buf: memory buffer
376
 * @bufsz: size of @buf
377
 * @crc_target: "correct" CRC value
378
 *
379
 * Returns the cyclic redundancy kind for the given memory buffer and target CRC.
380
 *
381
 * You can use a very simple buffer to discover most types of standard CRC-32:
382
 *
383
 *    guint8 buf[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
384
 *    g_info("CRC:%u", fu_crc_find(buf, sizeof(buf), _custom_crc(buf, sizeof(buf))));
385
 *
386
 * Returns: a #FuCrcKind, or %FU_CRC_KIND_UNKNOWN on error
387
 *
388
 * Since: 2.0.0
389
 **/
390
FuCrcKind
391
fu_crc_find(const guint8 *buf, gsize bufsz, guint32 crc_target)
392
0
{
393
0
  for (guint i = 0; i < G_N_ELEMENTS(crc_map); i++) {
394
0
    if (crc_map[i].bitwidth == 32) {
395
0
      if (crc_target == fu_crc32(crc_map[i].kind, buf, bufsz))
396
0
        return crc_map[i].kind;
397
0
    }
398
0
    if (crc_map[i].bitwidth == 16) {
399
0
      if ((guint16)crc_target == fu_crc16(crc_map[i].kind, buf, bufsz))
400
0
        return crc_map[i].kind;
401
0
    }
402
0
    if (crc_map[i].bitwidth == 8) {
403
0
      if ((guint8)crc_target == fu_crc8(crc_map[i].kind, buf, bufsz))
404
0
        return crc_map[i].kind;
405
0
    }
406
0
  }
407
0
  return FU_CRC_KIND_UNKNOWN;
408
0
}
409
410
static guint16
411
fu_crc_misr16_step(guint16 cur, guint16 new)
412
0
{
413
0
  guint16 bit0;
414
0
  guint16 res;
415
416
0
  bit0 = cur ^ (new & 1);
417
0
  bit0 ^= cur >> 1;
418
0
  bit0 ^= cur >> 2;
419
0
  bit0 ^= cur >> 4;
420
0
  bit0 ^= cur >> 5;
421
0
  bit0 ^= cur >> 7;
422
0
  bit0 ^= cur >> 11;
423
0
  bit0 ^= cur >> 15;
424
0
  res = (cur << 1) ^ new;
425
0
  res = (res & ~1) | (bit0 & 1);
426
0
  return res;
427
0
}
428
429
/**
430
 * fu_crc_misr16:
431
 * @buf: memory buffer
432
 * @bufsz: size of @buf
433
 * @init: initial value, typically 0x0
434
 *
435
 * Returns the MISR check value for the given memory buffer.
436
 *
437
 * Returns: value
438
 *
439
 * Since: 1.9.17
440
 **/
441
guint16
442
fu_crc_misr16(guint16 init, const guint8 *buf, gsize bufsz)
443
0
{
444
0
  g_return_val_if_fail(buf != NULL, G_MAXUINT16);
445
0
  g_return_val_if_fail(bufsz % 2 == 0, G_MAXUINT16);
446
447
0
  for (gsize i = 0; i < bufsz; i += 2)
448
0
    init = fu_crc_misr16_step(init, fu_memread_uint16(buf + i, G_LITTLE_ENDIAN));
449
0
  return init;
450
0
}