v4.1.0
Highlights
otpauth://URI parser and builder — full round-trip support for the de-facto Google Authenticator URI format used by most TOTP/HOTP apps and QR provisioning flows.- Context API — bundle
digits,period, andalgoonce withcotp_ctx_create, then callcotp_ctx_totp/_hotp/_steam_totpetc. without repeating the parameters. Contexts are immutable and safe to share across threads. cotp_strerror— static, never-NULL human-readable description for anycotp_error_tvalue.- Public secure utilities —
cotp_secure_memzero(compiler-elision-proof zeroing) andcotp_timing_safe_memcmp(constant-time compare) are now part of the public API, so callers can scrub their own secret buffers and compare secret-derived tokens with the same primitives the library uses internally.
New APIs
const char *cotp_strerror(cotp_error_t err);
void cotp_secure_memzero(void *ptr, size_t len);
int cotp_timing_safe_memcmp(const void *a, const void *b, size_t len);
cotp_ctx *cotp_ctx_create(int digits, int period, int sha_algo);
void cotp_ctx_free(cotp_ctx *ctx);
char *cotp_ctx_totp(cotp_ctx *ctx, const char *base32_secret, cotp_error_t *err);
char *cotp_ctx_totp_at(cotp_ctx *ctx, const char *base32_secret, long timestamp, cotp_error_t *err);
char *cotp_ctx_hotp(cotp_ctx *ctx, const char *base32_secret, long counter, cotp_error_t *err);
char *cotp_ctx_steam_totp(cotp_ctx *ctx, const char *base32_secret, cotp_error_t *err);
char *cotp_ctx_steam_totp_at(cotp_ctx *ctx, const char *base32_secret, long timestamp, cotp_error_t *err);
#ifdef COTP_ENABLE_VALIDATION
int cotp_ctx_validate_totp(cotp_ctx *ctx, const char *user_code, const char *base32_secret,
long timestamp, int window, int *matched_delta, cotp_error_t *err);
#endif
cotp_otpauth_uri *cotp_otpauth_uri_parse(const char *uri, cotp_error_t *err);
char *cotp_otpauth_uri_build(const cotp_otpauth_uri *u, cotp_error_t *err);
void cotp_otpauth_uri_free(cotp_otpauth_uri *u);Hardening
- HMAC errors are now propagated across all three backends (gcrypt, OpenSSL, MbedTLS). Previously some backend failure paths could silently produce invalid output.
- Base32 decoder rejects malformed padding counts (2, 5, 7, >6) and data characters following padding, per RFC 4648.
validate_totp_in_windowis overflow-safe: window is clamped to ±1024 periods, time arithmetic uses__builtin_*_overflow,INT_MINis handled, and the comparison is constant-time.otpauth://URI parser rejects%00payloads (which previously caused silent NUL truncation of secrets).COTP_WUR(warn-unused-result) annotation applied to every return-value-bearing public function.
Build / Test / CI
- libFuzzer harnesses for
base32_decode,get_totp_at, and theotpauth://parser. Opt in with-DCOTP_BUILD_FUZZERS=ON(requires Clang). - ASan + UBSan CI workflow runs the full test suite across all three backends on every push and PR.
- Fuzz-smoke CI workflow runs each fuzzer for 30 seconds on every push and PR.
- CMake asserts that
COTP_VERSION_STRINGand the project version stay in sync. - Cross-platform linker hardening flags via the CMake
LINKER:syntax (fixes macOS).
Compatibility
ABI-compatible with v4.0.x — SOVERSION stays at 4. New symbols are purely additive. You can drop the new .so in place of the old; recompilation is only needed if you want to use the new APIs.
Documentation
The README has been substantially expanded: Quick Index near the top; end-to-end examples for the Context, Validation, otpauth, and Base32 APIs; a Utilities section; an expanded Operational Notes section (system clock, HOTP counter persistence, Steam secret format, minimum secret length, thread safety, scrubbing); and explicit notes on Base32 lenient-mode behavior.
Full changelog
sha256: e51016eb220647e7f16b67c0baae2a42730b07fec3131aaad0f39a3a2a638b89