size_t li_to_base64(char* out, size_t out_length, const unsigned char* in, size_t in_length, base64_charset charset) { const size_t in_tuple_remainder = in_length % 3; size_t padding_length = in_tuple_remainder ? 3 - in_tuple_remainder : 0; char padding; size_t out_pos; switch (charset) { case BASE64_STANDARD: padding = base64_standard_table[64]; break; case BASE64_URL: padding = base64_url_table[64]; break; default: force_assert(0 && "invalid charset"); } force_assert(out_length >= padding_length); out_pos = li_to_base64_no_padding(out, out_length - padding_length, in, in_length, charset); while (padding_length > 0) { out[out_pos++] = padding; padding_length--; } force_assert(out_pos <= out_length); return out_pos; }
inline static void check_base64 (char *out, const size_t out_sz, const char *in, const size_t in_len, const base64_charset enc) { force_assert(out_sz == li_to_base64_no_padding(out, out_sz, (const unsigned char *)in, in_len, enc)); buffer_reset(check); force_assert(NULL != buffer_append_base64_decode(check, out, out_sz, enc)); force_assert(buffer_is_equal_string(check, in, in_len)); }
char* buffer_append_base64_encode_no_padding(buffer *out, const unsigned char* in, size_t in_length, base64_charset charset) { size_t reserve = 4*(in_length/3) + 4; char* result = buffer_string_prepare_append(out, reserve); size_t out_pos = li_to_base64_no_padding(result, reserve, in, in_length, charset); buffer_commit(out, out_pos); return result; }
static int secdl_verify_mac(server *srv, plugin_config *config, const char* protected_path, const char* mac, size_t maclen) { UNUSED(srv); if (0 == maclen || secdl_algorithm_mac_length(config->algorithm) != maclen) return 0; switch (config->algorithm) { case SECDL_INVALID: break; case SECDL_MD5: { li_MD5_CTX Md5Ctx; HASH HA1; char hexmd5[33]; const char *ts_str; const char *rel_uri; /* legacy message: * protected_path := '/' <timestamp-hex> <rel-path> * timestamp-hex := [0-9a-f]{8} * rel-path := '/' any* * (the protected path was already verified) * message = <secret><rel-path><timestamp-hex> */ ts_str = protected_path + 1; rel_uri = ts_str + 8; li_MD5_Init(&Md5Ctx); li_MD5_Update(&Md5Ctx, CONST_BUF_LEN(config->secret)); li_MD5_Update(&Md5Ctx, rel_uri, strlen(rel_uri)); li_MD5_Update(&Md5Ctx, ts_str, 8); li_MD5_Final(HA1, &Md5Ctx); li_tohex(hexmd5, sizeof(hexmd5), (const char *)HA1, 16); return (32 == maclen) && const_time_memeq(mac, hexmd5, 32); } case SECDL_HMAC_SHA1: #ifdef USE_OPENSSL_CRYPTO { unsigned char digest[20]; char base64_digest[27]; if (NULL == HMAC( EVP_sha1(), (unsigned char const*) CONST_BUF_LEN(config->secret), (unsigned char const*) protected_path, strlen(protected_path), digest, NULL)) { log_error_write(srv, __FILE__, __LINE__, "s", "hmac-sha1: HMAC() failed"); return 0; } li_to_base64_no_padding(base64_digest, 27, digest, 20, BASE64_URL); return (27 == maclen) && const_time_memeq(mac, base64_digest, 27); } #endif break; case SECDL_HMAC_SHA256: #ifdef USE_OPENSSL_CRYPTO { unsigned char digest[32]; char base64_digest[43]; if (NULL == HMAC( EVP_sha256(), (unsigned char const*) CONST_BUF_LEN(config->secret), (unsigned char const*) protected_path, strlen(protected_path), digest, NULL)) { log_error_write(srv, __FILE__, __LINE__, "s", "hmac-sha256: HMAC() failed"); return 0; } li_to_base64_no_padding(base64_digest, 43, digest, 32, BASE64_URL); return (43 == maclen) && const_time_memeq(mac, base64_digest, 43); } #endif break; } return 0; }