diff --git a/include/zephyr/sys/crc.h b/include/zephyr/sys/crc.h index e29fce45d9e..c16281b10fd 100644 --- a/include/zephyr/sys/crc.h +++ b/include/zephyr/sys/crc.h @@ -30,6 +30,14 @@ extern "C" { */ #define CRC8_CCITT_INITIAL_VALUE 0xFF +/* Initial value expected to be used at the beginning of the OpenPGP CRC-24 computation. */ +#define CRC24_PGP_INITIAL_VALUE 0x00B704CEU +/* + * The CRC-24 value is stored on a 32-bit value, only the 3 least significant bytes + * are meaningful. Use the following mask to only keep the CRC-24 value. + */ +#define CRC24_FINAL_VALUE_MASK 0x00FFFFFFU + /** * @defgroup checksum Checksum * @ingroup os_services @@ -56,6 +64,7 @@ enum crc_type { CRC16_ANSI, /**< Use @ref crc16_ansi */ CRC16_CCITT, /**< Use @ref crc16_ccitt */ CRC16_ITU_T, /**< Use @ref crc16_itu_t */ + CRC24_PGP, /**< Use @ref crc24_pgp */ CRC32_C, /**< Use @ref crc32_c */ CRC32_IEEE, /**< Use @ref crc32_ieee */ }; @@ -315,16 +324,39 @@ uint8_t crc4_ti(uint8_t seed, const uint8_t *src, size_t len); uint8_t crc4(const uint8_t *src, size_t len, uint8_t polynomial, uint8_t initial_value, bool reversed); +/** + * @brief Generate an OpenPGP CRC-24 checksum as defined in RFC 4880 section 6.1. + * + * @param data A pointer to the data on which the CRC will be calculated. + * @param len Data length in bytes. + * + * @return The CRC-24 value. + */ +uint32_t crc24_pgp(const uint8_t *data, size_t len); + +/** + * @brief Update an OpenPGP CRC-24 checksum. + * + * @param crc The CRC-24 checksum that needs to be updated. The full 32-bit value of the CRC needs + * to be used between calls, do not mask the value to keep only the last 24 bits. + * @param data A pointer to the data on which the CRC will be calculated. + * @param len Data length in bytes. + * + * @return The CRC-24 value. When the last buffer of data has been processed, mask the value + * with CRC24_FINAL_VALUE_MASK to keep only the meaningful 24 bits of the CRC result. + */ +uint32_t crc24_pgp_update(uint32_t crc, const uint8_t *data, size_t len); + /** * @brief Compute a CRC checksum, in a generic way. * * This is a dispatch function that calls the individual CRC routine * determined by @p type. * - * For 7, 8, and 16-bit CRCs, the relevant @p seed and @p poly values should + * For 7, 8, 16 and 24-bit CRCs, the relevant @p seed and @p poly values should * be passed in via the least-significant byte(s). * - * Similarly, for 7, 8, and 16-bit CRCs, the relevant result is stored in the + * Similarly, for 7, 8, 16 and 24-bit CRCs, the relevant result is stored in the * least-significant byte(s) of the returned value. * * @param type CRC algorithm to use. @@ -364,6 +396,13 @@ static inline uint32_t crc_by_type(enum crc_type type, const uint8_t *src, size_ return crc16_ccitt(seed, src, len); case CRC16_ITU_T: return crc16_itu_t(seed, src, len); + case CRC24_PGP: { + uint32_t crc = crc24_pgp_update(seed, src, len); + + if (last) + crc &= CRC24_FINAL_VALUE_MASK; + return crc; + } case CRC32_C: return crc32_c(seed, src, len, first, last); case CRC32_IEEE: diff --git a/lib/crc/CMakeLists.txt b/lib/crc/CMakeLists.txt index a85cc3b05cc..7285af4f3c2 100644 --- a/lib/crc/CMakeLists.txt +++ b/lib/crc/CMakeLists.txt @@ -3,6 +3,7 @@ zephyr_sources_ifdef(CONFIG_CRC crc32c_sw.c crc32_sw.c + crc24_sw.c crc16_sw.c crc8_sw.c crc7_sw.c diff --git a/lib/crc/crc24_sw.c b/lib/crc/crc24_sw.c new file mode 100644 index 00000000000..3e9b48fa014 --- /dev/null +++ b/lib/crc/crc24_sw.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 BayLibre. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#define CRC24_PGP_POLY 0x01864cfbU + +uint32_t crc24_pgp(const uint8_t *data, size_t len) +{ + return crc24_pgp_update(CRC24_PGP_INITIAL_VALUE, data, len) & CRC24_FINAL_VALUE_MASK; +} + +/* CRC-24 implementation from the section 6.1 of the RFC 4880 */ +uint32_t crc24_pgp_update(uint32_t crc, const uint8_t *data, size_t len) +{ + int i; + + while (len--) { + crc ^= (*data++) << 16; + for (i = 0; i < 8; i++) { + crc <<= 1; + if (crc & 0x01000000) + crc ^= CRC24_PGP_POLY; + } + } + + return crc; +} diff --git a/lib/crc/crc_shell.c b/lib/crc/crc_shell.c index 32393ff6f6e..e2647ee6623 100644 --- a/lib/crc/crc_shell.c +++ b/lib/crc/crc_shell.c @@ -28,6 +28,7 @@ static const char *const crc_types[] = { [CRC16_ANSI] = "16_ansi", [CRC16_CCITT] = "16_ccitt", [CRC16_ITU_T] = "16_itu_t", + [CRC24_PGP] = "24_pgp", [CRC32_C] = "32_c", [CRC32_IEEE] = "32_ieee", };