/* ============================================================================= * sig.c - raw-body 서명 구현 (HMAC-SHA256) * * 서버 규약(php/config.php:verify_signature_raw): * X-Signature = lowercase_hex( HMAC-SHA256( key=API_KEY, msg=raw_body_bytes ) ) * * HMAC(키 접두 SHA256 이 아님)을 쓰는 이유: 길이확장(length-extension) 공격에 * 견디고, 서버 hash_hmac('sha256', body, API_KEY) 와 바이트 단위로 일치한다. * reference.py:sign_raw() (hmac.new) 와도 동일하다. * ===========================================================================*/ #include "sig.h" #include "sha256_backend.h" #include "hexutil.h" #include /* SHA-256 블록 크기(HMAC 키 패딩 단위). */ #define SIG_HMAC_BLOCK 64u void sig_raw_body(const char *key, const char *body, size_t body_len, char out_hex[SIG_HEX_BUFSZ]) { uint8_t k0[SIG_HMAC_BLOCK]; /* 블록 크기로 정규화한 키 K' */ uint8_t ipad[SIG_HMAC_BLOCK]; uint8_t opad[SIG_HMAC_BLOCK]; uint8_t inner[SHA256_DIGEST_LEN]; uint8_t digest[SHA256_DIGEST_LEN]; sha256_ctx ctx; size_t key_len = strlen(key); /* K' = 키를 블록 크기로 맞춘 값. 64바이트 초과면 SHA256 으로 줄이고 0 패딩. */ memset(k0, 0, sizeof(k0)); if (key_len > SIG_HMAC_BLOCK) { sha256((const uint8_t *)key, key_len, k0); /* 앞 32바이트, 나머지는 0 유지 */ } else { memcpy(k0, key, key_len); } for (size_t i = 0; i < SIG_HMAC_BLOCK; i++) { ipad[i] = (uint8_t)(k0[i] ^ 0x36u); opad[i] = (uint8_t)(k0[i] ^ 0x5cu); } /* inner = SHA256(ipad || body) */ sha256_init(&ctx); sha256_update(&ctx, ipad, SIG_HMAC_BLOCK); sha256_update(&ctx, (const uint8_t *)body, body_len); sha256_final(&ctx, inner); /* digest = SHA256(opad || inner) */ sha256_init(&ctx); sha256_update(&ctx, opad, SIG_HMAC_BLOCK); sha256_update(&ctx, inner, SHA256_DIGEST_LEN); sha256_final(&ctx, digest); hex_encode_lower(digest, SHA256_DIGEST_LEN, out_hex); }