C library that generates TOTP and HOTP according to RFC-6238.
- GCC or Clang and CMake
- One crypto backend:
- libgcrypt ≥ 1.8.0
- OpenSSL ≥ 3.0.0
- MbedTLS 2.x or 3.x
git clone https://github.com/paolostivanin/libcotp.git
cd libcotp
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr ..
make
sudo make install| Option | Default | Description |
|---|---|---|
-DBUILD_TESTS=ON |
OFF | Build tests |
-DBUILD_SHARED_LIBS=OFF |
ON | Build static instead of shared |
| `-DHMAC_WRAPPER=<gcrypt | openssl | mbedtls>` |
-DCOTP_ENABLE_VALIDATION=ON |
OFF | Enable validation helper APIs |
char *get_totp(const char *base32_secret,
int digits,
int period,
int algo,
cotp_error_t *err);
char *get_steam_totp(const char *base32_secret,
int period,
cotp_error_t *err);
char *get_hotp(const char *base32_secret,
long counter,
int digits,
int algo,
cotp_error_t *err);
char *get_totp_at(const char *base32_secret,
long timestamp,
int digits,
int period,
int algo,
cotp_error_t *err);
int64_t otp_to_int(const char *otp,
cotp_error_t *err);base32_secret: Base32 encoded (may contain spaces).NULLis invalid.digits: 4–10 inclusiveperiod: 1–120 seconds inclusivealgo:SHA1,SHA256,SHA512counter: non-negativetimestamp: UNIX epoch seconds
Secrets are normalized (spaces removed, lowercase → uppercase).
- On success, OTP functions return
char *. Caller mustfree(). - On error, they return
NULLand seterrif non-NULL. - If
err == NULL, functions still behave correctly using an internal error variable. otp_to_int()never allocates:- returns
-1on invalid input - returns integer on success
- strips leading zeroes and sets
MISSING_LEADING_ZEROwhen applicable
- returns
Example:
cotp_error_t err;
char *code = get_totp("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ", 6, 30, SHA1, &err);
if (!code) {
// handle error
}
free(code);| Error | Meaning |
|---|---|
NO_ERROR |
Success |
VALID |
Validation helper matched |
WHMAC_ERROR |
Backend crypto error |
INVALID_B32_INPUT |
Secret not valid Base32 |
INVALID_ALGO |
Unsupported algorithm |
INVALID_PERIOD |
Period not in allowed range |
INVALID_DIGITS |
Digits not in allowed range |
INVALID_COUNTER |
counter < 0 |
INVALID_USER_INPUT |
NULL or malformed user input |
MISSING_LEADING_ZERO |
Leading zeroes stripped |
MEMORY_ALLOCATION_ERROR |
Allocation failure |
EMPTY_STRING |
Input was empty |
Return rules:
get_totp,get_totp_at,get_steam_totp,get_hotp→NULLon failureotp_to_int→-1on failure
Enabled with -DCOTP_ENABLE_VALIDATION=ON:
int validate_totp_in_window(const char *user_code,
const char *base32_secret,
long timestamp,
int digits,
int period,
int sha_algo,
int window,
int *matched_delta,
cotp_error_t *err);Returns:
1on match within[-window, +window]periods (setsVALID)0otherwise
cotp_ctx *cotp_ctx_create(int digits, int period, int sha_algo);
char *cotp_ctx_totp_at(cotp_ctx *ctx, const char *base32_secret, long timestamp, cotp_error_t *err);
char *cotp_ctx_totp(cotp_ctx *ctx, const char *base32_secret, cotp_error_t *err);
void cotp_ctx_free(cotp_ctx *ctx);char *base32_encode(const unsigned char *data,
size_t len,
cotp_error_t *err);
unsigned char *base32_decode(const char *user_data,
size_t data_len,
cotp_error_t *err);
bool is_string_valid_b32(const char *user_data);Behavior:
NULLon error (setserr)- empty input → empty output +
EMPTY_STRING - spaces allowed
- invalid base32 →
INVALID_B32_INPUT
- TOTP requires correct system time (use NTP)
- Validation should allow small window (±1–2 periods)
- Secrets should be handled securely