30 uint8_t secret[32] = {};
31 size_t secret_len = 0;
39bool ct_equal(
const char *a,
const char *b,
size_t n)
42 for (
size_t i = 0; i < n; i++)
44 diff |= (uint8_t)(a[i] ^ b[i]);
50void sign_nonce(
const CsrfCtx &c,
const uint8_t *nonce,
size_t nlen,
char *sig_hex)
59void pc_csrf_set_secret(
const uint8_t *secret,
size_t len)
63 s_csrf.secret_len = 0;
66 s_csrf.secret_len = len >
sizeof(s_csrf.secret) ?
sizeof(s_csrf.secret) : len;
67 memcpy(s_csrf.secret, secret, s_csrf.secret_len);
70int pc_csrf_issue(
char *out,
size_t cap)
72 if (s_csrf.secret_len == 0 || !out || cap < CSRF_TOKEN_BUF)
77 uint8_t nonce[CSRF_NONCE_BYTES];
78 uint64_t c = ++s_csrf.counter;
79 for (
size_t i = 0; i < CSRF_NONCE_BYTES; i++)
81 nonce[i] = (uint8_t)(c >> (8 * i));
84 char nhex[CSRF_NONCE_BYTES * 2 + 1];
85 char shex[CSRF_SIG_BYTES * 2 + 1];
87 sign_nonce(s_csrf, nonce, CSRF_NONCE_BYTES, shex);
89 pc_sb sb_out = {out, cap, 0,
true};
99 return (n > 0 && (
size_t)n < cap) ? n : 0;
102bool pc_csrf_verify(
const char *token)
104 if (s_csrf.secret_len == 0 || !token)
109 const char *dot = strchr(token,
'.');
115 size_t nhexlen = (size_t)(dot - token);
116 if (nhexlen != CSRF_NONCE_BYTES * 2)
121 uint8_t nonce[CSRF_NONCE_BYTES];
122 if (
pc_hex_decode(token, nhexlen, nonce,
sizeof(nonce)) != CSRF_NONCE_BYTES)
127 const char *sig = dot + 1;
128 if (strnlen(sig, CSRF_SIG_BYTES * 2 + 1) != CSRF_SIG_BYTES * 2)
133 char expect[CSRF_SIG_BYTES * 2 + 1];
134 sign_nonce(s_csrf, nonce, CSRF_NONCE_BYTES, expect);
135 return ct_equal(sig, expect, CSRF_SIG_BYTES * 2);
138void pc_csrf_reset(
void)
140 memset(s_csrf.secret, 0,
sizeof(s_csrf.secret));
141 s_csrf.secret_len = 0;
Stateless HMAC-signed CSRF token (PC_ENABLE_CSRF).
Base-16 conversion between raw bytes and their ASCII digits.
void pc_hex_encode(const uint8_t *in, uint32_t n, char *out, bool upper=false)
Write n bytes of in into out as 2 * n hex characters plus a NUL.
int32_t pc_hex_decode(const char *in, uint32_t hexlen, uint8_t *out, uint32_t out_cap)
Read exactly hexlen hex characters from in into out as hexlen / 2 bytes.
void pc_hmac_sha256(const uint8_t *key, size_t key_len, const uint8_t *data, size_t len, uint8_t mac[PC_HMAC_SHA256_LEN])
Compute HMAC-SHA2-256 over a single contiguous buffer.
HMAC-SHA2-256 (RFC 2104 + FIPS 198-1) - streaming context and one-shot API.
#define PC_HMAC_SHA256_LEN
HMAC-SHA2-256 output length in bytes.
Bounded no-heap string builder that fails closed on overflow (one shared copy).
size_t pc_sb_finish(pc_sb *b)
NUL-terminate and return the built length, or 0 if the build overflowed.
void pc_sb_put(pc_sb *b, const char *s)
Append NUL-terminated s; leaves the buffer untouched and clears ok if it would not fit.
Bump-append target; ok latches false once an append would overflow cap.