PR #21517 opened by rogerhardiman URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21517 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21517.patch
Based on a patchwork patch by Aki Sakurai from 2022-09-18, with a change to an 'else if' and a fix to av_hash_freep() The SHA-256 feature was tested with the open source SharpRTSP Server running in SHA-256 Digest Authentication mode. Testing of the existing MD5 to ensure no breakages was carried out with my room full of different makes of IP camera including IP cameras from Avigilon, Axis, Bosch, HikVision, Panasonic, and TP-Link. >From 6dd8e902165fca2feadab9c792ce9b66249ea656 Mon Sep 17 00:00:00 2001 From: Roger Hardiman <[email protected]> Date: Mon, 19 Jan 2026 14:03:57 +0000 Subject: [PATCH] Add Digest Authentication with SHA-256 Tested with SharpRTSP Camera Server Example Based on a patchwork patch by Aki Sakurai from 2022-09-18 with a bug fix to an 'else if' and a bug fix to av_hash_freep() --- libavformat/httpauth.c | 81 +++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/libavformat/httpauth.c b/libavformat/httpauth.c index 9048362509..a93b082154 100644 --- a/libavformat/httpauth.c +++ b/libavformat/httpauth.c @@ -25,7 +25,7 @@ #include "libavutil/mem.h" #include "internal.h" #include "libavutil/random_seed.h" -#include "libavutil/md5.h" +#include "libavutil/hash.h" #include "urldecode.h" static void handle_basic_params(HTTPAuthState *state, const char *key, @@ -118,22 +118,21 @@ void ff_http_auth_handle_header(HTTPAuthState *state, const char *key, } } - -static void update_md5_strings(struct AVMD5 *md5ctx, ...) +static void update_hash_strings(struct AVHashContext *hashctx, ...) { va_list vl; - va_start(vl, md5ctx); + va_start(vl, hashctx); while (1) { const char* str = va_arg(vl, const char*); if (!str) break; - av_md5_update(md5ctx, str, strlen(str)); + av_hash_update(hashctx, str, strlen(str)); } va_end(vl); } -/* Generate a digest reply, according to RFC 2617. */ +/* Generate a digest reply, according to RFC 2617 and RFC 7616. */ static char *make_digest_auth(HTTPAuthState *state, const char *username, const char *password, const char *uri, const char *method) @@ -144,55 +143,65 @@ static char *make_digest_auth(HTTPAuthState *state, const char *username, char cnonce[17]; char nc[9]; int i; - char A1hash[33], A2hash[33], response[33]; - struct AVMD5 *md5ctx; - uint8_t hash[16]; + char A1hash[AV_HASH_MAX_SIZE * 2 + 1], A2hash[AV_HASH_MAX_SIZE * 2 + 1], response[AV_HASH_MAX_SIZE * 2 + 1]; // HEX String plus string terminator + struct AVHashContext *hashctx = NULL; + uint8_t hash[AV_HASH_MAX_SIZE]; + const char* algorithm = NULL; + int hash_size; char *authstr; digest->nc++; snprintf(nc, sizeof(nc), "%08x", digest->nc); + if(!strcmp(digest->algorithm, "") || !strcmp(digest->algorithm, "MD5") || !strcmp(digest->algorithm, "MD5-sess")) + algorithm = "MD5"; + else if(!strcmp(digest->algorithm, "SHA-256") || !strcmp(digest->algorithm, "SHA-256-sess")) + algorithm = "SHA256"; + else if(!strcmp(digest->algorithm, "SHA-512-256") || !strcmp(digest->algorithm, "SHA-512-256-sess")) + algorithm = "SHA512/256"; + + if (!algorithm) { + /* Unsupported algorithm */ + return NULL; + } + /* Generate a client nonce. */ for (i = 0; i < 2; i++) cnonce_buf[i] = av_get_random_seed(); ff_data_to_hex(cnonce, (const uint8_t*) cnonce_buf, sizeof(cnonce_buf), 1); - md5ctx = av_md5_alloc(); - if (!md5ctx) + if(av_hash_alloc(&hashctx, algorithm) < 0) return NULL; - av_md5_init(md5ctx); - update_md5_strings(md5ctx, username, ":", state->realm, ":", password, NULL); - av_md5_final(md5ctx, hash); - ff_data_to_hex(A1hash, hash, 16, 1); + hash_size = av_hash_get_size(hashctx); - if (!strcmp(digest->algorithm, "") || !strcmp(digest->algorithm, "MD5")) { - } else if (!strcmp(digest->algorithm, "MD5-sess")) { - av_md5_init(md5ctx); - update_md5_strings(md5ctx, A1hash, ":", digest->nonce, ":", cnonce, NULL); - av_md5_final(md5ctx, hash); - ff_data_to_hex(A1hash, hash, 16, 1); - } else { - /* Unsupported algorithm */ - av_free(md5ctx); - return NULL; + av_hash_init (hashctx); + update_hash_strings(hashctx, username, ":", state->realm, ":", password, NULL); + av_hash_final(hashctx, hash); + ff_data_to_hex(A1hash, hash, hash_size, 1); + + if (!strcmp(digest->algorithm, "MD5-sess") || !strcmp(digest->algorithm, "SHA-256-sess") || !strcmp(digest->algorithm, "SHA-512-256-sess")) { + av_hash_init(hashctx); + update_hash_strings(hashctx, A1hash, ":", digest->nonce, ":", cnonce, NULL); + av_hash_final(hashctx, hash); + ff_data_to_hex(A1hash, hash, hash_size, 1); } - av_md5_init(md5ctx); - update_md5_strings(md5ctx, method, ":", uri, NULL); - av_md5_final(md5ctx, hash); - ff_data_to_hex(A2hash, hash, 16, 1); + av_hash_init(hashctx); + update_hash_strings(hashctx, method, ":", uri, NULL); + av_hash_final(hashctx, hash); + ff_data_to_hex(A2hash, hash, hash_size, 1); - av_md5_init(md5ctx); - update_md5_strings(md5ctx, A1hash, ":", digest->nonce, NULL); + av_hash_init(hashctx); + update_hash_strings(hashctx, A1hash, ":", digest->nonce, NULL); if (!strcmp(digest->qop, "auth") || !strcmp(digest->qop, "auth-int")) { - update_md5_strings(md5ctx, ":", nc, ":", cnonce, ":", digest->qop, NULL); + update_hash_strings(hashctx, ":", nc, ":", cnonce, ":", digest->qop, NULL); } - update_md5_strings(md5ctx, ":", A2hash, NULL); - av_md5_final(md5ctx, hash); - ff_data_to_hex(response, hash, 16, 1); + update_hash_strings(hashctx, ":", A2hash, NULL); + av_hash_final(hashctx, hash); + ff_data_to_hex(response, hash, hash_size, 1); - av_free(md5ctx); + av_hash_freep(&hashctx); if (!strcmp(digest->qop, "") || !strcmp(digest->qop, "auth")) { } else if (!strcmp(digest->qop, "auth-int")) { -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
