{"id":50425500,"url":"https://github.com/sippy/sip25519","last_synced_at":"2026-05-31T10:04:15.820Z","repository":{"id":361240081,"uuid":"1253673050","full_name":"sippy/sip25519","owner":"sippy","description":"RFC Draft: SIP Digest Authentication with X25519 Shared Secrets and Ristretto255 Schnorr Proofs","archived":false,"fork":false,"pushed_at":"2026-05-29T18:13:42.000Z","size":57,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-29T20:05:49.567Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sippy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-29T17:46:04.000Z","updated_at":"2026-05-29T18:13:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sippy/sip25519","commit_stats":null,"previous_names":["sippy/sip25519"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/sippy/sip25519","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sippy%2Fsip25519","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sippy%2Fsip25519/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sippy%2Fsip25519/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sippy%2Fsip25519/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sippy","download_url":"https://codeload.github.com/sippy/sip25519/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sippy%2Fsip25519/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33726739,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-31T02:00:06.040Z","response_time":95,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-31T10:04:14.885Z","updated_at":"2026-05-31T10:04:15.807Z","avatar_url":"https://github.com/sippy.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build](https://github.com/sippy/sip25519/actions/workflows/build.yml/badge.svg)](https://github.com/sippy/sip25519/actions/workflows/build.yml)\n\n\u003c!-- Generated content below. Edit README.md.pre for the preamble. --\u003e\n\n# SIP Digest Authentication with X25519 Shared Secrets and Ristretto255 Schnorr Proofs\n\n*Internet-Draft: `draft-sobolyev-sip-digest-auth-x25519-ristretto255-schnorr-00`*\n\n## Abstract\n\nThis document defines three Session Initiation Protocol (SIP) Digest authentication\nalgorithms that replace password-derived Digest secrets with public-key-based\nauthentication material. Two algorithms derive a response secret from an X25519 shared\nsecret, and one algorithm uses a Fiat-Shamir Schnorr proof over the ristretto255 group.\n\nThe mechanisms defined here preserve the existing SIP Digest challenge and authorization\nheader flow while adding Digest parameters that carry public keys and, optionally, an\nauthenticated server challenge proof.\n\n## 1. Introduction\n\nThis document defines the following SIP Digest authentication algorithm tokens:\n\n- `X25519-HKDF-SHA256`\n- `X25519-HMAC-SHA256`\n- `R25519-SCHNORR-SHA256`\n\nThe algorithms are intended for deployments where the User Agent Client (UAC) and User\nAgent Server (UAS), or a proxy acting as the authenticating server, have pre-provisioned\ntrust in each other's public keys. They do not define certificate discovery, enrollment,\nor authorization policy.\n\nThe X25519 algorithms derive authentication material from the shared secret computed by\n[RFC7748] X25519. The ristretto255 algorithm uses a Schnorr-style non-interactive proof\nover the group defined by [RFC9496].\n\n`X25519-HKDF-SHA256` and `X25519-HMAC-SHA256` preserve the original SIP Digest flow: the\nUAS sends a challenge and the UAC sends an authorization response after validating the\nchallenged server public key against local policy. `R25519-SCHNORR-SHA256` adds a new\ncapability: the UAC can request that the UAS pre-authenticate the challenge using\n`server-response` before the UAC generates its own proof. This prevents an\nunauthenticated man-in-the-middle attacker from causing the UAC to perform private-key\noperations for attacker-generated challenges, reducing exposure to private-key\nextraction attempts that rely on side channels or fault behavior during proof\ngeneration.\n\nThe existing SIP Digest parameters, including `realm`, `username`, `nonce`, `uri`,\n`qop`, `nc`, `cnonce`, and `response`, retain their existing Digest roles. This document\ndefines four new Digest parameters: `server-pubkey`, `client-pubkey`,\n`client-challenge`, and `server-response`.\n\n## 2. Motivation\n\nTraditional SIP Digest authentication is based on a `username` and a shared password or\npassword-equivalent secret. This model is well suited to human subscriber authentication\nand legacy provisioning systems, but it is a poor fit for many machine-to-machine SIP\ndeployments.\n\nMachine-to-machine SIP authentication is often performed between systems, services,\ntrunks, gateways, proxies, application servers, Session Border Controllers (SBCs), and\nother automated endpoints. These entities do not always naturally correspond to human\nusernames and passwords. Password-based provisioning also creates operational issues:\nshared secrets must be generated, distributed, rotated, stored, and protected by both\nsides. A compromise of the verifier-side secret database can expose password-equivalent\nmaterial that can be used for impersonation.\n\nPublic-key authentication is often a better fit for these environments. Each endpoint\ncan be provisioned with a private key and a corresponding trusted public key. The\nprivate key does not need to be shared with the peer, and the public key can be\ndistributed through configuration, inventory, orchestration, certificates, or another\ntrust-management system.\n\nThe mechanisms in this document use modern elliptic-curve primitives rather than older\nRSA-based public-key schemes. X25519 and ristretto255 provide compact public keys and\nauthentication material, efficient constant-time implementations, and simpler fixed-size\nencodings. These properties are useful for SIP deployments where authentication data is\ncarried in header fields and where endpoints may need to perform many authentication\noperations per second.\n\nThe goal of these mechanisms is to support deployments where authorization is tied to\npossession of a configured private key rather than knowledge of a shared password, while\npreserving SIP Digest processing. This model also supports deployments where a request\nis not accepted merely because it arrives from a particular network, IP address,\ninterface, trunk, or transport path. Instead, the receiver verifies cryptographic proof\nthat the sender possesses the private key corresponding to a trusted public key, and\nthen applies local authorization policy for that key, realm, endpoint, account, route,\nor service.\n\nSIP over TLS can provide transport confidentiality, transport integrity, and\ntransport-layer peer authentication. However, TLS authentication is tied to the\ntransport connection and does not by itself define SIP Digest identities, Digest `realm`\nscoping, SIP authorization policy, or authentication of individual SIP requests and\nentity bodies through the Digest `qop` model. The mechanisms in this document are\ntherefore complementary to TLS rather than replacements for it.\n\n## 3. Conventions and Terminology\n\nThe key words **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHALL NOT**,\n**SHOULD**, **SHOULD NOT**, **RECOMMENDED**, **NOT RECOMMENDED**, **MAY**, and\n**OPTIONAL** in this document are to be interpreted as described in BCP 14 [RFC2119]\n[RFC8174] when, and only when, they appear in all capitals, as shown here.\n\n- **UAC**: SIP User Agent Client.\n- **UAS**: SIP User Agent Server.\n- **X25519 public key**: A 32-octet raw X25519 public key as specified by [RFC7748].\n- **ristretto255 public key**: A 32-octet compressed ristretto255 group element as specified by [RFC9496].\n- **base64url**: Base64url encoding without padding, using the URL and filename safe alphabet from [RFC4648] Section 5.\n- **digest-uri**: The value of the Digest `uri` parameter.\n- **entity-body**: The SIP message body used for the `qop=auth-int` calculation.\n- **SHA-256**: The SHA-256 hash function specified by [RFC6234].\n\n## 4. Digest Parameters and Syntax\n\nThe parameters in this section extend the Digest `auth-param` syntax used by SIP Digest\nauthentication [RFC3261] [RFC8760]. Unless otherwise stated, each value is carried as a\nquoted string containing an unpadded base64url value.\n\n```abnf\nbase64url-char     = ALPHA / DIGIT / \"-\" / \"_\"\nbase64url-value    = 1*base64url-char\nb64q               = DQUOTE base64url-value DQUOTE\n\nserver-pubkey      = \"server-pubkey\" EQUAL b64q\nclient-pubkey      = \"client-pubkey\" EQUAL b64q\nclient-challenge   = \"client-challenge\" EQUAL b64q\nserver-response    = \"server-response\" EQUAL b64q\n```\n\n`ALPHA`, `DIGIT`, and `DQUOTE` are defined by [RFC5234]. `EQUAL` is inherited from the\nSIP grammar in [RFC3261].\n\n### 4.1. server-pubkey\n\nThe `server-pubkey` parameter is sent by the UAS in `WWW-Authenticate`, or by a proxy in\n`Proxy-Authenticate`.\n\nFor `X25519-HKDF-SHA256` and `X25519-HMAC-SHA256`, it contains the raw 32-octet X25519\npublic key of the authenticating server. For `R25519-SCHNORR-SHA256`, it contains the\n32-octet ristretto255 public key of the authenticating server.\n\nA UAC receiving this parameter **MUST** verify that the decoded public key is trusted\nfor the challenged SIP realm, peer, route, outbound proxy, or configured authentication\ndomain before generating an authorization response.\n\n### 4.2. client-pubkey\n\nThe `client-pubkey` parameter is sent by the UAC in `Authorization` or\n`Proxy-Authorization`.\n\nFor `X25519-HKDF-SHA256` and `X25519-HMAC-SHA256`, it contains the raw 32-octet X25519\npublic key of the authenticating client. For `R25519-SCHNORR-SHA256`, it contains the\n32-octet ristretto255 public key whose corresponding private scalar is proven by the\nUAC.\n\nA UAS receiving this parameter **MUST** verify that the decoded public key is trusted\nfor the claimed `username`, if present, and `realm`. If `username` is absent, the UAS\n**MUST** verify that `client-pubkey` is trusted for the `realm` and for the applicable\naccount, subscriber, endpoint, authorization identity, or other local authorization\nrecord.\n\n### 4.3. client-challenge\n\nThe `client-challenge` parameter is sent by the UAC in an initial `Authorization` or\n`Proxy-Authorization` header when requesting an authenticated server challenge. It\ncontains at least 128 bits of client-generated randomness.\n\nThe parameter is used by `R25519-SCHNORR-SHA256` to allow the UAS to prove possession of\nthe private scalar corresponding to `server-pubkey` in the 401 or 407 challenge\nresponse. The UAS **MUST NOT** echo `client-challenge` in `WWW-Authenticate` or\n`Proxy-Authenticate`.\n\nThe UAC **MUST** verify `server-response` using the locally remembered\n`client-challenge` value that it generated and sent. The UAC **MUST NOT** use any\nreflected or received `client-challenge` value from a response header when verifying\n`server-response`.\n\n### 4.4. server-response\n\nThe `server-response` parameter is sent by the UAS in `WWW-Authenticate`, or by a proxy\nin `Proxy-Authenticate`, when responding to a request that contained `client-challenge`.\n\nThe value is `base64url(R || s)`, where `R` is a compressed ristretto255 commitment of\n32 octets and `s` is a canonical scalar modulo the ristretto255 group order, encoded as\n32 octets. The decoded value is therefore exactly 64 octets.\n\n## 5. Transcript Encoding\n\nAll cryptographic transcripts defined by this document use the following deterministic\nencoding to avoid ambiguity between adjacent SIP and Digest fields.\n\n`Transcript(label, field-list)` is the octet string formed by concatenating the US-ASCII\n`label`, a line feed (`%x0A`), and then, for each field in order:\n\n1. the US-ASCII field name,\n1. a colon (`%x3A`),\n1. the decimal octet length of the field value encoded in US-ASCII without leading zeroes,\n1. another colon,\n1. the field value octets, and\n1. a line feed.\n\nUnless otherwise stated, SIP and Digest string fields are encoded exactly as their field\nvalues appear after Digest quoted-string unescaping. Binary fields, including public\nkeys, shared secrets, commitments, scalars, and hash outputs, are encoded as their raw\noctets when they are transcript fields. The final line feed is part of the transcript.\n\nFor `qop=auth`, the `body-hash` transcript field is the zero-length value. For\n`qop=auth-int`, it is the raw 32-octet SHA-256 digest of the entity body.\n\n## 6. Common Digest Fields\n\nThe Digest fields `realm`, `username`, `nonce`, `uri`, `qop`, `nc`, `cnonce`, and\n`response` retain their usual meanings in SIP Digest authentication, except as\nexplicitly stated in this section. For all algorithms in this document, `realm` is\n**REQUIRED** and `qop=auth` and `qop=auth-int` are supported.\n\nFor the algorithms defined by this document, `username` is **OPTIONAL**. For all\ncalculations and transcripts defined by this document, an absent `username` is\nequivalent to an explicitly empty username. All formulas that reference `username` use\nthe received username value if present, or a zero-length string if absent.\n\nIf `username` is present, it is an identity hint. The verifier **MAY** use it to select\nan account, subscriber, endpoint, or authorization record. The verifier **MUST** still\nverify that `client-pubkey` is trusted for the claimed `username` and `realm`. If\n`username` is absent, the verifier **MUST** identify the peer by `client-pubkey` and\n`realm` using local policy.\n\nWhen `qop=auth-int` is used, the authentication calculation includes the entity-body\nhash. For SIP `INVITE` requests carrying Session Description Protocol (SDP), this\nprovides integrity protection for the SDP body against attackers that cannot produce the\nrequired authentication response.\n\nThe `response` value is algorithm-specific. The `X25519-HKDF-SHA256` and\n`X25519-HMAC-SHA256` algorithms encode `response` as lowercase hexadecimal. The\n`R25519-SCHNORR-SHA256` algorithm uses a different format: `response` is an unpadded\nbase64url encoding of the 64-octet Schnorr proof `R_c || s_c`.\n\n## 7. Algorithm: X25519-HKDF-SHA256\n\n### 7.1. Challenge\n\nThe UAS sends a Digest challenge with `algorithm=X25519-HKDF-SHA256` and\n`server-pubkey`.\n\n```text\nWWW-Authenticate: Digest\n    realm=\"sip.example.net\",\n    algorithm=X25519-HKDF-SHA256,\n    nonce=\"NQ7x0vR3VnP0aK9fW6tDHA\",\n    qop=\"auth,auth-int\",\n    server-pubkey=\"xRbeh9_DZBrONNFs7P8rhZhcLlXSw79RU5frhaOvIZc\"\n```\n\n### 7.2. Authorization Response\n\nThe UAC sends a Digest authorization response with `client-pubkey`. The `username`\nparameter **MAY** be omitted.\n\nExample with `username` present:\n\n```text\nAuthorization: Digest\n    username=\"alice\",\n    realm=\"sip.example.net\",\n    algorithm=X25519-HKDF-SHA256,\n    nonce=\"NQ7x0vR3VnP0aK9fW6tDHA\",\n    uri=\"sip:bob@example.net\",\n    qop=auth-int,\n    nc=00000001,\n    cnonce=\"q1w2e3r4t5y6\",\n    client-pubkey=\"fPEDas5tsJgGPG_QMPVECsTySsC0TFGHRVSNcWSmABQ\",\n    response=\"281847efc4a3739d638de9f729fb6b5565bb2f2a006f1719\"\n```\n\nExample with `username` absent:\n\n```text\nAuthorization: Digest\n    realm=\"sip.example.net\",\n    algorithm=X25519-HKDF-SHA256,\n    nonce=\"NQ7x0vR3VnP0aK9fW6tDHA\",\n    uri=\"sip:bob@example.net\",\n    qop=auth-int,\n    nc=00000001,\n    cnonce=\"q1w2e3r4t5y6\",\n    client-pubkey=\"zLhVVAHkZJ8oNU-v2DKauUB_TvWBn1dpcBFtQL6kd6s\",\n    response=\"fb2e80bda9f83361e995f1c7662b5cc32ee259f3c4ea9d66\"\n```\n\n### 7.3. Shared Secret Calculation\n\nThe UAC computes `Z = X25519(client-private-key, server-pubkey)`. The UAS computes `Z =\nX25519(server-private-key, client-pubkey)`. Both sides **MUST** reject the exchange if\nthe computed X25519 shared secret is the all-zero value.\n\nThe Digest response key `K` is derived with HKDF-SHA256 [RFC5869]:\n\n```pseudocode\nsalt = Transcript(\"SIP-Digest-X25519-HKDF-SHA256-salt-v1\",\n                  nonce, cnonce)\n\ninfo = Transcript(\"SIP-Digest-X25519-HKDF-SHA256-info-v1\",\n                  algorithm, username, realm, nonce, cnonce,\n                  server-pubkey, client-pubkey)\n\nK = HKDF-SHA256(IKM = Z, salt = salt, info = info, L = 32)\n```\n\n### 7.4. Response Calculation\n\nThe `response` value is computed as follows:\n\n```pseudocode\nbody-hash = \"\"                  ; for qop=auth\nbody-hash = SHA-256(entity-body) ; for qop=auth-int\n\nHA1 = SHA-256(Transcript(\n          \"SIP-Digest-X25519-HKDF-SHA256-HA1-v1\",\n          username, realm, K))\n\nHA2 = SHA-256(Transcript(\n          \"SIP-Digest-X25519-HKDF-SHA256-HA2-v1\",\n          method, digest-uri, qop, body-hash))\n\nresponse = SHA-256(Transcript(\n          \"SIP-Digest-X25519-HKDF-SHA256-response-v1\",\n          HA1, nonce, nc, cnonce, qop, HA2))\n```\n\nThe `response` value is encoded as lowercase hexadecimal SHA-256 output.\n\n## 8. Algorithm: X25519-HMAC-SHA256\n\nThe `X25519-HMAC-SHA256` algorithm uses the same `server-pubkey` and `client-pubkey`\nparameters as `X25519-HKDF-SHA256`, but computes the final `response` as an HMAC\n[RFC2104] rather than as a Digest-style hash chain.\n\n### 8.1. Challenge\n\nThe UAS sends a Digest challenge with `algorithm=X25519-HMAC-SHA256` and\n`server-pubkey`.\n\n```text\nWWW-Authenticate: Digest\n    realm=\"sip.example.net\",\n    algorithm=X25519-HMAC-SHA256,\n    nonce=\"NQ7x0vR3VnP0aK9fW6tDHA\",\n    qop=\"auth,auth-int\",\n    server-pubkey=\"bzeK9qEcpcMStQYlqQbVs5NfjMMu76AlsKV587PvlT8\"\n```\n\n### 8.2. Authorization Response\n\nThe UAC sends a Digest authorization response with `client-pubkey`. The `username`\nparameter **MAY** be omitted.\n\nExample with `username` present:\n\n```text\nAuthorization: Digest\n    username=\"alice\",\n    realm=\"sip.example.net\",\n    algorithm=X25519-HMAC-SHA256,\n    nonce=\"NQ7x0vR3VnP0aK9fW6tDHA\",\n    uri=\"sip:bob@example.net\",\n    qop=auth-int,\n    nc=00000001,\n    cnonce=\"q1w2e3r4t5y6\",\n    client-pubkey=\"hDX3Ky19NCnnzATsdgvdu5BvPqwGdOOP1koEUWU6gZ4\",\n    response=\"3401ac99fa30dacdeeb245749639dcd46c504611df2398dd\"\n```\n\nExample with `username` absent:\n\n```text\nAuthorization: Digest\n    realm=\"sip.example.net\",\n    algorithm=X25519-HMAC-SHA256,\n    nonce=\"NQ7x0vR3VnP0aK9fW6tDHA\",\n    uri=\"sip:bob@example.net\",\n    qop=auth-int,\n    nc=00000001,\n    cnonce=\"q1w2e3r4t5y6\",\n    client-pubkey=\"dywz9UEYmTmzGXuNrfSZGw1maX0vGJ3i4kMPaHmRyzo\",\n    response=\"14ec53f746359ba4d64ff8cf8d5667cbe64b14c9b50c4dd4\"\n```\n\n### 8.3. Shared Secret Calculation\n\nThe UAC computes `Z = X25519(client-private-key, server-pubkey)`. The UAS computes `Z =\nX25519(server-private-key, client-pubkey)`. Both sides **MUST** reject the exchange if\nthe computed X25519 shared secret is the all-zero value.\n\n```pseudocode\nK = SHA-256(Transcript(\n        \"SIP-Digest-X25519-HMAC-SHA256-key-v1\",\n        Z, algorithm, username, realm, nonce, cnonce,\n        server-pubkey, client-pubkey))\n```\n\n### 8.4. HMAC Transcript\n\n```pseudocode\nbody-hash = \"\"                  ; for qop=auth\nbody-hash = SHA-256(entity-body) ; for qop=auth-int\n\ntranscript = Transcript(\n        \"SIP-Digest-X25519-HMAC-SHA256-response-v1\",\n        username, realm, nonce, nc, cnonce, qop,\n        method, digest-uri, body-hash, server-pubkey, client-pubkey)\n\nresponse = HMAC-SHA256(K, transcript)\n```\n\nThe `response` value is encoded as lowercase hexadecimal HMAC-SHA256 output.\n\n## 9. Algorithm: R25519-SCHNORR-SHA256\n\nThe `R25519-SCHNORR-SHA256` algorithm defines a Schnorr-style Fiat-Shamir\nnon-interactive proof of knowledge over the ristretto255 group. The UAC proves knowledge\nof a scalar `x_c` corresponding to `client-pubkey = x_c * G`, where `G` is the canonical\nristretto255 base point.\n\n### 9.1. Optional Authenticated Server Challenge Request\n\nA UAC **MAY** request an authenticated server challenge by including `client-challenge`\nin an initial request.\n\n```text\nINVITE sip:bob@example.net SIP/2.0\nAuthorization: Digest\n    algorithm=R25519-SCHNORR-SHA256,\n    client-challenge=\"0Xc7ag8QRtRWlamLDDozsA\"\n```\n\nThis header does not authenticate the UAC. It only supplies freshness for an\nauthenticated server challenge. A UAC that sends `client-challenge` **MUST** remember\nthe value locally until it receives and verifies the corresponding `WWW-Authenticate` or\n`Proxy-Authenticate` challenge, or until the transaction is abandoned.\n\n### 9.2. Challenge\n\nThe UAS sends a Digest challenge with `algorithm=R25519-SCHNORR-SHA256` and\n`server-pubkey`. If the request contained a valid `client-challenge`, the UAS **MAY**\ninclude `server-response`.\n\n```text\nWWW-Authenticate: Digest\n    realm=\"sip.example.net\",\n    algorithm=R25519-SCHNORR-SHA256,\n    nonce=\"NQ7x0vR3VnP0aK9fW6tDHA\",\n    qop=\"auth,auth-int\",\n    server-pubkey=\"xBiXzi82PKyiSqcRBXJauiNECbQDQZfzt-RRwzsKAXs\",\n    server-response=\"neTvyoW2SLh32ob-UTteu_ragDBe2Ub3wqhm969gjlw\"\n```\n\n### 9.3. Authenticated Server Challenge Proof\n\nWhen `server-response` is present, it proves possession of the private scalar\ncorresponding to `server-pubkey`. The UAS has private scalar `x_s` and public key `A_s =\nx_s * G`, where `A_s` is `server-pubkey`.\n\n```pseudocode\nT_srv_chal = Transcript(\n    \"SIP-Digest-R25519-SCHNORR-SHA256-ServerChallenge-v1\",\n    algorithm, method, digest-uri, realm, nonce, qop-list,\n    server-pubkey, client-challenge)\n\nR_s = r_s * G\nc_s = SHA-256(Transcript(\n          \"SIP-Digest-R25519-SCHNORR-SHA256-ServerChallenge-c-v1\",\n          T_srv_chal, R_s)) mod L\ns_s = r_s + c_s * x_s mod L\n\nserver-response = base64url(R_s || s_s)\n```\n\n`r_s` is a fresh random scalar and `L` is the ristretto255 group order. The UAC verifies\nby recomputing the transcript and checking `s_s * G == R_s + c_s * A_s`.\n\nThe UAC **MUST** reject the challenge if `server-response` is required by local policy\nand is absent, malformed, invalid, not bound to the locally remembered\n`client-challenge`, or not valid for the received `server-pubkey`.\n\n### 9.4. Authorization Proof\n\nThe UAC sends a Digest authorization response with `client-pubkey`. The `username`\nparameter **MAY** be omitted. The `response` parameter contains `base64url(R_c || s_c)`,\nwhere `R_c` is a compressed ristretto255 commitment and `s_c` is a canonical scalar\nmodulo the group order. This differs from the hexadecimal Digest response values used by\nthe X25519 algorithms. The decoded value is exactly 64 octets.\n\n```pseudocode\nA_c = x_c * G\nR_c = r_c * G\n\nbody-hash = \"\"                  ; for qop=auth\nbody-hash = SHA-256(entity-body) ; for qop=auth-int\n\nT_uac = Transcript(\n    \"SIP-Digest-R25519-SCHNORR-SHA256-UAC-v1\",\n    algorithm, username, realm, nonce, nc, cnonce, qop,\n    method, digest-uri, body-hash, server-pubkey, client-pubkey)\n\nc_c = SHA-256(Transcript(\n          \"SIP-Digest-R25519-SCHNORR-SHA256-UAC-c-v1\",\n          T_uac, R_c)) mod L\ns_c = r_c + c_c * x_c mod L\n\nresponse = base64url(R_c || s_c)\n```\n\nThe UAS decodes `A_c` from `client-pubkey`, reconstructs `T_uac` from the received\nrequest and Digest parameters, and accepts only if `s_c * G == R_c + c_c * A_c`. The UAS\n**MUST** reject malformed ristretto255 encodings, non-canonical scalars, invalid proof\nlengths, and proofs that are not valid for the exact received transcript.\n\nA proof generated for one method, URI, nonce, cnonce, nonce-count, qop value, body,\nrealm, server public key, client public key, or username value **MUST NOT** be accepted\nfor another.\n\n## 10. Verification Rules\n\nA receiver **MUST** reject authentication if any of the following are true:\n\n- `server-pubkey` is absent from the challenge;\n- `client-pubkey` is absent from the authorization response;\n- `realm` is absent from the challenge or authorization response;\n- a public key is malformed for the selected algorithm;\n- the peer public key is not trusted for the claimed identity or realm;\n- `nonce` is expired, unknown, malformed, or already consumed;\n- `nc` does not increase monotonically for the nonce and client identity pair;\n- `cnonce` is absent when `qop` is present;\n- `qop` is unsupported;\n- `response` is malformed; or\n- `response` does not match or verify against the locally computed value.\n\nFor `R25519-SCHNORR-SHA256`, a receiver **MUST** also reject authentication if\n`server-response` is malformed when present, is absent when required by local policy, or\ndoes not verify against the locally remembered `client-challenge`.\n\nA UAS **MUST NOT** authenticate a UAC merely because `client-pubkey` is present. The\n`client-pubkey` value **MUST** be bound to a trusted identity, such as the `username` if\npresent, configured endpoint, account, subscriber, realm, or equivalent local\nauthorization record.\n\nA UAC **MUST NOT** answer a challenge merely because `server-pubkey` is present. The\n`server-pubkey` value **MUST** be present in the UAC's trusted key list for the\nchallenged peer, realm, outbound proxy, or service domain.\n\nImplementations **MUST** reject algorithm identifiers other than those explicitly\ndefined by this document or locally configured for this mechanism.\n\n## 11. Replay Protection\n\nThe UAS **MUST** generate nonces with sufficient entropy and unpredictability. The UAS\n**MUST** reject replayed tuples of `client-pubkey`, `nonce`, `nc`, and `cnonce`. If\n`username` is present, the UAS **MAY** also include `username` in the replay cache key.\nThe UAS **SHOULD** expire nonces after a short interval and **SHOULD** bind nonces to\nthe challenged realm, selected algorithm, and `server-pubkey`.\n\nThe UAC **SHOULD** generate a fresh `client-challenge` for each initial authenticated\nchallenge request. The UAC **MUST NOT** accept a `server-response` generated for a\ndifferent `client-challenge`.\n\n## 12. Body Integrity\n\nWhen `qop=auth-int` is used, the entity-body hash is included in the authentication\ncalculation. For SIP requests carrying SDP, this protects the SDP body against\nmodification by an attacker that does not know the X25519-derived authentication secret\nor cannot generate the required ristretto255 Schnorr proof.\n\nIf intermediaries are expected to modify the SDP body, `qop=auth-int` can fail unless\nthe modification happens before the UAC computes the authorization response or unless\nthe deployment explicitly permits such behavior.\n\n## 13. Examples\n\n### 13.1. Initial Request Asking for Authenticated Server Challenge\n\n```text\nINVITE sip:bob@example.net SIP/2.0\nVia: SIP/2.0/TLS client.example.org;branch=z9hG4bK776asdhds\nFrom: \u003csip:alice@example.org\u003e;tag=1928301774\nTo: \u003csip:bob@example.net\u003e\nCall-ID: a84b4c76e66710@example.org\nCSeq: 314159 INVITE\nAuthorization: Digest algorithm=R25519-SCHNORR-SHA256,\n    client-challenge=\"QG7xYpk5XlVz9hHMKx3uRg\"\nContent-Length: 0\n```\n\n### 13.2. Authenticated R25519-SCHNORR-SHA256 Challenge\n\n```text\nSIP/2.0 401 Unauthorized\nVia: SIP/2.0/TLS client.example.org;branch=z9hG4bK776asdhds\nFrom: \u003csip:alice@example.org\u003e;tag=1928301774\nTo: \u003csip:bob@example.net\u003e;tag=a6c85cf\nCall-ID: a84b4c76e66710@example.org\nCSeq: 314159 INVITE\nWWW-Authenticate: Digest realm=\"sip.example.net\",\n    algorithm=R25519-SCHNORR-SHA256,\n    nonce=\"NQ7x0vR3VnP0aK9fW6tDHA\",\n    qop=\"auth,auth-int\",\n    server-pubkey=\"V8nM6R1l7Pp4sLdbZSyGx6Fv5F1LxPvV9gzLg4YhV2I\",\n    server-response=\"Jvx3L4ZPTVq43cacYBONePT4nInA-F8FPqL1mv7ORC0\"\nContent-Length: 0\n```\n\n### 13.3. R25519-SCHNORR-SHA256 Authorization with Username\n\n```text\nINVITE sip:bob@example.net SIP/2.0\nVia: SIP/2.0/TLS client.example.org;branch=z9hG4bK776asdhds\nFrom: \u003csip:alice@example.org\u003e;tag=1928301774\nTo: \u003csip:bob@example.net\u003e\nCall-ID: a84b4c76e66710@example.org\nCSeq: 314160 INVITE\nContact: \u003csip:alice@client.example.org\u003e\nAuthorization: Digest username=\"alice\",\n    realm=\"sip.example.net\",\n    algorithm=R25519-SCHNORR-SHA256,\n    nonce=\"NQ7x0vR3VnP0aK9fW6tDHA\",\n    uri=\"sip:bob@example.net\",\n    qop=auth-int,\n    nc=00000001,\n    cnonce=\"q1w2e3r4t5y6\",\n    client-pubkey=\"LKz2bq0TLeHqkCJ2m6v9MGWQp9WnZtDZ9pYyHk4IoX0\",\n    response=\"mU7Wgqm2wHIAk993xXo6OXKMQBNtgl-mFJQ_-Rgo8oI\"\nContent-Type: application/sdp\nContent-Length: ...\n```\n\n### 13.4. R25519-SCHNORR-SHA256 Authorization without Username\n\n```text\nINVITE sip:bob@example.net SIP/2.0\nVia: SIP/2.0/TLS client.example.org;branch=z9hG4bK776asdhds\nFrom: \u003csip:alice@example.org\u003e;tag=1928301774\nTo: \u003csip:bob@example.net\u003e\nCall-ID: a84b4c76e66710@example.org\nCSeq: 314160 INVITE\nContact: \u003csip:alice@client.example.org\u003e\nAuthorization: Digest\n    realm=\"sip.example.net\",\n    algorithm=R25519-SCHNORR-SHA256,\n    nonce=\"NQ7x0vR3VnP0aK9fW6tDHA\",\n    uri=\"sip:bob@example.net\",\n    qop=auth-int,\n    nc=00000001,\n    cnonce=\"q1w2e3r4t5y6\",\n    client-pubkey=\"a0t5YmU8Ppgp0zLGgwsVXnxViPImkjyyzWTDj5wfmxE\",\n    response=\"bde_KoYDFV3SYJa55WppUdlgLjhgM3vqT5U7qa6YR_o\"\nContent-Type: application/sdp\nContent-Length: ...\n```\n\n### 13.5. X25519-HKDF-SHA256 Challenge\n\n```text\nSIP/2.0 401 Unauthorized\nVia: SIP/2.0/TLS client.example.org;branch=z9hG4bK776asdhds\nFrom: \u003csip:alice@example.org\u003e;tag=1928301774\nTo: \u003csip:bob@example.net\u003e;tag=a6c85cf\nCall-ID: a84b4c76e66710@example.org\nCSeq: 314159 INVITE\nWWW-Authenticate: Digest realm=\"sip.example.net\",\n    algorithm=X25519-HKDF-SHA256,\n    nonce=\"NQ7x0vR3VnP0aK9fW6tDHA\",\n    qop=\"auth,auth-int\",\n    server-pubkey=\"V8nM6R1l7Pp4sLdbZSyGx6Fv5F1LxPvV9gzLg4YhV2I\"\nContent-Length: 0\n```\n\n### 13.6. X25519-HKDF-SHA256 Authorization with Username\n\n```text\nINVITE sip:bob@example.net SIP/2.0\nVia: SIP/2.0/TLS client.example.org;branch=z9hG4bK776asdhds\nFrom: \u003csip:alice@example.org\u003e;tag=1928301774\nTo: \u003csip:bob@example.net\u003e\nCall-ID: a84b4c76e66710@example.org\nCSeq: 314160 INVITE\nContact: \u003csip:alice@client.example.org\u003e\nAuthorization: Digest username=\"alice\",\n    realm=\"sip.example.net\",\n    algorithm=X25519-HKDF-SHA256,\n    nonce=\"NQ7x0vR3VnP0aK9fW6tDHA\",\n    uri=\"sip:bob@example.net\",\n    qop=auth-int,\n    nc=00000001,\n    cnonce=\"q1w2e3r4t5y6\",\n    client-pubkey=\"LKz2bq0TLeHqkCJ2m6v9MGWQp9WnZtDZ9pYyHk4IoX0\",\n    response=\"92eab8507440bf720bfffdffcdab35c785ddee69d419db58\"\nContent-Type: application/sdp\nContent-Length: ...\n```\n\n### 13.7. X25519-HKDF-SHA256 Authorization without Username\n\n```text\nINVITE sip:bob@example.net SIP/2.0\nVia: SIP/2.0/TLS client.example.org;branch=z9hG4bK776asdhds\nFrom: \u003csip:alice@example.org\u003e;tag=1928301774\nTo: \u003csip:bob@example.net\u003e\nCall-ID: a84b4c76e66710@example.org\nCSeq: 314160 INVITE\nContact: \u003csip:alice@client.example.org\u003e\nAuthorization: Digest\n    realm=\"sip.example.net\",\n    algorithm=X25519-HKDF-SHA256,\n    nonce=\"NQ7x0vR3VnP0aK9fW6tDHA\",\n    uri=\"sip:bob@example.net\",\n    qop=auth-int,\n    nc=00000001,\n    cnonce=\"q1w2e3r4t5y6\",\n    client-pubkey=\"q6wi4GXRx1poYAVvqcp7nmC4FU0MDxnvooatixWp1mY\",\n    response=\"d857749505ba1cc5262d945bfd793d7988f6a0d675eab113\"\nContent-Type: application/sdp\nContent-Length: ...\n```\n\n## 14. IANA Considerations\n\nThis document requests registration of the following Digest algorithm tokens in the\napplicable Digest algorithm registry:\n\n- `X25519-HKDF-SHA256`\n- `X25519-HMAC-SHA256`\n- `R25519-SCHNORR-SHA256`\n\nThe following Digest authentication parameters are also defined by this document:\n`server-pubkey`, `client-pubkey`, `client-challenge`, and `server-response`.\n\n## 15. Implementation Notes\n\nImplementations **SHOULD** use well-reviewed cryptographic libraries for X25519,\nHKDF-SHA256, HMAC-SHA256, SHA-256, and ristretto255. Implementations **SHOULD** avoid\naccepting algorithm aliases.\n\nImplementations **SHOULD** domain-separate every proof or MAC input exactly as\nspecified.\n\nImplementations **SHOULD** log authentication failures without logging private keys,\nshared secrets, raw proof scalars, derived keys, or complete authentication transcripts.\n\nImplementations **SHOULD** treat `server-pubkey` and `client-pubkey` as identity-bearing\nmaterial and apply local authorization policy before accepting a request.\n\nImplementations need to account for generic Digest parsers that assume `username` is\nalways present. Implementations of this specification **MUST** support the absence of\n`username` for the algorithms defined here.\n\n## 16. Security Considerations\n\nThis mechanism prevents impersonation only when both sides have securely provisioned\npeer public keys, bind those keys to the applicable realm and authorization identity,\nand enforce the replay protections required by this document. X25519 by itself is not\nauthentication. Authentication is achieved only by deriving a secret from a trusted peer\npublic key and proving possession of the corresponding private key through the Digest\n`response`.\n\nFor `X25519-HKDF-SHA256` and `X25519-HMAC-SHA256`, the UAC trusts the UAS X25519 public\nkey and the UAS trusts the UAC X25519 public key. For `R25519-SCHNORR-SHA256`, the UAS\ntrusts the UAC ristretto255 public key, and the UAC trusts the UAS ristretto255 public\nkey before answering the challenge. The `server-response` parameter provides\nauthenticated server challenges when required by local policy.\n\nThe ristretto255 Schnorr algorithm authenticates the UAC by proving knowledge of the\nprivate scalar corresponding to `client-pubkey`, bound to the SIP Digest transcript. The\n`server-response` parameter authenticates the server challenge by proving knowledge of\nthe private scalar corresponding to `server-pubkey`, bound to a UAC-generated\n`client-challenge`.\n\nNonce freshness, nonce-count validation, client nonce validation, and replay-cache\nenforcement are part of the security of this mechanism. An implementation that accepts\nreplayed Digest responses can authenticate a stale request even when the cryptographic\nproof or MAC is otherwise valid.\n\nThese algorithms authenticate SIP Digest exchanges and, when `qop=auth-int` is used,\nprovide integrity protection for the authenticated SIP entity body. They do not\nestablish a confidential transport channel, protect SIP metadata, or provide media\nsecurity. Deployments requiring confidential signaling, SIP metadata protection,\ntransport-layer peer authentication, or media security **SHOULD** use SIP over TLS and\nappropriate media-security mechanisms.\n\nCompromise of a provisioned private key enables impersonation for the identities and\nrealms authorized for the corresponding public key. Deployments need operational\nprocedures for protecting, rotating, and revoking keys according to local policy.\n\nSchnorr nonces **MUST** be generated with high-quality randomness or by a deterministic\nnonce generation construction with equivalent security. Reusing a Schnorr nonce with the\nsame private scalar can reveal the private scalar.\n\nImplementations **MUST** use constant-time comparison when checking MAC or hash\nresponses and **SHOULD** use constant-time scalar and group operations where provided by\nthe cryptographic library.\n\n## Normative References\n\n- **[RFC2104]** H. Krawczyk, M. Bellare, and R. Canetti, \"HMAC: Keyed-Hashing for\n  Message Authentication\", RFC 2104, DOI 10.17487/RFC2104, February 1997,\n  \u003chttps://www.rfc-editor.org/info/rfc2104\u003e.\n- **[RFC2119]** S. Bradner, \"Key words for use in RFCs to Indicate Requirement Levels\",\n  RFC 2119, DOI 10.17487/RFC2119, March 1997, \u003chttps://www.rfc-editor.org/info/rfc2119\u003e.\n- **[RFC3261]** J. Rosenberg, H. Schulzrinne, G. Camarillo, A. Johnston, J. Peterson, R.\n  Sparks, M. Handley, and E. Schooler, \"SIP: Session Initiation Protocol\", RFC 3261, DOI\n  10.17487/RFC3261, July 2002, \u003chttps://www.rfc-editor.org/info/rfc3261\u003e.\n- **[RFC4648]** S. Josefsson, \"The Base16, Base32, and Base64 Data Encodings\", RFC 4648,\n  DOI 10.17487/RFC4648, October 2006, \u003chttps://www.rfc-editor.org/info/rfc4648\u003e.\n- **[RFC5234]** D. Crocker and P. Overell, \"Augmented BNF for Syntax Specifications:\n  ABNF\", RFC 5234, DOI 10.17487/RFC5234, January 2008,\n  \u003chttps://www.rfc-editor.org/info/rfc5234\u003e.\n- **[RFC5869]** H. Krawczyk and P. Eronen, \"HMAC-based Extract-and-Expand Key Derivation\n  Function (HKDF)\", RFC 5869, DOI 10.17487/RFC5869, May 2010,\n  \u003chttps://www.rfc-editor.org/info/rfc5869\u003e.\n- **[RFC6234]** D. Eastlake 3rd and T. Hansen, \"US Secure Hash Algorithms (SHA and\n  SHA-based HMAC and HKDF)\", RFC 6234, DOI 10.17487/RFC6234, May 2011,\n  \u003chttps://www.rfc-editor.org/info/rfc6234\u003e.\n- **[RFC7748]** A. Langley, M. Hamburg, and S. Turner, \"Elliptic Curves for Security\",\n  RFC 7748, DOI 10.17487/RFC7748, January 2016,\n  \u003chttps://www.rfc-editor.org/info/rfc7748\u003e.\n- **[RFC8174]** B. Leiba, \"Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words\",\n  RFC 8174, DOI 10.17487/RFC8174, May 2017, \u003chttps://www.rfc-editor.org/info/rfc8174\u003e.\n- **[RFC8760]** R. Shekh-Yusef, \"The Session Initiation Protocol (SIP) Digest Access\n  Authentication Scheme\", RFC 8760, DOI 10.17487/RFC8760, March 2020,\n  \u003chttps://www.rfc-editor.org/info/rfc8760\u003e.\n- **[RFC9496]** H. de Valence, J. Grigg, M. Hamburg, I. Lovecruft, G. Tankersley, and F.\n  Valsorda, \"The ristretto255 and decaf448 Groups\", RFC 9496, DOI 10.17487/RFC9496,\n  December 2023, \u003chttps://www.rfc-editor.org/info/rfc9496\u003e.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsippy%2Fsip25519","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsippy%2Fsip25519","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsippy%2Fsip25519/lists"}