<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.43 (Ruby 3.4.9) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-denis-uricrypt-05" category="info" submissionType="independent" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.34.1 -->
  <front>
    <title abbrev="URICrypt">Prefix-Preserving Encryption for URIs</title>
    <seriesInfo name="Internet-Draft" value="draft-denis-uricrypt-05"/>
    <author initials="F." surname="Denis" fullname="Frank Denis">
      <organization>Fastly Inc.</organization>
      <address>
        <email>fde@00f.net</email>
      </address>
    </author>
    <date year="2026"/>
    <keyword>Internet-Draft</keyword>
    <abstract>
      <?line 19?>

<t>This document specifies URICrypt, a deterministic, prefix-preserving
encryption scheme for Uniform Resource Identifiers (URIs). URICrypt
encrypts URI paths while preserving their hierarchical structure,
enabling systems that rely on URI prefix relationships to continue
functioning with encrypted URIs. The scheme provides authenticated
encryption for each URI path component, preventing tampering,
reordering, or mixing of encrypted segments.</t>
    </abstract>
    <note removeInRFC="true">
      <name>Discussion Venues</name>
      <t>Source for this draft and an issue tracker can be found at
    <eref target="https://github.com/jedisct1/draft-denis-uricrypt"/>.</t>
    </note>
  </front>
  <middle>
    <?line 29?>

<section anchor="introduction">
      <name>Introduction</name>
      <t>This document specifies URICrypt, a method for encrypting Uniform
Resource Identifiers (URIs) while preserving their hierarchical
structure. The primary motivation is to enable systems that rely on
URI prefix relationships for routing, filtering, or access control to
continue functioning with encrypted URIs.</t>
      <t>URICrypt achieves prefix preservation through a chained encryption
model where the encryption of each URI component depends
cryptographically on all preceding components. This ensures that URIs
sharing common prefixes produce ciphertexts that also share common
encrypted prefixes.</t>
      <t>The scheme uses an extendable-output function (XOF) as its cryptographic primitive
and provides authenticated encryption for each component, preventing
tampering, reordering, or mixing of encrypted segments. URICrypt is a
reversible encryption scheme: encrypted URIs can be fully decrypted to
recover the original URIs, but only with possession of the secret key.</t>
      <section anchor="use-cases-and-motivations">
        <name>Use Cases and Motivations</name>
        <t>The main motivations include:</t>
        <ul spacing="normal">
          <li>
            <t>Access Control in CDNs: Content Delivery Networks often use URI
prefixes for routing and access control. URICrypt allows encryption of
resource paths while preserving the prefix structure needed for
CDN operations.</t>
          </li>
          <li>
            <t>Privacy-Preserving Logging: Systems can log encrypted URIs
without exposing sensitive path information, while still enabling
analysis based on URI structure.</t>
          </li>
          <li>
            <t>Confidential Data Sharing: When sharing links to sensitive
resources, URICrypt prevents the path structure itself from
revealing confidential information.</t>
          </li>
          <li>
            <t>Token-Based Access Systems: Systems that issue time-limited
access tokens can use URICrypt to obfuscate the underlying
resource location while maintaining routability.</t>
          </li>
          <li>
            <t>Multi-tenant Systems: In systems where multiple tenants share
infrastructure, URICrypt can isolate tenant data while allowing
shared components to be processed efficiently.</t>
          </li>
          <li>
            <t>Privacy-Preserving Analytics: URICrypt can complement IPCrypt
<xref target="I-D.draft-denis-ipcrypt"/>. Together, they enable systems to perform
analytics on encrypted network flows and resource access patterns
without exposing sensitive information about either the network
endpoints or the specific resources being accessed.</t>
          </li>
        </ul>
      </section>
    </section>
    <section anchor="terminology">
      <name>Terminology</name>
      <t>The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”,
“SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and
“OPTIONAL” in this document are to be interpreted as described in BCP
14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all capitals, as
shown here.</t>
      <t>Throughout this document, the following terms and conventions apply:</t>
      <ul spacing="normal">
        <li>
          <t>URI: Uniform Resource Identifier as defined in <xref target="RFC3986"/>.</t>
        </li>
        <li>
          <t>URI Component: A segment of a URI path, terminated by ‘/’, ‘?’, or
‘#’ characters. For encryption purposes, components include the
trailing terminator except for the final component.</t>
        </li>
        <li>
          <t>Scheme: The URI scheme (e.g., “https://”) which is preserved in
plaintext.</t>
        </li>
        <li>
          <t>XOF: Extendable-Output Function, a cryptographic function that can
produce output of arbitrary length.</t>
        </li>
        <li>
          <t>SIV: Synthetic Initialization Vector, a value derived from the
accumulated state of all previous components, used for
authentication and as input to keystream generation.</t>
        </li>
        <li>
          <t>SIVLEN: The length of the Synthetic Initialization Vector in bytes,
defined as 16 bytes (128 bits) for this specification.</t>
        </li>
        <li>
          <t>PADBS: Padding Block Size, the number of bytes to which ciphertext
components are aligned. Defined as 3 bytes for this specification
to ensure efficient Base64url encoding without padding characters.</t>
        </li>
        <li>
          <t>Domain Separation: The practice of using distinct inputs to
cryptographic functions to ensure outputs for different purposes
are not compatible.</t>
        </li>
        <li>
          <t>Prefix-preserving Encryption: An encryption scheme where, if two
plaintexts share a common prefix, their corresponding ciphertexts
also share a common (encrypted) prefix.</t>
        </li>
        <li>
          <t>Chained Encryption: A mode where encryption of each component
depends cryptographically on all preceding components.</t>
        </li>
      </ul>
    </section>
    <section anchor="uri-processing">
      <name>URI Processing</name>
      <t>This section describes how URIs are processed for encryption and
decryption.</t>
      <t>The overall encryption flow transforms a plaintext URI into an encrypted
URI while preserving its hierarchical structure:</t>
      <artwork><![CDATA[
+-------------------------------------------------------------+
|                         Input URI                           |
|          "https://example.com/path/to/resource"             |
+-------------------------------------------------------------+
                              |
                              v
+-------------------------------------------------------------+
|                    URI Decomposition                        |
+-------------------------------------------------------------+
|  Scheme: "https://"                                         |
|  Components: ["example.com/", "path/", "to/", "resource"]   |
+-------------------------------------------------------------+
                              |
                              v
+-------------------------------------------------------------+
|                 Chained Encryption Process                  |
+-------------------------------------------------------------+
|  For each component in sequence:                            |
|    1. Update state with plaintext                           |
|    2. Generate SIV from accumulated state                   |
|    3. Derive keystream using SIV                            |
|    4. Encrypt component with keystream                      |
|    5. Output: SIV || encrypted_component                    |
+-------------------------------------------------------------+
                              |
                              v
+-------------------------------------------------------------+
|                    Encoding & Assembly                      |
+-------------------------------------------------------------+
|  1. Concatenate all (SIV || encrypted_component) pairs      |
|  2. Apply base64url encoding                                |
|  3. Prepend original scheme                                 |
+-------------------------------------------------------------+
                              |
                              v
+-------------------------------------------------------------+
|                       Encrypted URI                         |
|          "https://HOGo9vauZ3b3xsPNPQng5apS..."              |
+-------------------------------------------------------------+
]]></artwork>
      <section anchor="uri-component-extraction">
        <name>URI Component Extraction</name>
        <t>Before encryption, a URI must be split into its scheme and path
components. The path is further divided into individual components for
chained encryption. Components are terminated by ‘/’, ‘?’, or ‘#’
characters, which allows proper handling of query strings and fragments.</t>
        <section anchor="full-uris">
          <name>Full URIs</name>
          <t>For a full URI including a scheme:</t>
          <artwork><![CDATA[
Input:  "https://example.com/a/b/c"

Components:

- Scheme: "https://"
- Component 1: "example.com/"
- Component 2: "a/"
- Component 3: "b/"
- Component 4: "c"
]]></artwork>
          <t>For a URI with query parameters:</t>
          <artwork><![CDATA[
Input:  "https://example.com/path?foo=bar&baz=qux"

Components:

- Scheme: "https://"
- Component 1: "example.com/"
- Component 2: "path?"
- Component 3: "foo=bar&baz=qux"
]]></artwork>
          <t>For a URI with a fragment:</t>
          <artwork><![CDATA[
Input:  "https://example.com/path#section"

Components:

- Scheme: "https://"
- Component 1: "example.com/"
- Component 2: "path#"
- Component 3: "section"
]]></artwork>
          <t>Note that all components except the last include their trailing terminator
character (‘/’, ‘?’, or ‘#’). This ensures proper reconstruction during decryption.</t>
        </section>
        <section anchor="path-only-uris">
          <name>Path-Only URIs</name>
          <t>For absolute paths (URIs starting with ‘/’ but without a scheme), the
leading ‘/’ is treated as the first component:</t>
          <artwork><![CDATA[
Input:  "/a/b/c"

Components:

- Scheme: "" (empty)
- Component 1: "/"
- Component 2: "a/"
- Component 3: "b/"
- Component 4: "c"
]]></artwork>
          <t>For a path with query parameters:</t>
          <artwork><![CDATA[
Input:  "/path/to/file?param=value"

Components:

- Scheme: "" (empty)
- Component 1: "/"
- Component 2: "path/"
- Component 3: "to/"
- Component 4: "file?"
- Component 5: "param=value"
]]></artwork>
          <t>The leading ‘/’ is explicitly encrypted as a component to maintain
consistency and enable proper prefix preservation for absolute paths.</t>
          <t>This character receives its own SIV and is encrypted, ensuring that the
root path is authenticated like any other path component and that
different keys and contexts produce different ciphertexts for that path,
consistent with other paths.</t>
          <t>In applications where all paths are guaranteed to be absolute and the <tt>'/'</tt> path
can be considered a special case, ciphertext expansion can be reduced by
removing the leading <tt>'/'</tt> character from the URI prior to encryption,
treating the path as relative with <tt>'/'</tt> as implicit.</t>
        </section>
      </section>
      <section anchor="component-reconstruction">
        <name>Component Reconstruction</name>
        <t>During decryption, components are joined to reconstruct the original
path:</t>
        <artwork><![CDATA[
Components: ["example.com/", "a/", "b/", "c"]
Reconstructed Path: "example.com/a/b/c"

When combined with the scheme: "https://example.com/a/b/c"
]]></artwork>
        <t>For absolute paths without a scheme:</t>
        <artwork><![CDATA[
Components: ["/", "a/", "b/", "c"]
Reconstructed Path: "/a/b/c"
]]></artwork>
      </section>
    </section>
    <section anchor="cryptographic-operations">
      <name>Cryptographic Operations</name>
      <t>The chained encryption model creates cryptographic dependencies between components, ensuring prefix preservation.</t>
      <artwork><![CDATA[
  URI: "https://example.com/path/to/resource"

  +-------------------+
  |   Component 1:    |
  |  "example.com/"   |
  +-------------------+
            |
            | Plaintext absorbed into components_xof
            v
  +-------------------+
  | SIV1 generation   |------> SIV1 (SIVLEN bytes)
  +-------------------+         |
                                |
                                v
                      Encrypt("example.com/")
                                |
                                v
                      Output1 = SIV1 || Ciphertext1
            |
            | State carries forward
            v
  +-------------------+
  |   Component 2:    |
  |     "path/"       |
  +-------------------+
            |
            | Plaintext absorbed (includes Component 1 state)
            v
  +-------------------+
  | SIV2 generation   |------> SIV2 (depends on 1)
  +-------------------+         |
                                |
                                v
                      Encrypt("path/")
                                |
                                v
                      Output2 = SIV2 || Ciphertext2
            |
            | State carries forward
            v
  +-------------------+
  |   Component 3:    |
  |      "to/"        |
  +-------------------+
            |
            | Plaintext absorbed (includes 1 + 2 state)
            v
  +-------------------+
  | SIV3 generation   |------> SIV3 (depends on 1, 2)
  +-------------------+         |
                                |
                                v
                      Encrypt("to/")
                                |
                                v
                      Output3 = SIV3 || Ciphertext3
            |
            | State carries forward
            v
  +-------------------+
  |   Component 4:    |
  |    "resource"     |
  +-------------------+
            |
            | Plaintext absorbed (includes 1 + 2 + 3 state)
            v
  +-------------------+
  | SIV4 generation   |------> SIV4 (depends on 1, 2, 3)
  +-------------------+         |
                                |
                                v
                      Encrypt("resource")
                                |
                                v
                      Output4 = SIV4 || Ciphertext4

  Final Output: Output1 || Output2 || Output3 || Output4
]]></artwork>
      <t>If URIs share a common prefix <tt>example.com/path/</tt>, their <tt>Output1</tt> and <tt>Output2</tt> will be identical.</t>
      <section anchor="xof-init">
        <name>XOF Initialization</name>
        <t>The base XOF is initialized with the secret key and context
parameters using length-prefixed encoding to prevent ambiguities.</t>
        <t>Two XOF instances are derived from the base XOF:</t>
        <ol spacing="normal" type="1"><li>
            <t>Components XOF: Updated with each component’s plaintext to
generate SIVs</t>
          </li>
          <li>
            <t>Base Keystream XOF: Used as the starting point for generating
keystream for each component</t>
          </li>
        </ol>
        <artwork><![CDATA[
  Input: len(key) || key || len(context) || context

  +-----------------------------------------------------+
  | base_xof = TurboSHAKE128(domain_sep=0x1F)           |
  | base_xof.update(len(secret_key))                    |
  | base_xof.update(secret_key)                         |
  | base_xof.update(len(context))                       |
  | base_xof.update(context)                            |
  +-----------------------------------------------------+
                            |
                            v
               +------------------------+
               |   Clone Base State     |
               +------------------------+
                            |
           +----------------+----------------+
           v                                 v
  +--------------------+          +--------------------+
  |  Components XOF    |          | Base Keystream XOF |
  +--------------------+          +--------------------+
  |   update("IV")     |          |   update("KS")     |
  +--------------------+          +--------------------+
           |                                 |
           |                                 |
           v                                 v
   For SIV Generation              For Keystream Base
   (Updated with each              (Cloned for each
    component plaintext)            component's keystream)
]]></artwork>
        <t>The initialization process is:</t>
        <artwork><![CDATA[
base_xof = TurboSHAKE128()
base_xof.update(len(secret_key))
base_xof.update(secret_key)
base_xof.update(len(context))
base_xof.update(context)

components_xof = base_xof.clone()
components_xof.update("IV")

base_keystream_xof = base_xof.clone()
base_keystream_xof.update("KS")
]]></artwork>
        <t>Note on XOF cloning: The <tt>.clone()</tt> operation creates a new XOF instance with
an identical internal state, preserving all previously absorbed data. After
cloning, the original and cloned XOFs can be updated and read from
independently. This allows the <tt>components_xof</tt> to maintain a running state
across all components while <tt>base_keystream_xof</tt> remains unchanged for creating
per-component keystreams.</t>
      </section>
      <section anchor="component-encryption">
        <name>Component Encryption</name>
        <t>For each component, the encryption process follows a precise sequence
that ensures both confidentiality and authenticity:</t>
        <ol spacing="normal" type="1"><li>
            <t>Update <tt>components_xof</tt> with the component plaintext</t>
          </li>
          <li>
            <t>Squeeze the SIV from <tt>components_xof</tt> (<tt>SIVLEN</tt> bytes). This requires cloning <tt>components_xof</tt> before reading, as reading may finalize the XOF.</t>
          </li>
          <li>
            <t>Create <tt>keystream_xof</tt> by cloning <tt>base_keystream_xof</tt> and updating it with SIV</t>
          </li>
          <li>
            <t>Calculate padding needed for base64 encoding</t>
          </li>
          <li>
            <t>Generate a keystream of length <tt>(component_length + padding)</tt></t>
          </li>
          <li>
            <t>XOR the padded component with the keystream</t>
          </li>
          <li>
            <t>Output SIV concatenated with <tt>encrypted_component</tt></t>
          </li>
        </ol>
        <t>The padding ensures clean base64url encoding without padding characters. Since
base64 encoding works with groups of 3 bytes (producing 4 characters), we pad each
<tt>(SIV || encrypted_component)</tt> pair to have a length that’s a multiple of PADBS:</t>
        <sourcecode type="pseudocode"><![CDATA[
total_bytes = SIVLEN (SIV) + component_len
padding_len = (PADBS - total_bytes % PADBS) % PADBS
]]></sourcecode>
        <t>This formula calculates:</t>
        <ul spacing="normal">
          <li>
            <t>How many bytes are needed to reach the next multiple of PADBS</t>
          </li>
          <li>
            <t>The outer modulo handles the case where <tt>total_bytes</tt> is already a multiple of PADBS</t>
          </li>
        </ul>
        <t>The <tt>components_xof</tt> maintains state across all components.
After generating the SIV for component <tt>N</tt>, the XOF can be updated with component <tt>N+1</tt>’s
plaintext. This chaining ensures that each component’s encryption depends on
all previous components, thus enabling the prefix-preserving property.</t>
      </section>
      <section anchor="component-decryption">
        <name>Component Decryption</name>
        <t>For each encrypted component, the decryption process is:</t>
        <ol spacing="normal" type="1"><li>
            <t>Read SIV from input (<tt>SIVLEN</tt> bytes)</t>
          </li>
          <li>
            <t>Create <tt>keystream_xof</tt> by cloning <tt>base_keystream_xof</tt> and updating it with SIV</t>
          </li>
          <li>
            <t>Decrypt bytes incrementally to determine component boundaries:
            </t>
            <ul spacing="normal">
              <li>
                <t>Generate keystream bytes one at a time from the XOF</t>
              </li>
              <li>
                <t>XOR each encrypted byte with its corresponding keystream byte</t>
              </li>
              <li>
                <t>Check each decrypted byte for component terminators (<tt>'/'</tt>, <tt>'?'</tt>, <tt>'#'</tt>)</t>
              </li>
              <li>
                <t>When a terminator is found, the component is complete.</t>
              </li>
              <li>
                <t>Skip any padding bytes (null bytes) after the component</t>
              </li>
            </ul>
          </li>
          <li>
            <t>Update <tt>components_xof</tt> with the complete plaintext component (including terminator)</t>
          </li>
          <li>
            <t>Generate the expected SIV from <tt>components_xof</tt></t>
          </li>
          <li>
            <t>Compare the expected SIV with the received SIV (constant-time)</t>
          </li>
          <li>
            <t>If mismatch, return <tt>error</tt></t>
          </li>
        </ol>
        <section anchor="component-boundary-detection">
          <name>Component Boundary Detection</name>
          <t>During decryption, component boundaries are discovered dynamically by examining the decrypted plaintext:</t>
          <ul spacing="normal">
            <li>
              <t>Each component (except possibly the last) ends with a terminator character (<tt>'/'</tt>, <tt>'?'</tt>, or <tt>'#'</tt>)</t>
            </li>
            <li>
              <t>When a terminator is encountered, we know the component is complete</t>
            </li>
            <li>
              <t>After finding the terminator, we skip padding bytes to align to the next PADBS-byte boundary.</t>
            </li>
            <li>
              <t>The padding length can be calculated: <tt>padding = (PADBS - ((SIVLEN + bytes_read) % PADBS)) % PADBS</tt></t>
            </li>
          </ul>
          <t>This approach eliminates the need for explicit length encoding, as the component structure itself provides the necessary boundary information.</t>
          <t>Any tampering with the encrypted data will cause the SIV comparison to fail.</t>
        </section>
      </section>
      <section anchor="padding-and-encoding">
        <name>Padding and Encoding</name>
        <t>To enable clean base64url encoding without padding characters (‘=’), each
encrypted component pair <tt>(SIV || ciphertext)</tt> is padded to be a multiple of PADBS bytes.
This is necessary because base64 encoding processes 3 bytes at a time to produce
4 characters of output.</t>
        <t>The padding calculation <tt>(PADBS - (SIVLEN + component_len) % PADBS) % PADBS</tt> ensures the following:</t>
        <ul spacing="normal">
          <li>
            <t>If <tt>(SIVLEN + component_len) % PADBS = 0</tt>: no padding needed (already aligned)</t>
          </li>
          <li>
            <t>If <tt>(SIVLEN + component_len) % PADBS = 1</tt>: add 2 bytes of padding</t>
          </li>
          <li>
            <t>If <tt>(SIVLEN + component_len) % PADBS = 2</tt>: add 1 byte of padding</t>
          </li>
        </ul>
        <t>With the default value of <tt>PADBS=3</tt>, this padding scheme provides partial length-hiding.
For example, with <tt>SIVLEN=16</tt>, components “abc”, “abcd”, and “abcde” all produce 21-byte
outputs after padding. Without the secret key, a passive adversary cannot determine
the exact original component size.</t>
        <t>The final output is encoded using URL-safe base64 <xref target="RFC4648"/>, with ‘-‘ replacing
‘+’ and ‘_’ replacing ‘/’ for URI compatibility.</t>
        <t>Note: Encrypted URIs may contain slash characters (‘/’) at arbitrary locations
in the base64-encoded ciphertext portion (i.e., after the scheme for full URIs,
or after the leading ‘/’ for path-only URIs). These slashes may or may not
correspond to the original URI structure and serve aesthetic or structural
purposes only. They are not part of the encrypted data. During decryption, all
slashes within the ciphertext must be removed before base64 decoding.</t>
        <t>For example, these are equivalent encrypted representations:
- <tt>https://ABC123def456GHI789</tt>
- <tt>https://ABC123/def456/GHI789</tt>
- <tt>https://ABC/123/def/456/GHI/789</tt></t>
        <t>All three would be decoded identically by removing slashes to produce
<tt>ABC123def456GHI789</tt> before base64 decoding.</t>
      </section>
    </section>
    <section anchor="algorithm-specification">
      <name>Algorithm Specification</name>
      <t>This section provides the complete algorithms for encryption and
decryption. The following functions and operations are used throughout
the algorithms:</t>
      <ul spacing="normal">
        <li>
          <t><tt>TurboSHAKE128()</tt>: Creates a new TurboSHAKE128 XOF instance with domain separation parameter 0x1F. This function produces an extensible output function (XOF) that can generate arbitrary-length outputs.</t>
        </li>
        <li>
          <t><tt>.update(data)</tt>: Absorbs the provided data into the XOF state. Data is processed sequentially and updates the internal state of the XOF.</t>
        </li>
        <li>
          <t><tt>.read(length)</tt>: Squeezes the specified number of bytes from the XOF’s output. Each call continues from where the previous read left off, producing a continuous stream of pseudorandom bytes.</t>
        </li>
        <li>
          <t><tt>.clone()</tt>: Creates a new XOF instance with an identical internal state to the original. This enables multiple independent computation paths from the same initial state.</t>
        </li>
        <li>
          <t>XOR operation: The bitwise exclusive OR operation between two byte sequences of equal length. This operation is used to combine plaintext with keystream for encryption, and ciphertext with keystream for decryption.</t>
        </li>
        <li>
          <t><tt>base64url_encode(data)</tt>: Converts binary data to a base64 string using URL-safe encoding (replacing ‘+’ with ‘-‘ and ‘/’ with ‘_’) and omitting padding characters.</t>
        </li>
        <li>
          <t><tt>base64url_decode(string)</tt>: Converts a URL-safe base64 string back to binary data, automatically handling the absence of padding characters.</t>
        </li>
        <li>
          <t><tt>Stream(data)</tt>: Creates a sequential reader for binary data, enabling byte-by-byte or block-based access to the contents.</t>
        </li>
        <li>
          <t><tt>constant_time_compare(a, b)</tt>: Compares two byte sequences in constant time, regardless of their contents. This prevents timing attacks by ensuring the comparison duration does not depend on which bytes differ.</t>
        </li>
        <li>
          <t><tt>len(data)</tt>: Returns the length of the provided data in bytes.</t>
        </li>
        <li>
          <t>Concatenation: The operation of joining two byte sequences end-to-end to form a single sequence.</t>
        </li>
        <li>
          <t><tt>zeros(count)</tt>: Generates a sequence of zero-valued bytes of the specified length, used for padding.</t>
        </li>
        <li>
          <t><tt>remove_padding(data)</tt>: Removes trailing zero bytes from a byte sequence to recover the original data length.</t>
        </li>
        <li>
          <t><tt>join(components)</tt>: Combines multiple path components into a single path string, preserving the terminator characters (<tt>'/'</tt>, <tt>'?'</tt>, <tt>'#'</tt>) that are included in each component.</t>
        </li>
      </ul>
      <section anchor="encryption-algorithm">
        <name>Encryption Algorithm</name>
        <t>Input: secret_key, context, uri_string</t>
        <t>Output: encrypted_uri</t>
        <t>Steps:</t>
        <ol spacing="normal" type="1"><li>
            <t>Split URI into scheme and components</t>
          </li>
          <li>
            <t>Initialize XOF instances as described in <xref target="xof-init"/></t>
          </li>
          <li>
            <t><tt>encrypted_output = empty byte array</tt></t>
          </li>
          <li>
            <t>For each component:
            </t>
            <ul spacing="normal">
              <li>
                <t>Update <tt>components_xof</tt> with <tt>component</tt></t>
              </li>
              <li>
                <t><tt>SIV = components_xof.clone().read(SIVLEN)</tt></t>
              </li>
              <li>
                <t><tt>keystream_xof = base_keystream_xof.clone()</tt></t>
              </li>
              <li>
                <t><tt>keystream_xof.update(SIV)</tt></t>
              </li>
              <li>
                <t><tt>padding_len = (PADBS - (SIVLEN + len(component)) % PADBS) % PADBS</tt></t>
              </li>
              <li>
                <t><tt>keystream = keystream_xof.read(len(component) + padding_len)</tt></t>
              </li>
              <li>
                <t><tt>padded_component = component concatenated with zeros(padding_len)</tt></t>
              </li>
              <li>
                <t><tt>encrypted_part = padded_component XOR keystream</tt></t>
              </li>
              <li>
                <t><tt>encrypted_output = encrypted_output concatenated with SIV concatenated with encrypted_part</tt></t>
              </li>
            </ul>
          </li>
          <li>
            <t><tt>base64_output = base64url_encode(encrypted_output)</tt></t>
          </li>
          <li>
            <t>If scheme is not empty: Return <tt>scheme + base64_output</tt></t>
          </li>
          <li>
            <t>Else if original URI started with ‘/’: Return <tt>'/' + base64_output</tt></t>
          </li>
          <li>
            <t>Else: Return <tt>base64_output</tt></t>
          </li>
        </ol>
      </section>
      <section anchor="decryption-algorithm">
        <name>Decryption Algorithm</name>
        <t>Input: secret_key, context, encrypted_uri</t>
        <t>Output: decrypted_uri or error</t>
        <t>Note: For path-only URIs (those starting with ‘/’), the output format is:
- ‘/’ followed by the base64url-encoded encrypted components
- This preserves the absolute path indicator in the encrypted form</t>
        <t>Steps:</t>
        <ol spacing="normal" type="1"><li>
            <t>Split encrypted URI into scheme and base64 part</t>
          </li>
          <li>
            <t>Remove all slash characters (‘/’) from the base64 part (the encrypted ciphertext after the scheme). These slashes may appear at arbitrary locations for aesthetic or structural purposes but are not part of the encrypted data.</t>
          </li>
          <li>
            <t><tt>decoded = base64url_decode(base64_part)</tt> If decoding fails, return <tt>error</tt></t>
          </li>
          <li>
            <t>Initialize XOF instances as described in <xref target="xof-init"/></t>
          </li>
          <li>
            <t><tt>decrypted_components = empty list</tt></t>
          </li>
          <li>
            <t><tt>position = 0</tt></t>
          </li>
          <li>
            <t>While <tt>position &lt; len(decoded)</tt>:
            </t>
            <ul spacing="normal">
              <li>
                <t><tt>SIV = decoded[position:position+SIVLEN]</tt> If not enough bytes, return <tt>error</tt></t>
              </li>
              <li>
                <t><tt>keystream_xof = base_keystream_xof.clone()</tt></t>
              </li>
              <li>
                <t><tt>keystream_xof.update(SIV)</tt></t>
              </li>
              <li>
                <t><tt>component_start = position + SIVLEN</tt></t>
              </li>
              <li>
                <t><tt>component = empty byte array</tt></t>
              </li>
              <li>
                <t><tt>position = position + SIVLEN</tt></t>
              </li>
              <li>
                <t>While <tt>position &lt; len(decoded)</tt>:
                </t>
                <ul spacing="normal">
                  <li>
                    <t><tt>decrypted_byte = decoded[position] XOR keystream_xof.read(1)</tt></t>
                  </li>
                  <li>
                    <t><tt>position = position + 1</tt></t>
                  </li>
                  <li>
                    <t>If <tt>decrypted_byte == 0x00</tt>: continue (skip padding)</t>
                  </li>
                  <li>
                    <t><tt>component.append(decrypted_byte)</tt></t>
                  </li>
                  <li>
                    <t>If <tt>decrypted_byte</tt> is <tt>'/'</tt>, <tt>'?'</tt>, or <tt>'#'</tt>:
                    </t>
                    <ul spacing="normal">
                      <li>
                        <t><tt>total_len = position - component_start</tt></t>
                      </li>
                      <li>
                        <t><tt>position = position + ((PADBS - ((SIVLEN + total_len) % PADBS)) % PADBS)</tt></t>
                      </li>
                      <li>
                        <t>Break inner loop</t>
                      </li>
                    </ul>
                  </li>
                </ul>
              </li>
              <li>
                <t>Update <tt>components_xof</tt> with <tt>component</tt></t>
              </li>
              <li>
                <t><tt>expected_SIV = components_xof.clone().read(SIVLEN)</tt></t>
              </li>
              <li>
                <t>If <tt>constant_time_compare(SIV, expected_SIV) == false</tt>, return <tt>error</tt></t>
              </li>
              <li>
                <t><tt>decrypted_components.append(component)</tt></t>
              </li>
            </ul>
          </li>
          <li>
            <t><tt>decrypted_path = join(decrypted_components)</tt></t>
          </li>
          <li>
            <t>Return <tt>scheme + decrypted_path</tt></t>
          </li>
        </ol>
      </section>
    </section>
    <section anchor="implementation-details">
      <name>Implementation Details</name>
      <section anchor="turboshake128-usage">
        <name>TurboSHAKE128 Usage</name>
        <t>Implementations MUST use TurboSHAKE128 with a domain separation
parameter of <tt>0x1F</tt> for all operations. The TurboSHAKE128 XOF is used
for:</t>
        <ul spacing="normal">
          <li>
            <t>Generating SIVs from the components XOF</t>
          </li>
          <li>
            <t>Generating keystream for encryption/decryption</t>
          </li>
          <li>
            <t>All XOF operations in the initialization</t>
          </li>
        </ul>
        <t>TurboSHAKE128 is specified in <xref target="RFC9861"/> and provides the security
properties needed for this construction.</t>
      </section>
      <section anchor="key-and-context-handling">
        <name>Key and Context Handling</name>
        <t>The secret key MUST be at least <tt>SIVLEN</tt> bytes long. Keys shorter than <tt>SIVLEN</tt>
bytes MUST be rejected. Implementations SHOULD validate that the key
does not consist of repeated patterns (e.g., identical first and
second halves) as a best practice.</t>
        <t>The context parameter is a string that provides domain separation.
Different applications SHOULD use different context strings to prevent
cross-application attacks. The context string MAY be empty.</t>
        <t>Both key and context are length-prefixed when absorbed into the base
XOF:</t>
        <sourcecode type="pseudocode"><![CDATA[
base_xof.update(len(secret_key) as uint8)
base_xof.update(secret_key)
base_xof.update(len(context) as uint8)
base_xof.update(context)
]]></sourcecode>
        <t>The length is encoded as a single byte, limiting keys and contexts to
255 bytes. This is sufficient for all practical use cases.</t>
      </section>
      <section anchor="error-handling">
        <name>Error Handling</name>
        <t>Implementations MUST NOT reveal the cause of decryption failures. All
error conditions (invalid base64, incorrect padding, SIV mismatch,
insufficient data) MUST result in identical, generic error messages.</t>
        <t>SIV comparison MUST be performed in constant-time to prevent timing
attacks.</t>
      </section>
    </section>
    <section anchor="security-guarantees">
      <name>Security Guarantees</name>
      <t>URICrypt provides the following cryptographic security guarantees:</t>
      <section anchor="confidentiality">
        <name>Confidentiality</name>
        <t>URICrypt achieves semantic security for URI path components through its use of TurboSHAKE128 as a pseudorandom function. Each component is encrypted using a unique keystream derived from the following:</t>
        <ul spacing="normal">
          <li>
            <t>The secret key</t>
          </li>
          <li>
            <t>The application context</t>
          </li>
          <li>
            <t>A synthetic initialization vector (SIV) that depends on all preceding components</t>
          </li>
        </ul>
        <t>This construction ensures that:</t>
        <ul spacing="normal">
          <li>
            <t>An attacker without the secret key cannot recover plaintext components from ciphertexts.</t>
          </li>
          <li>
            <t>The keystream generation is computationally indistinguishable from random for each unique (key, context, path-prefix) tuple.</t>
          </li>
          <li>
            <t>Components are protected by at least 128 bits of security against brute-force attacks.</t>
          </li>
        </ul>
      </section>
      <section anchor="authenticity-and-integrity">
        <name>Authenticity and Integrity</name>
        <t>Each URI component is authenticated through the SIV mechanism:</t>
        <ul spacing="normal">
          <li>
            <t>The SIV acts as a Message Authentication Code (MAC) computed over the component and all preceding components.</t>
          </li>
          <li>
            <t>Any modification to a component will cause the SIV verification to fail during decryption.</t>
          </li>
          <li>
            <t>The chained construction ensures that reordering, insertion, or deletion of components is detected.</t>
          </li>
          <li>
            <t>Authentication provides 128-bit security against forgery attempts.</t>
          </li>
        </ul>
      </section>
      <section anchor="prefix-preserving-property">
        <name>Prefix-Preserving Property</name>
        <t>URICrypt maintains a controlled information leakage pattern:</t>
        <ul spacing="normal">
          <li>
            <t>URIs sharing a common prefix will produce ciphertexts with the same encrypted prefix.</t>
          </li>
          <li>
            <t>This property is deterministic and intentional, enabling systems to perform prefix-based operations.</t>
          </li>
          <li>
            <t>The leakage is limited to prefix structure only—no information about non-matching suffixes is revealed.</t>
          </li>
        </ul>
      </section>
      <section anchor="domain-separation">
        <name>Domain Separation</name>
        <t>The context parameter provides cryptographic domain separation:</t>
        <ul spacing="normal">
          <li>
            <t>Different contexts with the same key produce completely independent ciphertexts.</t>
          </li>
          <li>
            <t>This prevents cross-context attacks where ciphertexts from one application could be used in another.</t>
          </li>
          <li>
            <t>Context binding is cryptographically enforced through the XOF initialization.</t>
          </li>
        </ul>
      </section>
      <section anchor="key-commitment">
        <name>Key Commitment</name>
        <t>URICrypt provides full key-commitment security.</t>
        <t>The scheme is fully key-committing, meaning that a ciphertext can only be decrypted with the exact key that was used to encrypt it. It is computationally infeasible to find two different keys that successfully decrypt the same ciphertext to valid plaintexts.</t>
      </section>
      <section anchor="resistance-to-common-attacks">
        <name>Resistance to Common Attacks</name>
        <t>URICrypt resists several categories of attacks:</t>
        <t>Chosen-plaintext Attacks (CPA): While deterministic, URICrypt is CPA-secure for unique inputs. The determinism is a design requirement for prefix preservation.</t>
        <t>Tampering Detection: Any bit flip, truncation, or modification in the ciphertext will be detected with overwhelming probability (1 - 2<sup>-128</sup>).</t>
        <t>Length-extension Attacks: The use of length-prefixed encoding and domain separation prevents length-extension attacks.</t>
        <t>Replay Attacks: Within a single (key, context) pair, replay is possible due to determinism. Applications requiring replay protection should incorporate timestamps or nonces into the context.</t>
        <t>Key Recovery: TurboSHAKE128’s security properties ensure that observing ciphertexts does not leak information about the secret key.</t>
      </section>
      <section anchor="security-bounds">
        <name>Security Bounds</name>
        <t>The security of URICrypt is bounded by the following:</t>
        <ul spacing="normal">
          <li>
            <t>Key strength: Minimum 128-bit security with <tt>SIVLEN</tt>-byte keys</t>
          </li>
          <li>
            <t>Collision resistance: 2<sup>64</sup> birthday bound for SIV collisions</t>
          </li>
          <li>
            <t>Authentication security: 2<sup>-128</sup> probability of successful forgery</t>
          </li>
          <li>
            <t>Computational security: Based on TurboSHAKE128’s proven security as an XOF</t>
          </li>
        </ul>
      </section>
      <section anchor="limitations-and-trade-offs">
        <name>Limitations and Trade-offs</name>
        <t>URICrypt makes specific security trade-offs for functionality, including the following:</t>
        <ul spacing="normal">
          <li>
            <t>Deterministic encryption: Same inputs produce same outputs, enabling certain traffic analysis</t>
          </li>
          <li>
            <t>Partial length obfuscation: With <tt>PADBS=3</tt>, exact component lengths are partially hidden</t>
          </li>
          <li>
            <t>Prefix structure leakage: The hierarchical structure of URIs is preserved by design</t>
          </li>
          <li>
            <t>SIV length configuration: Implementations MAY adjust <tt>SIVLEN</tt> for different usage bounds. Larger values (24 or 32 bytes) increase birthday bound resistance at the cost of ciphertext expansion. However, 16 bytes is generally recommended as it provides practical collision resistance with acceptable overhead</t>
          </li>
          <li>
            <t>Padding block size configuration: The default <tt>PADBS=3</tt> already provides partial length-hiding. Implementations MAY adjust <tt>PADBS</tt> to increase size obfuscation. Larger values create larger size buckets but increase ciphertext expansion. The value MUST remain a multiple of 3 to ensure efficient Base64url encoding without padding characters</t>
          </li>
        </ul>
        <t>These trade-offs are intentional and necessary for the prefix-preserving functionality. Applications requiring stronger privacy guarantees should evaluate whether URICrypt’s properties align with their threat model.</t>
      </section>
    </section>
    <section anchor="security-considerations">
      <name>Security Considerations</name>
      <t>URICrypt provides confidentiality and integrity for URI paths while
preserving prefix relationships. The encryption is fully reversible:
encrypted URIs can be decrypted to recover the original plaintext URIs,
but only with knowledge of the secret key. The security properties depend on:</t>
      <ul spacing="normal">
        <li>
          <t>Key Secrecy: The security of URICrypt depends entirely on the
secrecy of the secret key. Keys MUST be generated using a
cryptographically secure random number generator <xref target="RFC4086"/> and
stored securely.</t>
        </li>
        <li>
          <t>Deterministic Encryption: URICrypt is deterministic - identical
inputs produce identical outputs. This allows observers to detect
when the same URI is encrypted multiple times. Applications
requiring unlinkability SHOULD incorporate additional entropy (e.g.,
via the context parameter).</t>
        </li>
        <li>
          <t>Prefix Preservation: While essential for functionality, prefix
preservation leaks information about URI structure. Systems where
this information is sensitive SHOULD consider alternative
approaches.</t>
        </li>
        <li>
          <t>Context Separation: The context parameter prevents cross-context
attacks. Applications MUST use distinct contexts for different
purposes, even when sharing keys.</t>
        </li>
        <li>
          <t>Component Authentication: Each component is authenticated via
the SIV mechanism. Any modification, reordering, or truncation of
components will be detected during decryption.</t>
        </li>
        <li>
          <t>Length Obfuscation: The default <tt>PADBS=3</tt> configuration provides partial
length-hiding. Applications requiring stronger length-hiding
SHOULD consider using larger <tt>PADBS</tt> values or padding components to fixed lengths.</t>
        </li>
        <li>
          <t>Key Reuse: Using the same key with different contexts is safe, but
using the same (key, context) pair for different applications is
NOT RECOMMENDED.</t>
        </li>
      </ul>
    </section>
    <section numbered="false" anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>This document has no actions for IANA.</t>
    </section>
    <section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>The author would like to thank Maciej Soltysiak for highlighting the importance of properly supporting query parameters and fragments in URI encryption.</t>
    </section>
  </middle>
  <back>
    <references anchor="sec-normative-references">
      <name>Normative References</name>
      <reference anchor="I-D.draft-denis-ipcrypt">
        <front>
          <title>Methods for IP Address Encryption and Obfuscation</title>
          <author fullname="Christopher Barber" initials="C." surname="Barber">
            <organization>Trim</organization>
          </author>
          <author fullname="Frank Denis" initials="F." surname="Denis">
            <organization>Fastly Inc.</organization>
          </author>
          <date day="24" month="August" year="2026"/>
          <abstract>
            <t>   This document specifies secure, efficient methods for Internet
   Protocol (IP) address encryption and obfuscation in privacy-
   preserving storage, logging, and analytics.  Unlike truncation, which
   destroys data irreversibly, these methods are reversible with the
   encryption key while providing strong privacy guarantees.

   Four modes are defined: ipcrypt-deterministic (format-preserving, IP-
   address output), ipcrypt-pfx (prefix-preserving, native address
   size), ipcrypt-nd and ipcrypt-ndx (non-deterministic with random
   tweaks).  All support high-performance processing at network speeds
   and produce interoperable results across implementations.

            </t>
          </abstract>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-denis-ipcrypt-14"/>
      </reference>
      <reference anchor="RFC2119">
        <front>
          <title>Key words for use in RFCs to Indicate Requirement Levels</title>
          <author fullname="S. Bradner" initials="S." surname="Bradner"/>
          <date month="March" year="1997"/>
          <abstract>
            <t>In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
          </abstract>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="2119"/>
        <seriesInfo name="DOI" value="10.17487/RFC2119"/>
      </reference>
      <reference anchor="RFC8174">
        <front>
          <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
          <author fullname="B. Leiba" initials="B." surname="Leiba"/>
          <date month="May" year="2017"/>
          <abstract>
            <t>RFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.</t>
          </abstract>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="8174"/>
        <seriesInfo name="DOI" value="10.17487/RFC8174"/>
      </reference>
      <reference anchor="RFC3986">
        <front>
          <title>Uniform Resource Identifier (URI): Generic Syntax</title>
          <author fullname="T. Berners-Lee" initials="T." surname="Berners-Lee"/>
          <author fullname="R. Fielding" initials="R." surname="Fielding"/>
          <author fullname="L. Masinter" initials="L." surname="Masinter"/>
          <date month="January" year="2005"/>
          <abstract>
            <t>A Uniform Resource Identifier (URI) is a compact sequence of characters that identifies an abstract or physical resource. This specification defines the generic URI syntax and a process for resolving URI references that might be in relative form, along with guidelines and security considerations for the use of URIs on the Internet. The URI syntax defines a grammar that is a superset of all valid URIs, allowing an implementation to parse the common components of a URI reference without knowing the scheme-specific requirements of every possible identifier. This specification does not define a generative grammar for URIs; that task is performed by the individual specifications of each URI scheme. [STANDARDS-TRACK]</t>
          </abstract>
        </front>
        <seriesInfo name="STD" value="66"/>
        <seriesInfo name="RFC" value="3986"/>
        <seriesInfo name="DOI" value="10.17487/RFC3986"/>
      </reference>
      <reference anchor="RFC4648">
        <front>
          <title>The Base16, Base32, and Base64 Data Encodings</title>
          <author fullname="S. Josefsson" initials="S." surname="Josefsson"/>
          <date month="October" year="2006"/>
          <abstract>
            <t>This document describes the commonly used base 64, base 32, and base 16 encoding schemes. It also discusses the use of line-feeds in encoded data, use of padding in encoded data, use of non-alphabet characters in encoded data, use of different encoding alphabets, and canonical encodings. [STANDARDS-TRACK]</t>
          </abstract>
        </front>
        <seriesInfo name="RFC" value="4648"/>
        <seriesInfo name="DOI" value="10.17487/RFC4648"/>
      </reference>
      <reference anchor="RFC9861">
        <front>
          <title>KangarooTwelve and TurboSHAKE</title>
          <author fullname="B. Viguier" initials="B." surname="Viguier"/>
          <author fullname="D. Wong" initials="D." role="editor" surname="Wong"/>
          <author fullname="G. Van Assche" initials="G." role="editor" surname="Van Assche"/>
          <author fullname="Q. Dang" initials="Q." role="editor" surname="Dang"/>
          <author fullname="J. Daemen" initials="J." role="editor" surname="Daemen"/>
          <date month="October" year="2025"/>
          <abstract>
            <t>This document defines four eXtendable-Output Functions (XOFs), hash functions with output of arbitrary length, named TurboSHAKE128, TurboSHAKE256, KT128, and KT256.</t>
            <t>All four functions provide efficient and secure hashing primitives, and the last two are able to exploit the parallelism of the implementation in a scalable way.</t>
            <t>This document is a product of the Crypto Forum Research Group. It builds up on the definitions of the permutations and of the sponge construction in NIST FIPS 202 and is meant to serve as a stable reference and an implementation guide.</t>
          </abstract>
        </front>
        <seriesInfo name="RFC" value="9861"/>
        <seriesInfo name="DOI" value="10.17487/RFC9861"/>
      </reference>
      <reference anchor="RFC4086">
        <front>
          <title>Randomness Requirements for Security</title>
          <author fullname="D. Eastlake 3rd" initials="D." surname="Eastlake 3rd"/>
          <author fullname="J. Schiller" initials="J." surname="Schiller"/>
          <author fullname="S. Crocker" initials="S." surname="Crocker"/>
          <date month="June" year="2005"/>
          <abstract>
            <t>Security systems are built on strong cryptographic algorithms that foil pattern analysis attempts. However, the security of these systems is dependent on generating secret quantities for passwords, cryptographic keys, and similar quantities. The use of pseudo-random processes to generate secret quantities can result in pseudo-security. A sophisticated attacker may find it easier to reproduce the environment that produced the secret quantities and to search the resulting small set of possibilities than to locate the quantities in the whole of the potential number space.</t>
            <t>Choosing random quantities to foil a resourceful and motivated adversary is surprisingly difficult. This document points out many pitfalls in using poor entropy sources or traditional pseudo-random number generation techniques for generating such quantities. It recommends the use of truly random hardware techniques and shows that the existing hardware on many systems can be used for this purpose. It provides suggestions to ameliorate the problem when a hardware solution is not available, and it gives examples of how large such quantities need to be for some applications. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
          </abstract>
        </front>
        <seriesInfo name="BCP" value="106"/>
        <seriesInfo name="RFC" value="4086"/>
        <seriesInfo name="DOI" value="10.17487/RFC4086"/>
      </reference>
    </references>
    <?line 827?>

<section anchor="pseudocode">
      <name>Pseudocode</name>
      <section anchor="uri-component-extraction-1">
        <name>URI Component Extraction</name>
        <sourcecode type="pseudocode"><![CDATA[
function extract_components(uri_string):
  if uri_string contains "://":
     scheme = substring up to and including "://"
     path = substring after "://"
  else:
     scheme = ""
     path = uri_string

  components = []

  // For absolute paths, treat leading "/" as first component
  if path starts with "/":
     components.append("/")
     path = substring after first "/"

  while path is not empty:
     terminator_pos = find_next_terminator(path)
     if terminator_pos found:
        component = substring(path, 0, terminator_pos + 1)
        path = substring(path, terminator_pos + 1)
        components.append(component)
     else:
        components.append(path)
        path = ""

  return (scheme, components)

function find_next_terminator(path):
  for i from 0 to length(path) - 1:
     if path[i] == '/' or path[i] == '?' or path[i] == '#':
        return i
  return not_found
]]></sourcecode>
      </section>
      <section anchor="xof-initialization">
        <name>XOF Initialization</name>
        <sourcecode type="pseudocode"><![CDATA[
function initialize_xofs(secret_key, context):
  // Initialize base XOF
  base_xof = TurboSHAKE128(0x1F)

  // Absorb key and context with length prefixes
  base_xof.update(uint8(len(secret_key)))
  base_xof.update(secret_key)
  base_xof.update(uint8(len(context)))
  base_xof.update(context)

  // Create components XOF
  components_xof = base_xof.clone()
  components_xof.update("IV")

  // Create base keystream XOF
  base_keystream_xof = base_xof.clone()
  base_keystream_xof.update("KS")

  return (components_xof, base_keystream_xof)
]]></sourcecode>
      </section>
      <section anchor="encryption-algorithm-1">
        <name>Encryption Algorithm</name>
        <sourcecode type="pseudocode"><![CDATA[
function uricrypt_encrypt(secret_key, context, uri_string):
  // Extract components
  (scheme, components) = extract_components(uri_string)

  // Initialize XOF instances with secret key and context
  (components_xof, base_keystream_xof) =
      initialize_xofs(secret_key, context)
  if error: return error

  encrypted_output = byte_array()

  // Process each component
  for component in components:
     // Update components XOF for SIV computation
     components_xof.update(component)

     // Generate SIVLEN-byte Synthetic Initialization Vector (SIV)
     siv = components_xof.clone().squeeze(SIVLEN)

     // Create keystream XOF for this component
     keystream_xof = base_keystream_xof.clone()
     keystream_xof.update(siv)

     // Calculate padding for base64 encoding alignment
     // The total bytes (SIV + component) must be a multiple of PADBS
     // to produce clean base64 output without padding characters
     component_len = len(component)
     padding_len = (PADBS - (SIVLEN + component_len) % PADBS) % PADBS

     // Generate keystream
     keystream = keystream_xof.squeeze(component_len + padding_len)

     // Pad component to align with base64 encoding requirements
     padded_component = component + byte_array(padding_len)

     // Encrypt using XOR with keystream
     encrypted_part = xor_bytes(padded_component, keystream)

     // Append to output
     encrypted_output.extend(siv)
     encrypted_output.extend(encrypted_part)

  // Base64 encode with URL-safe characters and no padding
  base64_output = base64_urlsafe_no_pad_encode(encrypted_output)

  // Return with appropriate prefix
  if scheme != "":
     return scheme + base64_output
  else if uri_string starts with "/":
     return "/" + base64_output
  else:
     return base64_output
]]></sourcecode>
      </section>
      <section anchor="decryption-algorithm-1">
        <name>Decryption Algorithm</name>
        <sourcecode type="pseudocode"><![CDATA[
function uricrypt_decrypt(secret_key, context, encrypted_uri):
  // Split scheme and base64
  if encrypted_uri contains "://":
     scheme = substring up to and including "://"
     base64_part = substring after "://"
  else if encrypted_uri starts with "/":
     // Path-only URI: strip leading "/" before decoding
     scheme = ""
     base64_part = substring after first "/"
  else:
     scheme = ""
     base64_part = encrypted_uri

  // Remove all slashes from the base64 part (the encrypted ciphertext)
  // Slashes may appear at arbitrary locations after the scheme for
  // aesthetic/structural purposes, but are not part of the encrypted data
  base64_part = base64_part.replace("/", "")

  // Decode base64
  try:
     decoded = base64_urlsafe_no_pad_decode(base64_part)
  catch:
     return error("Decryption failed")

  // Initialize XOF instances with secret key and context
  (components_xof, base_keystream_xof) =
      initialize_xofs(secret_key, context)
  if error: return error

  decrypted_components = []
  input_stream = ByteStream(decoded)

  // Process each component
  while not input_stream.empty():
     // Read SIV
     siv = input_stream.read(SIVLEN)
     if len(siv) != SIVLEN:
        return error("Decryption failed")

     // Create keystream XOF
     keystream_xof = base_keystream_xof.clone()
     keystream_xof.update(siv)

     // Decrypt byte-by-byte to find component boundary
     component = byte_array()
     component_start = input_stream.position()

     while not input_stream.empty():
        // Decrypt one byte
        encrypted_byte = input_stream.read(1)
        if len(encrypted_byte) != 1:
           return error("Decryption failed")

        keystream_byte = keystream_xof.squeeze(1)
        decrypted_byte = xor_bytes(encrypted_byte, keystream_byte)[0]

        // Skip padding (null bytes)
        if decrypted_byte == 0x00:
           continue

        // Add to component
        component.append(decrypted_byte)

        // Check for terminator
        if decrypted_byte == '/' or decrypted_byte == '?' or decrypted_byte == '#':
           // Component complete - skip remaining padding
           total_len = input_stream.position() - component_start
           padding_len = (PADBS - ((SIVLEN + total_len) % PADBS)) % PADBS
           input_stream.skip(padding_len)
           break

     // Update XOF with plaintext
     components_xof.update(component)

     // Generate expected SIV
     expected_siv = components_xof.clone().squeeze(SIVLEN)

     // Authenticate using constant-time comparison to prevent timing attacks
     if not constant_time_equal(siv, expected_siv):
        return error("Decryption failed")

     decrypted_components.append(component)

  // Reconstruct URI
  path = "".join(decrypted_components)
  return scheme + path
]]></sourcecode>
      </section>
      <section anchor="padding-and-encoding-1">
        <name>Padding and Encoding</name>
        <sourcecode type="pseudocode"><![CDATA[
function calculate_padding(component_len):
  // Calculate padding needed for base64 encoding alignment
  // The combined SIV (SIVLEN bytes) + component must be divisible by PADBS
  // for clean base64 encoding without '=' padding characters
  total_len = SIVLEN + component_len
  return (PADBS - total_len % PADBS) % PADBS

function base64_urlsafe_no_pad_encode(data):
  // Use standard base64 encoding
  encoded = standard_base64_encode(data)
  // Make URL-safe and remove padding for URI compatibility
  encoded = encoded.replace('+', '-')
                   .replace('/', '_')
                   .rstrip('=')
  return encoded

function base64_urlsafe_no_pad_decode(encoded):
  // Add padding if needed for standard decoder
  padding = (4 - len(encoded) % 4) % 4
  if padding > 0:
     encoded = encoded + ('=' * padding)
  // Make standard base64
  encoded = encoded.replace('-', '+')
                   .replace('_', '/')
  // Decode
  return standard_base64_decode(encoded)
]]></sourcecode>
      </section>
    </section>
    <section anchor="test-vectors">
      <name>Test Vectors</name>
      <t>These test vectors were generated using the reference Rust implementation
of URICrypt with TurboSHAKE128.</t>
      <artwork><![CDATA[
Test Configuration:
secret_key (hex): 0102030405060708090a0b0c0d0e0f10
context: "test-context"
]]></artwork>
      <section anchor="test-vector-1-full-uri">
        <name>Test Vector 1: Full URI</name>
        <artwork><![CDATA[
Input: "https://example.com/a/b/c"
Output: "https://HOGo9vauZ3b3xsPNPQng5apSzL5V7QW94C7USgN8mHZJ337AKSWOu
         cUwMuD-uUfF95SsSHCNgBkXUnH1uGll_YtBltXSqKEHNcYJJwbdFdhfWz19"
]]></artwork>
      </section>
      <section anchor="test-vector-2-path-only-uri">
        <name>Test Vector 2: Path-Only URI</name>
        <artwork><![CDATA[
Input: "/a/b/c"
Output: "/b9bCOhqZsvU9XxGOMk6d8QFQhTIdI_xYKpds2lWXpZCms5-az9wtfUft3rec
         3d9YkUo0N7VcxO5MXfxE5UobvgTJX8UpRdNN"
]]></artwork>
      </section>
      <section anchor="test-vector-3-multi-component-path">
        <name>Test Vector 3: Multi-Component Path</name>
        <artwork><![CDATA[
Input: "https://cdn.example.com/videos/2025/03/file.mp4"
Output: "https://hxUM2N3txwYjGxjvCpWn30SznxR0v0fDbkSQgCTXCUu7Rq8iSbWP4
         0OvYxKs9zC3kw1JNzAc4Wuj7RZvRd0VUprJWLs5KJPnWsA9Kguxa_J7XviTS3G
         Tqf-XZdPxYyq1Y1MXVE9_4ojHwm6jBDUkVthAkuNe5Cqk_h6d"
]]></artwork>
      </section>
      <section anchor="test-vector-4-root-with-scheme">
        <name>Test Vector 4: Root with Scheme</name>
        <artwork><![CDATA[
Input: "https://example.com/"
Output: "https://HOGo9vauZ3b3xsPNPQng5apSzL5V7QW94C7USgN8"
]]></artwork>
      </section>
      <section anchor="test-vector-5-simple-path">
        <name>Test Vector 5: Simple Path</name>
        <artwork><![CDATA[
Input: "/path/to/resource"
Output: "/b9bCOhqZsvU9XxGOMk6d8QFQPTuMlsQKDBhAbc77JvsdRj0kxiFipunATQmm
         CkNhAe0BPP2EqQoxORElY_ukfUYSrr9mIMfiO9joa3Kn5RS7eSKr"
]]></artwork>
      </section>
      <section anchor="test-vector-6-uri-with-query-parameters">
        <name>Test Vector 6: URI with Query Parameters</name>
        <artwork><![CDATA[
Input: "https://example.com/search?q=test&limit=10"
Output: "https://HOGo9vauZ3b3xsPNPQng5apSzL5V7QW94C7USgN8cl2BBtuWmxTsI
         Ij59ka3KeDsaqXFGnKgW9aLLR36YvUf9ORkMnVE5PTR_3DiO43hL9WjdSu7L9
         FN"
]]></artwork>
      </section>
      <section anchor="test-vector-7-uri-with-fragment">
        <name>Test Vector 7: URI with Fragment</name>
        <artwork><![CDATA[
Input: "https://docs.example.com/guide#installation"
Output: "https://ypHTiw0JUMcr4bUjQH9Dxo8wGWHyfFlLq8VrOE-zX6IbgLFxYX_Jm
         2hzivywvrpIBWa-9Jl6nSZLq2pd35QwkDsc1-_Kao2BvyBB19ndu1PpwQv1wy
         uA"
]]></artwork>
      </section>
      <section anchor="test-vector-8-uri-with-query-and-fragment">
        <name>Test Vector 8: URI with Query and Fragment</name>
        <artwork><![CDATA[
Input: "/api/v2/users?id=123#profile"
Output: "/b9bCOhqZsvU9XxGOMk6d8QFQwcP2C3bJVNVZDge7zfub_ai4x6LaUlXp-XjZ
         XOgZlLloIbasK-JKlbeKeKV2rctq5bX9zQh1KogN2zaggTMZioUb4kwGIKp8Z
         y744xQwGDG64n6GhN56XEM8LvBfJuEj6ZgsjeLbTPIMbCmO0pJhzVSh"
]]></artwork>
      </section>
    </section>
  </back>
  <!-- ##markdown-source:
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
0388eTXALf8plGwrYQYTxZGc/m6nvSvcF/bxfsw2EWdPH8LsFbZaWqzbloB1
2gs0UcCWevv4AvNQ2RNowqfwM07YAiUeQ/+LgS0ZVRSnm91eIM7wFIZOvJln
B9aQnHDuIOQ7xzT5rhP15hnNXtRGwV29LZZXlleX15bXlzeWN5efLT9f3lr2
l7vLveX+crA8WFn2pAGA78HDgCrMYUGzOGuN+AbyS1lH1XnD/r5XqVXJFt3m
9cmreOvGzz+vddfu0tPj03fRcMOfnn873Hj/7N2HrfXdZ5fnw+Pnk9ef36yt
Pdt+e/7hJDeb2bu8Pcr3mvnl4OXWxnl6/nr3eLhz/fEyer2SvxqPrz5lO+Ps
4/nXt/uvj3uf3ry57fZf9keDD99WtqoXtdpm4/1EGu/uykrLWOpudXdPRl8/
pzeXWx/vXp0cXW/2n797+W50cdA/uLr79HbaT1fHHz5OP+9O0o2m/23rNhtc
DrK1JOiZZaz1tz5dX8bLx8/e9+5ONo4+Du72Ny7j7s3w4s3H55fTs/7xcTW8
a21xhA7VptGjEP7qDen1o5a9KRhkEadLq8urG0vLa0sDEKityXS9YptGd5dH
q8dr2d3tpy+v7r7c7E4/RGvL59+iu7Plm+XBXvf6/N1w9+Lj7mX+7Ozr8/C8
++F03axv+eTm093bdOvb7tr17cqb42/bvfUP+ZdnZ59vzvrL7y+nyZsPh+nG
2zen0Yd0e+vtML/zr948+3gTXpyvvTLjXHwdND9+7p/efZp9Xfm0cvTx/f7W
1Xr85fXtZPPLzt7l9ftstH2dHwcbu1+vr0ab/WqkrbfFWRyrFyFIlj9MwX+C
eKuh2GiLczrqFTtW8Tb5wzR3epEfjdN3b/d2Rtvd3rNnb27S/tmX5eu78GU4
zaPti3eTicHl7vXxaDtY3jk9Xd3/+i6+OznbH3+6yq8Hl5/Ok2RrcnA0CE+2
vsT+2tto4+z8WXD+NqleyCYFyjE231FYxqkOy3gYr2mAgdI/fX2BHOdvlEv2
YmX5T2C7N17d2cnyD5O7i/TArPfgy8bWNSwm2Ev9rx9fvoreDj9s+YeHZ2ub
n24uB1snZ9dH0fv9jdOLs6u1vfBkfW10uPXhS/88f3a4ZYZ5OecgPrOQ8FKG
oVQvHhTB1DmGwxzO4RNy9ow5UrRi9bPp64vwdvnN5VEvWe9efnn3emvvLn5+
++rD69ng5fjw6/P3ycl+89vHzYPu8PDl3aePV2+s3V4dfQtvZrc3yfRg54Pf
3Hoz3ozOPx9+XZ321zbe3V7vpb2V5tVbP17duZnt7KxsRf185XR6++5m5XZm
hsm3q1f/vEQCqBhV42HJn4ZLN6tLeQr08VPYf7GyuvZkmsTIfh5D5re909Xd
te6b98fvP+8Ng2ffBnn3yg/X7zYP/cvxx2nz45fPBuKPJ8PP48NxfADC+23z
zdtxN3gbvH2/mvSyrxvdj1vf3o1W3sbD49Vv/nB4cfQ5jC+769e3rw7eTp9b
w8yera/fvbt9tfdqcz3afDU63tj8uH/0/PBmZ/Am3/+y+XmYfgkOuxenB0fd
3cnJ8vTN6Nv78xFj678BydiouxioAAA=

-->

</rfc>
