Coverage Report

Created: 2026-01-17 07:04

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