RFC 9415

On the Generation of Transient Numeric Identifiers

๐Ÿ“… published July 2023, from ietf

RFC 9415: On the Generation of Transient Numeric Identifiers ๐ŸŽ€

Part 1 of 10 โœจ

bestie, this is RFC 9415 ๐Ÿฆ‹ and the title is On the Generation of Transient Numeric Identifiers. It was written by F. Gont at SI6 Networks and I. Arce at Quarkslab, and it's dated July 2023. The category is Informational and it comes from the IRTF stream, with ISSN 2070-1721 ๐Ÿ’œ. The header doesn't list any RFCs it obsoletes or updates, so it stands on its own ๐Ÿ’…

Abstract โœจ

okay so this doc looks at the security and privacy side of "transient numeric identifiers" (the little numbers protocols pick on the fly ๐Ÿ”ข). It sorts them into categories based on their interoperability requirements and on how bad things get (the failure severity) when those requirements aren't met ๐Ÿ“Š. Then it suggests algorithms that could satisfy each category's requirements while keeping the security and privacy risks as low as possible, which is basically a guide for protocol designers and implementers ๐Ÿงš. At the end it covers a bunch of algorithms that real implementations have actually used to generate these identifiers and checks out their security and privacy properties ๐Ÿ”. This document is a product of the Privacy Enhancements and Assessments Research Group (PEARG) in the IRTF ๐ŸŒˆ

Status of This Memo ๐ŸŒธ

This is not an Internet Standards Track spec. It's published just for informational purposes ๐Ÿ“š

It's a product of the Internet Research Task Force (IRTF), which publishes the results of Internet-related research and development. Those results might not be suitable for deployment, so be careful ๐Ÿ™ˆ This RFC represents the consensus of the Privacy Enhancements and Assessments Research Group of the IRTF. Documents approved for publication by the IRSG are not candidates for any level of Internet Standard, see Section 2 of RFC 7841 ๐Ÿ’…

For the current status, any errata, and how to send feedback, check https://www.rfc-editor.org/info/rfc9415 ๐Ÿ”—

Copyright (c) 2023 IETF Trust and the persons identified as the document authors. All rights reserved ๐ŸŽ€

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they stand on the publication date. Please read these carefully, because they describe your rights and restrictions for this document ๐Ÿซถ

Table of Contents ๐Ÿ“‘

1.  Introduction
2.  Terminology
3.  Threat Model
4.  Issues with the Specification of Transient Numeric Identifiers
5.  Protocol Failure Severity
6.  Categorizing Transient Numeric Identifiers
7.  Common Algorithms for Transient Numeric Identifier Generation
  7.1.  Category #1: Uniqueness (Soft Failure)
  7.2.  Category #2: Uniqueness (Hard Failure)
  7.3.  Category #3: Uniqueness, Stable within Context (Soft
        Failure)
  7.4.  Category #4: Uniqueness, Monotonically Increasing within
        Context (Hard Failure)
8.  Common Vulnerabilities Associated with Transient Numeric
        Identifiers
  8.1.  Network Activity Correlation
  8.2.  Information Leakage
  8.3.  Fingerprinting
  8.4.  Exploitation of the Semantics of Transient Numeric
        Identifiers
  8.5.  Exploitation of Collisions of Transient Numeric Identifiers
  8.6.  Exploitation of Predictable Transient Numeric Identifiers
        for Injection Attacks
  8.7.  Cryptanalysis
9.  Vulnerability Assessment of Transient Numeric Identifiers
  9.1.  Category #1: Uniqueness (Soft Failure)
  9.2.  Category #2: Uniqueness (Hard Failure)
  9.3.  Category #3: Uniqueness, Stable within Context (Soft
        Failure)
  9.4.  Category #4: Uniqueness, Monotonically Increasing within
        Context (Hard Failure)
10. IANA Considerations
11. Security Considerations
12. References
  12.1.  Normative References
  12.2.  Informative References
Appendix A.  Algorithms and Techniques with Known Issues
  A.1.  Predictable Linear Identifiers Algorithm
  A.2.  Random-Increments Algorithm
  A.3.  Reusing Identifiers Across Different Contexts
Acknowledgements
Authors' Addresses

1. Introduction ๐ŸŒท

Networking protocols use all kinds of transient numeric identifiers for different protocol objects ๐Ÿงฉ Some examples are the IPv4 and IPv6 Identification values [RFC0791] [RFC8200], IPv6 Interface Identifiers (IIDs) [RFC4291], transport-protocol ephemeral port numbers [RFC6056], TCP Initial Sequence Numbers (ISNs) [RFC9293], NTP Reference IDs (REFIDs) [RFC5905], and DNS IDs [RFC1035]. These identifiers usually have specific requirements (for example, being unique over a certain period of time) that must be met, or else you get negative interoperability effects and a failure severity attached to that ๐Ÿ˜ฌ

   |  NOTE: Some documents refer to the DNS ID as the DNS "Query ID"
   |  or "TxID".

For more than 30 years, tons of IETF protocol implementations have been hit by attacks ๐Ÿ’€ The results have ranged from Denial of Service (DoS) and data injection all the way to information leaks that could be used for pervasive monitoring [RFC7258]. A lot of the time, the root cause is a poor choice of transient numeric identifiers, usually because the specs were insufficient or misleading ๐Ÿ“‰ Finding an algorithm that meets the interoperability requirements of a given identifier is generally easy, but doing it without hurting the security and/or privacy properties of those protocols is where people keep slipping up [RFC9414] ๐Ÿ™ˆ

For example, implementations have had security and/or privacy issues from:

  • predictable IPv4 or IPv6 Identification values (e.g., see [Sanfilippo1998a], [RFC6274], and [RFC7739]),
  • predictable IPv6 IIDs (e.g., see [RFC7217], [RFC7707], and [RFC7721]),
  • predictable transport-protocol ephemeral port numbers (e.g., see [RFC6056] and [Silbersack2005]),
  • predictable TCP Initial Sequence Numbers (ISNs) (e.g., see [Morris1985], [Bellovin1989], and [RFC6528]),
  • predictable initial timestamps in TCP timestamps options (e.g., see [TCPT-uptime] and [RFC7323]), and
  • predictable DNS IDs (see, e.g., [Schuba1993] and [Klein2007]).

Recent history shows that when new protocols get standardized or new implementations come out, the security and privacy properties of their transient numeric identifiers tend to get overlooked ๐Ÿ˜ค Inappropriate algorithms for generating them either end up in the specs or get picked by implementers. So this area really needs advice ๐Ÿ“ฃ

Quick note: cryptographic techniques can help a lot with some of these problems ๐Ÿ” For example, cryptographic authentication can readily mitigate data injection attacks even when identifiers are predictable (like "sequence numbers"). Still, flawed algorithms (such as global counters) used to generate transient numeric identifiers can cause information leaks even when cryptography is in use ๐Ÿ‘€

This document is a non-exhaustive survey of transient numeric identifiers used in various IETF protocols ๐Ÿ—‚๏ธ It tries to categorize them by their interoperability requirements and by the failure severity when those requirements aren't met. Then it gives advice on algorithms that could satisfy each category's interoperability requirements while keeping the negative security and privacy implications low. Last, it analyzes several algorithms that real implementations have used to meet those requirements, and looks at their security and privacy properties ๐Ÿ”ฌ

This document represents the consensus of the Privacy Enhancements and Assessments Research Group (PEARG) ๐Ÿซถ

2. Terminology ๐Ÿ’…

Transient Numeric Identifier: a data object in a protocol specification that can be used to definitively tell one protocol object (a datagram, network interface, transport-protocol endpoint, session, etc.) apart from every other object of the same type, within a given context. These identifiers are usually defined as a series of bits and represented as integer values ๐Ÿ”ข They're typically picked dynamically, unlike statically assigned numeric identifiers (see, e.g., [IANA-PROT]). Different transient numeric identifiers may have extra requirements or properties depending on how the protocol uses them ๐ŸŽ€ In this document, "transient numeric identifier" (or just "numeric identifier" or "identifier") is a generic term for any data object in a protocol specification that has the identification property described above ๐Ÿฆ‹

Failure Severity: the interoperability consequences of failing to meet the interoperability requirements of a given identifier ๐Ÿ’ฅ Severity looks at the worst possible outcome of a failure, measured by the system damage and/or the time lost to fix it. This document defines two types of failure severity: "soft failure" and "hard failure" โœจ

Soft Failure: a recoverable situation where a protocol doesn't operate the way it's supposed to, but normal operation can resume automatically within a short period of time ๐ŸŒค๏ธ For example, a plain packet loss that gets fixed by retransmitting the packet counts as a soft failure ๐Ÿ”

Hard Failure: a non-recoverable situation where a protocol doesn't operate as prescribed, or where it runs with excessive degradation of service ๐Ÿšจ For example, an established TCP connection that gets aborted because of an error condition is a hard failure from the transport protocol's point of view, since it enters a state that normal operation can't recover from ๐Ÿ˜ญ

3. Threat Model โœจ

Okay bestie, first things first: in this doc we are NOT talking about on-path attacks ๐Ÿ™…โ€โ™€๏ธ. We assume the attacker doesn't have physical or logical access to the system(s) being attacked, and they can only see traffic that's explicitly sent to them. ๐Ÿ‘€ Also, the attacker can't see traffic going between the sender and the receiver(s) of a target protocol. BUT they can still interact with those entities, like sending them traffic to sample the transient numeric identifiers the target hosts use when talking to the attacker. Lowkey sneaky, but it's the rules ๐Ÿ’…

Let's make it concrete. When we look at vulnerabilities with TCP Initial Sequence Numbers (ISNs), we assume the attacker can't capture traffic for a TCP connection between two other hosts. However, the attacker can talk to any of those hosts (like establishing a TCP connection with them) to sample the TCP ISNs those hosts use when talking to the attacker. Main character energy for the attacker, honestly ๐Ÿ™ˆ

Same vibe with host-tracking attacks based on IPv6 Interface Identifiers ๐Ÿฆ‹. The attacker might learn a victim's IPv6 address if it gets exposed when the victim talks to an attacker-operated server. After that, the attacker can do host-tracking by probing a set of target addresses made from a set of target prefixes combined with that IPv6 Interface Identifier they originally learned. ๐Ÿงš Another route: the victim host talks to an attacker-operated server while it moves from one location to another, and that exposes its configured addresses. Either way, none of these scenarios need the attacker to see traffic that wasn't explicitly directed at them. Iconic for the attacker, not so iconic for the victim ๐Ÿ˜ญ


4. Issues with the Specification of Transient Numeric Identifiers ๐ŸŒธ

Okay so we went through IETF protocol specs that deal with transient numeric identifiers, and honestly? Most of the problems in this doc come down to one of three things ๐Ÿ”ฅ:

  • protocol specifications that under specify their transient numeric identifiers
  • protocol specifications that over specify their transient numeric identifiers
  • protocol implementations that simply fail to comply with the specified requirements

Let's start with under specifying. A bunch of IETF specs under specified their transient numeric identifiers, which led to implementations that were vulnerable to tons of off-path attacks ๐Ÿ’€. Examples are the TCP local ports in [RFC0793] and the DNS ID in [RFC1035].

NOTE: The TCP local port in an active OPEN request is commonly known as the "ephemeral port" of the corresponding TCP connection [RFC6056].

Now the other side of the coin: over specifying ๐ŸŽ€. Some specs over specify their associated transient numeric identifiers. For example, [RFC4291] basically overloads the semantics of IPv6 Interface Identifiers (IIDs) by embedding link-layer addresses in them. The interoperability requirement of uniqueness could be achieved in other ways that don't cause negative security and privacy implications [RFC7721], so this is a whole vibe check that didn't need to happen. Similarly, [RFC2460] suggests using a global counter for generating Identification values, when the interoperability requirement of uniqueness per {IPv6 Source Address, IPv6 Destination Address} could be achieved with other algorithms that don't cause negative security and privacy implications [RFC7739] โœจ.

Last but not least, there are implementations that just... don't comply with existing specs ๐Ÿ˜ค. For example, some popular operating systems still fail to implement transport-protocol ephemeral port randomization, even though [RFC6056] recommends it. Others still fail to implement TCP Initial Sequence Number randomization, as recommended in [RFC9293]. Not it, operating systems ๐Ÿ™„.


5. Protocol Failure Severity ๐Ÿ’œ

Okay this one's important. Section 2 defines the concept of "failure severity", and this doc uses two types throughout: soft and hard ๐Ÿ”ฅ.

Here's the thing though: we analyze how bad a failure is from the point of view of the protocol in question. The severity on the upper protocol (or application) might be totally different, though ๐Ÿ‘‘. Like, a TCP connection that gets aborted might or might not cause a hard failure in the upper application. If the upper application can just establish a new TCP connection with no impact on the app, then a hard failure at the TCP level might have zero severity at the application layer. Fine, no drama ๐Ÿ’….

On the flip side, if a hard failure of a TCP connection causes excessive degradation of service at the application layer, then yep, it'll also be a hard failure at the application. ๐Ÿ˜ญ Severity really depends on the perspective, bestie.

6. Categorizing Transient Numeric Identifiers โœจ

okay so this section is basically a big survey ๐Ÿ” of transient numeric identifiers, the little IDs that get picked for a moment and then tossed. It covers pretty much every combo of interop requirements and failure severity you'll find in popular protocols across different layers. Non-exhaustive, but representative, so you get the full vibe. Then it sorts everything into categories based on two things: what interop needs, and whether a collision is a soft failure or a hard one ๐Ÿ’…

NOTE: All the other transient numeric identifiers analyzed during this effort could be sorted into one of the existing categories from Table 1. Iconic, no notes ๐Ÿซถ
   +===============+===============================+==================+
   |   Identifier  | Interoperability Requirements | Failure Severity |
   +===============+===============================+==================+
   |    IPv6 ID    |  Uniqueness (for IPv6 address |  Soft/Hard (1)   |
   |               |             pair)             |                  |
   +---------------+-------------------------------+------------------+
   |    IPv6 IID   | Uniqueness (and stable within |     Soft (3)     |
   |               |        IPv6 prefix) (2)       |                  |
   +---------------+-------------------------------+------------------+
   |    TCP ISN    |  Monotonically increasing (4) |     Hard (4)     |
   +---------------+-------------------------------+------------------+
   |  TCP initial  |  Monotonically increasing (5) |     Hard (5)     |
   |   timestamp   |                               |                  |
   +---------------+-------------------------------+------------------+
   | TCP ephemeral |   Uniqueness (for connection  |       Hard       |
   |      port     |              ID)              |                  |
   +---------------+-------------------------------+------------------+
   |   IPv6 Flow   |           Uniqueness          |     None (6)     |
   |     Label     |                               |                  |
   +---------------+-------------------------------+------------------+
   |     DNS ID    |           Uniqueness          |     None (7)     |
   +---------------+-------------------------------+------------------+

             Table 1: Survey of Transient Numeric Identifiers

Here are the footnotes that go with Table 1, in my own words ๐ŸŽ€

(1) A single IPv6 Identification (ID) collision just drops one packet, so it's a "soft" failure. But repeated collisions at high data rates can start self-propagating, which can tip it into a hard failure [RFC4963] ๐Ÿ˜ฌ

(2) The only interop rule is that the Interface Identifier gives a unique IPv6 address. Operationally though, it's usually nicer if that address (and so the Interface Identifier) stays stable within each network [RFC7217] [RFC8064] โœจ

(3) IPv6 Interface Identifiers have to give unique addresses, but IPv6 Duplicate Address Detection (DAD) [RFC4862] can spot duplicate addresses, so these collisions can actually be recovered from ๐Ÿ™Œ

(4) Okay so, in theory TCP Initial Sequence Numbers (ISNs) have no interop requirements, because the TIME-WAIT state and TCP's "quiet time" concept handle old segments from previous incarnations of a connection. BUT there's a popular optimization where a new incarnation of a previous connection can be created if the ISN of the incoming SYN is larger than the last sequence number seen in that direction for the previous incarnation. So monotonically increasing TCP ISNs make that optimization work as expected [RFC6528], and they can help avoid connection-establishment failures ๐Ÿ“

(5) Strictly speaking, the initial TCP timestamp (the TS Value (TSval) in a segment with the SYN bit set) has no interop requirements either. Still, some TCP implementations let a new incarnation of a previous connection be created if the TSval of the incoming SYN is larger than the last TSval seen in that direction for the previous incarnation (please see [RFC6191]). So monotonically increasing initial timestamps across connections to the same endpoint make that optimization work as expected [RFC6191] and can help avoid connection-establishment failures ๐Ÿ•ฐ๏ธ

(6) The IPv6 Flow Label [RFC6437], together with the IPv6 Source Address and the IPv6 Destination Address, is usually used for load sharing [RFC7098]. Reusing a Flow Label value for the same {Source Address, Destination Address} set would usually put both flows onto the same link. As long as that doesn't happen deterministically, though, there aren't any negative implications ๐Ÿงš

(7) DNS IDs work together with the IP Source Address, the IP Destination Address, the transport-protocol Source Port, and the transport-protocol Destination Port to match DNS requests and responses. An implementation already knows which DNS requests it sent for that exact {IP Source Address, IP Destination Address, transport-protocol Source Port, transport-protocol Destination Port, DNS ID} set, so a DNS ID collision would, at worst, cost a small performance penalty. The response still gets thrown out when it turns out it doesn't answer the query that was sent ๐Ÿ’œ

Based on that survey, here's how the identifiers get categorized ๐Ÿ‘‘

   +=======+======================================+====================+
   | Cat # |               Category               |   Sample Numeric   |
   |       |                                      |        IDs         |
   +=======+======================================+====================+
   |   1   |      Uniqueness (soft failure)       | IPv6 Flow L., DNS  |
   |       |                                      |         ID         |
   +-------+--------------------------------------+--------------------+
   |   2   |      Uniqueness (hard failure)       |    IPv6 ID, TCP    |
   |       |                                      |   ephemeral port   |
   +-------+--------------------------------------+--------------------+
   |   3   |  Uniqueness, stable within context   |      IPv6 IID      |
   |       |            (soft failure)            |                    |
   +-------+--------------------------------------+--------------------+
   |   4   | Uniqueness, monotonically increasing |    TCP ISN, TCP    |
   |       |    within context (hard failure)     | initial timestamp  |
   +-------+--------------------------------------+--------------------+

                       Table 2: Identifier Categories

One more thing, and it's kind of a glow-up moment ๐ŸŒˆ Category #4 can be seen as a generalized version of Category #3, where a monotonically increasing element gets added to a stable (within context) element. That way the resulting identifiers are monotonically increasing within a specified context. The same algorithm can be used for both #3 and #4, as long as you pass in the right parameters ๐Ÿฆ‹

7. Common Algorithms for Transient Numeric Identifier Generation ๐Ÿ’–

Next up are some sample algorithms for generating transient numeric identifiers in each of the categories above. They're designed to hold up against the vulnerabilities analyzed in Section 8 of this document ๐Ÿ›ก๏ธ

Quick heads up on the variables: everything in these algorithms is of "unsigned integer" type, except the "retry" variable, which is a (signed) "integer" ๐Ÿ”ข

7.1. Category #1: Uniqueness (Soft Failure) ๐ŸŒธ

Uniqueness with a soft failure severity can be handled with a Pseudorandom Number Generator (PRNG). Easy peasy ๐Ÿ“

NOTE: Please see [RFC4086] for the randomness requirements around security. Don't skip this one, bestie ๐Ÿ™ˆ

Most systems do give you access to a PRNG, but a lot of those PRNG implementations aren't cryptographically secure. That means they might be statistically biased or open to adversarial influence ๐Ÿ˜ฌ For example, ISO C [C11] rand(3) implementations aren't cryptographically secure, so, yikes.

NOTE: Section 7.1 ("Uniform Deviates") of [Press1992] digs into the issues behind ISO C [C11] rand(3) implementations. Highly recommend the read ๐Ÿ“š

On the flip side, plenty of systems offer a Cryptographically Secure PRNG (CSPRNG) [RFC4086] [RFC8937], which guarantees high entropy, unpredictability, and a good statistical distribution of random values. For example, GNU/Linux's CSPRNG is available through the getentropy(3) interface [GETENTROPY], and OpenBSD's CSPRNG is available through the arc4random(3) and arc4random_uniform(3) interfaces [ARC4RANDOM]. Where they're available, these CSPRNGs should be preferred over, e.g., POSIX [POSIX] random(3) or ISO C [C11] rand(3) implementations. Main character choice ๐Ÿ‘‘

If a CSPRNG isn't readily available to pick Category #1 identifiers, a security and privacy assessment of using a regular PRNG should be performed to back up that implementation decision ๐Ÿ”

NOTE: [Aumasson2018], [Press1992], and [Knuth1983] cover the theory and practice of pseudorandom number generation, and they give guidance on how to evaluate PRNGs. Bookmark these ๐Ÿ”–

Here's the thing: since the premise is that collisions of this category's identifiers only cause soft failures, the algorithm often doesn't need to check whether a picked identifier is suitable. In plenty of cases, the suitable_id() function (described below) could always return "true" and that's totally fine โœจ

Now, say simultaneous use of a given identifier is undesirable and the implementation detects that. It can either pick the next available identifier in the same sequence, or pick another random number. Section 7.1.1 is an implementation of the first strategy, and Section 7.1.2 is an implementation of the second. Usually the Section 7.1.2 approach gives a more uniform distribution of the generated identifiers. But for identifiers where the implementation typically keeps local state about unsuitable or used ones, the Section 7.1.2 algorithm may need many more iterations than Section 7.1.1 to find a suitable identifier. How much that matters depends on the current usage ratio of the identifiers (the number of identifiers considered suitable divided by the total number of identifiers) and other parameters. So, in those cases, lots of implementations end up preferring the Section 7.1.1 algorithm over Section 7.1.2 ๐Ÿฅน๐Ÿ’œ

7.1.1. Simple Randomization Algorithm โœจ

Okay so this is the first randomization algorithm ๐Ÿ’– It's giving pseudocode, so here it is verbatim:

/* Transient Numeric ID selection function */

id_range = max_id - min_id + 1;
next_id = min_id + (random() % id_range);
retry = id_range;

do {
    if (suitable_id(next_id)) {
        return next_id;
    }

    if (next_id == max_id) {
        next_id = min_id;
    } else {
        next_id++;
    }

    retry--;

} while (retry > 0);

return ERROR;

NOTE: random() is a PRNG that returns a pseudorandom unsigned integer of an appropriate size. Bestie, be careful: "adapting" the length of the output of random() with a modulo operator (e.g., C language's %) may change the distribution of the PRNG. To keep a uniform distribution, the rejection sampling technique [Romailler2020] can be used. ๐ŸŽ€

suitable_id() is a function that checks, if possible and desirable, whether a candidate numeric identifier is suitable (e.g., whether it is in use or has been recently employed). Depending on how and where the numeric identifier is used, it may or may not be possible (or even desirable) to check whether it is suitable. ๐ŸŒธ

All the variables (in this algorithm and all the others discussed in this document) are unsigned integers. ๐Ÿงš

When an identifier is found to be unsuitable, this algorithm selects the next available numeric identifier in sequence. So even though the picks are random, it's lowkey biased toward the first available identifier after a run of unavailable ones ๐Ÿ˜ญ For example, if this algorithm is used for transport-protocol ephemeral port randomization [RFC6056] and the local list of unsuitable port numbers (e.g., registered port numbers that should not be used for ephemeral ports) is significant, an attacker may actually have a significantly better chance of guessing an ephemeral port number. Not iconic at all ๐Ÿ’€

Assuming the randomness requirements for the PRNG are met (see [RFC4086]), this algorithm does not suffer from any of the issues discussed in Section 8. Slay ๐Ÿ’…


7.1.2. Another Simple Randomization Algorithm ๐Ÿฆ‹

Here's another algorithm for picking a random transient numeric identifier. The idea is that if the picked identifier turns out to be unsuitable (e.g., already in use), it just randomly picks another one ๐Ÿ”ฅ

/* Transient Numeric ID selection function */

id_range = max_id - min_id + 1;
retry = id_range;

do {
    next_id = min_id + (random() % id_range);

    if (suitable_id(next_id)) {
        return next_id;
    }

    retry--;

} while (retry > 0);

return ERROR;

NOTE: random() is a PRNG that returns a pseudorandom unsigned integer of an appropriate size. Beware that "adapting" the length of the output of random() with a modulo operator (e.g., C language's %) may change the distribution of the PRNG. To preserve a uniform distribution, the rejection sampling technique [Romailler2020] can be used. ๐ŸŒˆ

suitable_id() is a function that checks, if possible and desirable, whether a candidate numeric identifier is suitable (e.g., whether it is not already in use). Depending on how and where the numeric identifier is used, it may or may not be possible (or even desirable) to check whether it is in use (or whether it has been recently employed). ๐Ÿซถ

When an identifier is found to be unsuitable, this algorithm selects another random numeric identifier. The tea here is that this algorithm might be unable to select a transient numeric identifier (i.e., return "ERROR"), even if suitable identifiers are available, in cases where a large number of identifiers are found to be unsuitable (e.g., "in use"). That's giving "so close but not quite" ๐Ÿ™ˆ

Assuming the randomness requirements for the PRNG are met (see [RFC4086]), this algorithm does not suffer from any of the issues discussed in Section 8. Periodt โœจ


7.2. Category #2: Uniqueness (Hard Failure) ๐Ÿ“

Okay so one of the most basic ways to get a unique transient numeric identifier (with a hard failure severity) is to cut down how often identifiers get reused, by generating them with a monotonically increasing function (e.g., linear). That means any of the algorithms in Section 7.4 ("Category #4: Uniqueness, Monotonically Increasing within Context (Hard Failure)") can be readily used to meet the requirements of this category. Main character energy ๐Ÿ‘‘

If the local system can definitely check whether an identifier is suitable (e.g., unique), then any of the algorithms in Section 7.1 ("Category #1: Uniqueness (Soft Failure)") can be readily used to meet the requirements of this category too. โœจ

NOTE: Ngl, this is the plot twist ๐Ÿ˜ญ For things like TCP ephemeral ports or TCP ISNs, an identifier that looks suitable from the local system's point of view might actually be unsuitable from the remote system's point of view (e.g., because there is state associated with the selected identifier at the remote system). So in those cases, it is not possible to use the algorithms from Section 7.1 ("Category #1: Uniqueness (Soft Failure)").

7.3. Category #3: Uniqueness, Stable within Context (Soft Failure) ๐Ÿ”ฎ

The goal of the following algorithm is to produce identifiers that stay the same for a given context (called "CONTEXT") but change when that context changes ๐Ÿฆ‹

To avoid storing the transient numeric identifiers computed for each CONTEXT in memory, the following algorithm uses a calculated technique (instead of keeping state in memory) to generate a stable transient numeric identifier for each context. Big brain move ๐Ÿง 

/* Transient Numeric ID selection function  */

id_range = max_id - min_id + 1;

retry = 0;

do {
    offset = F(CONTEXT, retry, secret_key);
    next_id = min_id + (offset % id_range);

    if (suitable_id(next_id)) {
        return next_id;
    }

    retry++;

} while (retry <= MAX_RETRIES);

return ERROR;

NOTE:

CONTEXT is the concatenation of all the elements that define a given context. ๐ŸŽ€

F() is a pseudorandom function (PRF). It must not be computable from the outside (without knowledge of the secret key). F() must also be difficult to reverse, so that it resists attempts to obtain the secret key, even when given samples of the output of F() and knowledge or control of the other input parameters. F() should produce an output of at least as many bits as required for the transient numeric identifier. SipHash-2-4 (128-bit key, 64-bit output) [SipHash] and BLAKE3 (256-bit key, arbitrary-length output) [BLAKE3] are two possible options for F(). Alternatively, F() could be implemented with a keyed hash message authentication code (HMAC) [RFC2104]. HMAC-SHA-256 [FIPS-SHS] would be one possible option for such an implementation alternative. Note: Use of HMAC-MD5 [RFC1321] or HMAC-SHA1 [FIPS-SHS] are not recommended for F() [RFC6151] [RFC6194]. The result of F() is no more secure than the secret key, and therefore, "secret_key" must be unknown to the attacker and must be of a reasonable length. "secret_key" must remain stable for a given CONTEXT, since otherwise, the numeric identifiers generated by this algorithm would not have the desired stability properties (i.e., stable for a given CONTEXT). In most cases, "secret_key" should be selected with a PRNG (see [RFC4086] for recommendations on choosing secrets) at an appropriate time and stored in stable or volatile storage (as necessary) for future use. ๐Ÿ”

suitable_id() checks whether a candidate numeric identifier has suitable uniqueness properties. โœ…

In this algorithm, the function F() provides a stateless and stable per-CONTEXT offset, where CONTEXT is the concatenation of all the elements that define the given context. ๐Ÿ’œ

For example, if this algorithm is expected to produce IPv6 IIDs that are unique per network interface and Stateless Address Autoconfiguration (SLAAC) prefix, CONTEXT should be the concatenation of, e.g., the network interface index and the SLAAC autoconfiguration prefix (please see [RFC7217] for an implementation of this algorithm for generation of stable IPv6 addresses). ๐ŸŒธ

The result of F() is stored in the variable "offset", which may take any value within the storage type range. We restrict the resulting identifier to the range [min_id, max_id] in a similar way to the algorithm in Section 7.1.1. ๐Ÿงš

As noted above, suitable_id() checks whether a candidate numeric identifier has suitable uniqueness properties. Collisions (i.e., an identifier that is not unique) are recovered from by incrementing the "retry" variable and recomputing F(), up to a maximum of MAX_RETRIES times. However, recovering from collisions will usually result in identifiers that fail to stay constant for the specified context. This is normally acceptable when the probability of collisions is small, as in the case of, e.g., IPv6 IIDs resulting from SLAAC [RFC7217] [RFC8981]. ๐Ÿ™ˆ

For obvious reasons, the transient numeric identifiers generated with this algorithm allow for network activity correlation and fingerprinting within "CONTEXT". However, this is essentially a design goal of this category of transient numeric identifiers. Tea spilled โ˜•


7.4. Category #4: Uniqueness, Monotonically Increasing within Context (Hard Failure) ๐ŸŒŸ

7.4.1. Per-Context Counter Algorithm ๐ŸŽ€

okay bestie, one totally valid way to pick unique numbers that go up within each context is a per-context counter ๐Ÿ’– It could look something like this:

/* Transient Numeric ID selection function */

id_range = max_id - min_id + 1;
retry = id_range;
id_inc = increment() % id_range;

if( (next_id = lookup_counter(CONTEXT)) == ERROR){
     next_id = min_id + random() % id_range;
}

do {
    if ( (max_id - next_id) >= id_inc){
        next_id = next_id + id_inc;
    }
    else {
        next_id = min_id + id_inc - (max_id - next_id);
    }

    if (suitable_id(next_id)){
        store_counter(CONTEXT, next_id);
        return next_id;
    }

    retry = retry - id_inc;

} while (retry > 0);

return ERROR;

NOTE ๐Ÿ“

  • CONTEXT is the concatenation of all the elements that define a given context.
  • increment() returns a small integer that gets added to the current counter value to get the next transient numeric identifier. This value must be larger than or equal to 1, and much smaller than the number of possible values for the numeric identifiers (aka "id_range"). Most implementations go with a constant increment of 1 ๐Ÿ’… Using a value other than 1 can help mitigate some information leakages (see below) at the cost of a possible increase in identifier reuse frequency. The code above makes sure the increment it uses (id_inc) is always smaller than the number of possible values for the numeric identifiers (i.e., max_id - min_d + 1). But like we said above, this value must also be much smaller than the number of possible values for the numeric identifiers.
  • lookup_counter() returns the current counter for a given context, or an error condition if that counter doesn't exist.
  • random() is a PRNG that returns a pseudorandom unsigned integer of an appropriate size. Be careful, because "adapting" the length of the output of random() with a modulo operator (like C's %) can change the distribution of the PRNG. To keep the distribution uniform, the rejection sampling technique [Romailler2020] can be used ๐Ÿง 
  • store_counter() saves a counter value for a given context.
  • suitable_id() checks whether a candidate numeric identifier has suitable uniqueness properties.

So basically, whenever a new identifier is needed, the algorithm checks whether a counter for that context exists ๐Ÿ‘€ If it does, the counter gets incremented to get the new transient numeric identifier, and the counter gets updated. If no counter exists for that context, a new one gets created, initialized to a random value, and that value becomes the selected transient numeric identifier. This gives you a per-context counter, which means one monotonically increasing function for each context. And since each counter starts at a random value, the resulting values can't be predicted by an off-path attacker ๐Ÿ”

The choice of id_inc affects both the security and privacy properties of the resulting identifiers, and also how well they interoperate ๐Ÿฆ‹ On one hand, minimizing the increments generally minimizes the identifier reuse frequency, but the values get more predictable. On the other hand, if the increments are randomized, the identifiers get less predictable, and the information leakage from global constant increments gets mitigated. Just know that using larger increments than necessary can result in a higher numeric identifier reuse frequency.

This algorithm has the following drawbacks:

  • It requires an implementation to store each per-context counter in memory. If, because of resource management, the counter for a given context must be removed, the last transient numeric identifier used for that context is lost. So if an identifier later needs to be generated for the same context, the counter has to be recreated and reinitialized to a random value, which could possibly lead to reuse or collision of numeric identifiers ๐Ÿ˜ฌ
  • Keeping one counter for every possible "context" may, in some cases, be considered too onerous in terms of memory requirements.

Otherwise, the identifiers produced by this algorithm don't suffer from the other issues discussed in Section 8. โœจ

7.4.2. Simple PRF-Based Algorithm ๐ŸŒˆ

The goal of this algorithm is to produce monotonically increasing transient numeric identifiers (for each given context) with a randomized initial value ๐Ÿ’œ For example, if the identifiers being generated must be monotonically increasing for each {Source Address, Destination Address} set, then every possible combination of {Source Address, Destination Address} gets its own monotonically increasing sequence, and each sequence starts at a different random value.

Instead of keeping a per-context counter (like in the algorithm from Section 7.4.1), this algorithm uses a calculated technique to maintain a random offset for each possible context ๐Ÿงš

/* Initialization code */
counter = 0;

/* Transient Numeric ID selection function  */

id_range = max_id - min_id + 1;
id_inc = increment() % id_range;
offset = F(CONTEXT, secret_key);
retry = id_range;

do {
    next_id = min_id + (offset + counter) % id_range;
    counter = counter + id_inc;

    if (suitable_id(next_id)) {
        return next_id;
    }

    retry = retry - id_inc;

} while (retry > 0);

return ERROR;

NOTE ๐Ÿ“

  • CONTEXT is the concatenation of all the elements that define a given context. For example, if this algorithm is supposed to produce identifiers that are monotonically increasing for each {Source Address, Destination Address} set, then CONTEXT should be the concatenation of Source Address and Destination Address.
  • increment() has the same properties and requirements as the ones specified for increment() in Section 7.4.1.
  • F() is a PRF, with the same properties as those specified for F() in Section 7.3.
  • suitable_id() checks whether a candidate numeric identifier has suitable uniqueness properties.

In the algorithm above, the function F() gives a stateless, stable, and unpredictable offset for each given context (as identified by "CONTEXT") ๐Ÿซถ Both the "offset" and "counter" variables may take any value within the storage type range. We're restricting the resulting identifier to the range [min_id, max_id] in a similar way to the algorithm described in Section 7.1.1, so we can simply increment the "counter" variable and rely on the unsigned integer to wrap around. Neat, right? ๐Ÿ˜Ž

The result of F() is no more secure than the secret key, so "secret_key" must be unknown to the attacker and must be of a reasonable length. "secret_key" must remain stable for a given CONTEXT, because otherwise the numeric identifiers generated by this algorithm wouldn't have the desired properties (i.e., monotonically increasing for a given CONTEXT). In most cases, "secret_key" should be selected with a PRNG (see [RFC4086] for recommendations on choosing secrets) at an appropriate time, and then stored in stable or volatile storage (as necessary) for future use ๐Ÿ”‘

It should be noted that, because this algorithm uses a global counter ("counter") for selecting identifiers (i.e., all counters share the same increment space), it results in an information leakage (as described in Section 8.2). For example, say this algorithm was used for selecting TCP ephemeral ports, and an attacker could force a client to periodically establish a new TCP connection to an attacker-controlled system (or through an attacker-observable routing path). The attacker could then subtract consecutive Source Port values to find the number of outgoing TCP connections the victim host established globally in that time period (up to wrap-around issues and five-tuple collisions, of course) ๐Ÿ‘€ This information leakage could be partially mitigated by using small random values for the increments (i.e., the increment() function), instead of having increment() return the constant "1".

We nevertheless note that an improved mitigation of this information leakage could be more successfully achieved by employing the algorithm from Section 7.4.3, instead. ๐Ÿ’–

7.4.3. Double-PRF Algorithm โœจ

Okay so this one is a trade-off, bestie ๐Ÿฆ‹ You could keep a single global "counter" variable, or you could keep 2**N "counter" variables (where N is the width of the result of F()). This algorithm is the chill middle ground. It keeps an array of TABLE_LENGTH values that splits the increment space into multiple buckets. It's basically an upgrade to the algorithm from Section 7.4.2, and it looks like this:

    /* Initialization code */

    for(i = 0; i < TABLE_LENGTH; i++) {
        table[i] = random();
    }

    /* Transient Numeric ID selection function */

    id_range = max_id - min_id + 1;
    id_inc = increment() % id_range;
    offset = F(CONTEXT, secret_key1);
    index = G(CONTEXT, secret_key2) % TABLE_LENGTH;
    retry = id_range;

    do {
        next_id = min_id + (offset + table[index]) % id_range;
        table[index] = table[index] + id_inc;

        if (suitable_id(next_id)) {
            return next_id;
        }

       retry = retry - id_inc;

    } while (retry > 0);

    return ERROR;

NOTE:

The increment() function has the same properties and requirements as the ones listed for increment() in Section 7.4.1. ๐Ÿ’…

Both F() and G() are PRFs, with the same properties as the ones required for F() in Section 7.3. The results of F() and G() are no more secure than their own secret keys (secret_key1 and secret_key2, respectively), so both secret keys have to be unknown to the attacker and they have to be a reasonable length. Both secret keys must remain stable for the given CONTEXT, because otherwise the transient numeric identifiers this algorithm makes won't have the good properties you want (aka monotonically increasing for a given CONTEXT) ๐Ÿ˜ญ In most cases, both secret keys should be picked with a PRNG (see [RFC4086] for recommendations on choosing secrets) at an appropriate time, then stored in stable or volatile storage (as necessary) for later. ๐Ÿ”

table[] could be initialized with random values, as shown in the initialization code in the pseudocode above. ๐ŸŽฒ

The table[] array makes sure that successive transient numeric identifiers for a given context go up monotonically. โญ Since the increment space is split into TABLE_LENGTH different spaces, the identifier reuse frequency is (probabilistically) lower than it is for the algorithm in Section 7.4.2. That means generating an identifier for one context won't necessarily bump the identifier sequence of other contexts. Here's the fun part: the size of table[] doesn't limit how many different identifier sequences you can have. It separates the increment space into TABLE_LENGTH different spaces instead ๐Ÿงš The selected transient numeric identifier sequence is made by adding the matching entry from table[] to the value in the offset variable. That's what picks the actual identifier sequence space, just like in the algorithm from Section 7.4.2.

An attacker can do traffic analysis on any "increment space" (aka context) they have "visibility" into. Basically, the attacker can force a system to generate identifiers for G(CONTEXT, secret_key2), and the result of G() picks out the target "increment space". ๐Ÿ‘€ Still, the attacker's ability to do traffic analysis is way reduced compared to the simple PRF-based identifiers (described in Section 7.4.2) and the predictable linear identifiers (described in Appendix A.1). ๐Ÿ™Œ An implementation can also make the attacker's life even harder by splitting the increment space further (using a bigger value for TABLE_LENGTH) and/or by randomizing the increments (so increment() returns a small random number instead of the constant "1").

Otherwise, this algorithm doesn't have the issues discussed in Section 8. ๐ŸŽ€


8. Common Vulnerabilities Associated with Transient Numeric Identifiers ๐Ÿšจ

8.1. Network Activity Correlation ๐Ÿ•ต๏ธโ€โ™€๏ธ

An identifier that is predictable within a given context lets people correlate network activity within that context. ๐Ÿ‘€

For example, a stable IPv6 Interface Identifier lets network activity get correlated within the context where the Interface Identifier stays stable [RFC7721]. A stable per-network IPv6 Interface Identifier (as in [RFC7217]) lets network activity get correlated within a network. A constant IPv6 Interface Identifier (one that stays the same across networks) lets people correlate activity not only within the same network but also across networks ("host-tracking"). ๐Ÿ˜ณ

Similarly, an implementation that makes TCP ISNs with a global counter could allow fingerprinting and network activity correlation across networks. An attacker could passively figure out who the victim is from the TCP ISNs used in later communication instances. Same vibe with an implementation that makes predictable IPv6 Identification values: it could be subject to fingerprinting attacks (see, e.g., [Bellovin2002]). ๐Ÿซฃ

8.2. Information Leakage ๐Ÿซข

Transient numeric identifiers that show specific patterns can leak information to other communicating entities. For example, it's common to make transient numeric identifiers with an algorithm like this:

           ID = offset(CONTEXT) + mono(CONTEXT);

This generic expression makes identifiers by adding a monotonically increasing function (e.g., linear) to a randomized offset. offset() is constant within a given context, while mono() produces a monotonically increasing sequence for the given context. Identifiers made with this expression are generally going to be predictable within CONTEXT. ๐ŸŽฏ

The predictability of mono() can leak info that's useful to attackers, even when offset() itself isn't predictable. For example, a node that picks transport-protocol ephemeral port numbers like this:

           ephemeral_port = offset(IP_Dst_Addr) + mono()

uses a per-destination offset but a global mono() function (e.g., a global counter). That leaks info about the total number of outgoing connections the vulnerable implementation has made. ๐Ÿ“ˆ

Similarly, a node that makes IPv6 Identification values like this:

           ID = offset(IP_Src_Addr, IP_Dst_Addr) + mono()

leaks info about the total number of fragmented packets the vulnerable implementation has sent. ๐Ÿ’€ The vulnerabilities described in [Sanfilippo1998a], [Sanfilippo1998b], and [Sanfilippo1999] all come from using a global mono() function (aka a global and constant "CONTEXT") โ€” especially when it's a linear function (constant increments of 1).

Predicting transient numeric identifiers can also help with other kinds of attacks. For example, predictable TCP ISNs can open the door to super easy connection-reset and data injection attacks (see Section 8.6). ๐Ÿ˜ค

8.3. Fingerprinting ๐Ÿ”

Fingerprinting is an attacker's ability to identify or re-identify a visiting user, user agent, or device through configuration settings or other observable characteristics. Observable protocol objects and characteristics can be used to identify or re-identify all sorts of entities, from the underlying hardware or operating system (OS) (vendor, type, and version) all the way up to the user. [EFF] shows web-browser-based fingerprinting, but similar techniques can be applied at other layers and protocols, either alone or together with it. ๐Ÿง

Transient numeric identifiers are one of the observable protocol components that can be used for fingerprinting. An attacker could sample transient numeric identifiers to figure out the algorithm (and its parameters, if any) that generates them, which could reveal the underlying OS vendor, type, and version. That info could then be combined with other fingerprinting techniques and sources. ๐Ÿงฉ

Evading protocol-stack fingerprinting can be a seriously hard task ๐Ÿ˜ฉ Most systems use a wide variety of protocols, and each one has a bunch of parameters that can be set to arbitrary values or generated with all kinds of algorithms that have multiple parameters.

   |  NOTE: General protocol-based fingerprinting is discussed in
   |  [RFC6973], along with guidelines to mitigate the associated
   |  vulnerability.  [Fyodor1998] and [Fyodor2006] are classic
   |  references on OS detection via TCP/IP stack fingerprinting.
   |  Network Mapper [nmap] is probably the most popular tool for
   |  remote OS identification via active TCP/IP stack
   |  fingerprinting. p0f [Zalewski2012], on the other hand, is a
   |  tool for performing remote OS detection via passive TCP/IP
   |  stack fingerprinting.  Finally, [TBIT] is a TCP fingerprinting
   |  tool that aims at characterizing the behavior of a remote TCP
   |  peer based on active probes, which has been widely used in the
   |  research community.

Algorithms that, from the view of an observer (e.g., the legitimate communicating peer), produce specific values or patterns will allow at least some level of fingerprinting. For example, the algorithm from Section 7.3 will typically allow fingerprinting within the context where the resulting identifiers are stable. Similarly, the algorithms from Section 7.4 produce monotonically increasing sequences within a given context, so they allow at least some level of fingerprinting (when the other communicating entity can tell that different sampled identifiers belong to the same monotonically increasing sequence). ๐Ÿซ 

So, where possible, algorithms from Section 7.1 should be preferred over algorithms that produce specific values or patterns. ๐Ÿ’–

8.4. Exploitation of the Semantics of Transient Numeric Identifiers ๐Ÿง 

Identifiers that aren't semantically opaque tend to be more predictable than semantically opaque identifiers. For example, a Media Access Control (MAC) address contains an Organizationally Unique Identifier (OUI), which may identify the vendor that made the network interface card. An attacker who knows roughly which Network Interface Card (NIC) vendor is in use can use that to "guess" MAC addresses. ๐ŸŽฏ

[RFC7707] discusses a bunch of techniques for shrinking the search space during IPv6 address-scanning attacks by using the semantics of IPv6 IIDs. ๐Ÿ”Ž

8.5. Exploitation of Collisions of Transient Numeric Identifiers ๐Ÿ’ฅ

In many cases, a collision of transient network identifiers can have a hard failure severity (or can result in a hard failure severity if an attacker can cause multiple collisions deterministically, one right after another). For example, predictable IP Identification values open the door to Denial of Service (DoS) attacks (see, e.g., [RFC5722].). ๐Ÿšซ๐Ÿ’…

8.6. Exploitation of Predictable Transient Numeric Identifiers for Injection Attacks โœจ

Okay so some protocols rely on "sequence numbers" to check that incoming packets are legit ๐Ÿง. TCP uses sequence numbers to put TCP segments back together, and IPv4 and IPv6 use Identification values to reassemble their fragments ๐Ÿงฉ. These protocols don't have built-in crypto for validating packets, so they're open to on-path data injection (see, e.g., [Joncheray1995]) and/or control-information injection (see, e.g., [RFC4953] and [RFC5927]) attacks ๐Ÿ˜ฌ. How well they hold up against off-path ("blind") injection depends on whether those "sequence numbers" are predictable, and how much effort it would take to guess a valid one (see, e.g., [RFC4953] and [RFC5927]) ๐Ÿ”.

We need to be real about this part ๐Ÿ’€. Using unpredictable "sequence numbers" is a completely ineffective fix for on-path injection, and it's mostly ineffective against off-path (blind) injection too ๐Ÿ™…โ€โ™€๏ธ. Still, lots of legacy protocols (TCP included) don't bake crypto into the core protocol. They treat it as an optional feature (see, e.g., [RFC5925]), if it's available at all ๐ŸŽ€. And ad hoc crypto might not be enough to let an implementation skip generating good transient numeric identifiers ๐Ÿซ . For example, using Transport Layer Security (TLS) [RFC8446] on top of TCP protects the application protocol, but it won't help with stuff like TCP-based connection-reset attacks (see, e.g., [RFC4953]) ๐Ÿ˜ญ. Same deal with SEcure Neighbor Discovery (SEND) [RFC3971]: you still end up relying on successfully reassembling IPv6 fragments whenever SEND packets don't fit into the link Maximum Transmission Unit (MTU) (see [RFC6980]) ๐Ÿงต.

8.7. Cryptanalysis ๐Ÿ”

Lots of the algorithms in this document (like the ones in Sections 7.4.2 and 7.4.3) rely on PRFs. If an implementation uses weak PRFs or keys of the wrong size, it can get cryptanalyzed ๐Ÿ˜ต. An attacker could then grab the secret key used for the PRF, predict numeric identifiers, and so on ๐Ÿ‘€.

It gets even worse if an implementation overloads what the secret key is for. That can make cryptanalysis way more trivial, and the value used as the secret key might leak out ๐Ÿšจ.

NOTE: [IPID-DEV] describes two vulnerable transient numeric identifier generators that use cryptographically weak hash functions ๐Ÿ™ˆ. One of those implementations also uses 32 bits of a kernel address as the secret key for a hash function. So if someone cryptanalyzes it successfully, the kernel address leaks, and that allows a Kernel Address Space Layout Randomization (KASLR) [KASLR] bypass ๐Ÿ’€๐Ÿšจ.

9. Vulnerability Assessment of Transient Numeric Identifiers ๐Ÿ”Ž

Okay, this section is where we check each algorithm from Section 7 for possible vulnerabilities ๐Ÿ•ต๏ธโ€โ™€๏ธ. Let's go category by category ๐Ÿ’–.

9.1. Category #1: Uniqueness (Soft Failure) ๐ŸŒธ

For the algorithms from Section 7.1, possible vulnerabilities include:

  • use of flawed PRNGs (please see, e.g., [Zalewski2001], [Zalewski2002], [Klein2007], and [CVEs])
  • inadvertently affecting the distribution of an otherwise suitable PRNG (please see, e.g., [Romailler2020])

Where they're available, CSPRNGs should be preferred over regular PRNGs, like POSIX random(3) implementations ๐Ÿ”. If a CSPRNG isn't readily available, you should do a security and privacy assessment of using a regular PRNG, and that assessment should back up the decision ๐Ÿ“.

NOTE: Check out [RFC4086] for the randomness requirements for security ๐ŸŽ€. [Aumasson2018], [Press1992], and [Knuth1983] dig into the theory and practice of random number generation, and they give guidance on how to evaluate PRNGs ๐Ÿ“š.

When you're using a PRNG, lots of implementations "adapt" its output length with a modulo operator (like C's "%") ๐Ÿงฎ. That can change the distribution of the PRNG's output, which is kind of sneaky ๐Ÿ™ƒ.

Say an implementation uses this code:

              id = random() % 50000;

The goal here is a transient numeric identifier in the range 0-49999 ๐ŸŽฏ. But if random() gives out a pseudorandom 16-bit number with a uniform distribution, the chosen identifier ends up nonuniform. The numbers in the range 0-15535 come up with double the frequency of the numbers in the range 15536-49999 ๐Ÿ˜ณ.

NOTE: In that sample code, both an output of 10 and an output of 50010 from the random() function give an "id" value of 10 ๐Ÿ™ˆ.

This effect gets smaller if the PRNG produces output that's much longer than the length the modulo operation implies ๐Ÿ“‰. To keep a uniform distribution, the rejection sampling technique [Romailler2020] can be used ๐Ÿ’ซ.

Using algorithms other than PRNGs for identifiers in this category is discouraged ๐Ÿ™…โ€โ™€๏ธ.

9.2. Category #2: Uniqueness (Hard Failure) ๐Ÿ’…

As noted in Section 7.2, this category can use the same algorithms as Category #4, because a monotonically increasing sequence tends to keep transient numeric identifier reuse frequency low ๐Ÿ“ˆ. So the vulnerability analysis in Section 9.4 also applies here โœจ.

On top of that, as noted in Section 7.2, some identifiers in this category might be able to use the algorithms from Section 7.1 ๐Ÿ”. In that case, the same considerations from Section 9.1 would apply ๐Ÿง .

9.3. Category #3: Uniqueness, Stable within Context (Soft Failure) ๐Ÿฆ‹

For the algorithms from Section 7.3, these are the possible vulnerabilities:

  • Using weak PRFs or inappropriate secret keys (whether that's a bad choice or the wrong size) could allow cryptanalysis ๐Ÿ”“. An attacker could eventually use that to predict future transient numeric identifiers ๐Ÿ”ฎ.
  • Since the algorithm makes a unique, stable identifier within a specified context, it may allow network activity correlation and fingerprinting within that context ๐Ÿ‘€.

9.4. Category #4: Uniqueness, Monotonically Increasing within Context (Hard Failure) ๐Ÿ”ฅ

The algorithm from Section 7.4.1 for generating Category #4 identifiers gives an identifiable pattern, namely a monotonically increasing sequence, for the transient numeric identifiers generated for each CONTEXT ๐Ÿ˜ญ. That means fingerprinting and network activity correlation within each CONTEXT are possible ๐Ÿ•ธ๏ธ.

Now, a simple way to generalize and analyze the algorithms from Sections 7.4.2 and 7.4.3 for Category #4 looks like this ๐Ÿง:

       /* Transient Numeric ID selection function */

       id_range = max_id - min_id + 1;
       retry = id_range;
       id_inc = increment() % id_range;

       do {
           update_mono(CONTEXT, id_inc);
           next_id = min_id + (offset(CONTEXT) + \
                               mono(CONTEXT)) % id_range;

           if (suitable_id(next_id)) {
               return next_id;
           }

           retry = retry - id_inc;

       } while (retry > 0);

       return ERROR;

Here's the vibe for the helper pieces ๐Ÿงš:

  • increment() returns a small integer that's used to build a monotonically increasing function. Most implementations use a constant value for "increment()", usually 1. The value increment() returns must be much smaller than the value computed for "id_range" ๐Ÿ“.
  • update_mono(CONTEXT, id_inc) bumps the counter for CONTEXT by "id_inc" ๐Ÿ”ผ.
  • mono(CONTEXT) reads the counter for CONTEXT ๐Ÿ‘“.

Basically, next_id is made by adding a monotonically increasing function (mono()) to an offset value. That offset is unknown to the attacker and stays stable for a given context (CONTEXT) ๐Ÿคซ.

A few things to keep in mind here ๐Ÿ’ญ:

  • Mostly, it's the offset() function that makes identifiers unpredictable to an off-path attacker ๐Ÿ™Œ. The sequence itself is known to be monotonically increasing, but the randomized offset keeps the actual values unknown to the attacker ๐Ÿซถ.
  • The most straightforward "stateless" way to do offset() is a PRF that takes the values identifying the context, plus a secret key (not shown in the figure above), as arguments ๐Ÿ”‘.
  • mono() could be implemented in a couple of ways. It could use a single counter, like in the algorithm from Section 7.4.2. Or it could map the increments for different contexts into a bunch of counters or buckets, so fewer counters need to sit in memory, like in the "Double-PRF Algorithm" from Section 7.4.3 ๐Ÿชฃ.
  • In every case, a monotonically increasing function works by adding increment() units to the previous counter value โž•. In the simplest case, increment() just returns the constant "1" 1๏ธโƒฃ. But increment() could also return small random integers, which makes the increments unpredictable (see Appendix A.2 of this document) ๐ŸŽฒ. That's a trade-off between how unpredictable the transient numeric identifiers are and how often they get reused ๐ŸŽข.

Looking at the generic algorithm above, these are the possible vulnerabilities ๐Ÿšฉ:

  • The algorithms in this category are similar to the ones in Section 9.3, plus a monotonically increasing function. So everything discussed in Section 9.3 ("Category #3: Uniqueness, Stable within Context (Soft Failure)") also applies here ๐Ÿ”.
  • mono() can be correlated with the number of identifiers generated for a given context (CONTEXT) ๐Ÿ“Š. So if mono() spans more than it needs to, the "increments" could leak to other parties. That would reveal how many identifiers the algorithm has generated across all contexts ๐Ÿ˜ฑ. This leak is way more obvious when an implementation uses a constant increment of 1. For example, if mono() is just one global counter, it unnecessarily leaks how many identifiers the algorithm has generated overall, across all contexts ๐Ÿ™ˆ. [Fyodor2003] describes one example of how these information leaks can be exploited ๐Ÿ•ต๏ธ. Limiting the span of the increment space means storing more counters in memory, so you'd need a larger value for the TABLE_LENGTH parameter of the algorithm in Section 7.4.3 ๐Ÿงฑ.
  • Transient numeric identifiers generated with the algorithms from Sections 7.4.2 and 7.4.3 will normally allow fingerprinting within CONTEXT, because for that context the identifiers show an identifiable pattern (a monotonically increasing sequence) ๐Ÿซฃ.

10. IANA Considerations ๐Ÿ“ฎ

This document has no IANA actions ๐ŸŒท.

11. Security Considerations ๐Ÿ”โœจ

Okay bestie, this whole document is about the security and privacy vibes of transient numeric identifiers ๐Ÿซฃ It's literally the main plot. [RFC9416] says protocol specs should spell out the interoperability requirements for their transient numeric identifiers, do a vulnerability assessment of them, and recommend an algorithm for generating each one ๐Ÿ’… This document looks at possible algorithms (and what they do to your security and privacy) that could meet the interoperability requirements for the most common categories of transient numeric identifiers, while keeping the negative security and privacy fallout as low as possible ๐Ÿ›ก๏ธ๐Ÿ’œ

12. References ๐Ÿ“š๐ŸŽ€

12.1. Normative References ๐Ÿ’Œ

12.2. Informative References ๐Ÿ“š๐Ÿฆ‹

Okay bestie, these are the extra-credit reads ๐Ÿงš For when you want to go full rabbit hole, here's the whole reading list, copied exactly as the original has it:

   [ARC4RANDOM]
              OpenBSD, "arc4random(3)", Library Functions Manual,
              September 2019, <https://man.openbsd.org/arc4random>.

   [Aumasson2018]
              Aumasson, J-P., "Serious Cryptography: A Practical
              Introduction to Modern Encryption", No Starch Press, Inc.,
              ISBN-10 1-59327-826-8, November 2017.

   [Bellovin1989]
              Bellovin, S., "Security Problems in the TCP/IP Protocol
              Suite", Computer Communications Review, Vol. 19, No. 2,
              pp. 32-48, April 1989,
              <https://www.cs.columbia.edu/~smb/papers/ipext.pdf>.

   [Bellovin2002]
              Bellovin, S., "A Technique for Counting NATted Hosts",
              IMW'02, Marseille, France, ISBN 1-58113-603-X/02/0011,
              November 2002,
              <https://www.cs.columbia.edu/~smb/papers/fnat.pdf>.

   [BLAKE3]   "BLAKE3: one function, fast everywhere", September 2022,
              <https://blake3.io/>.

   [C11]      ISO/IEC, "Information technology - Programming languages -
              C", ISO/IEC 9899:2018, June 2018.

   [CPNI-TCP] Centre for the Protection of National Infrastructure
              (CPNI), "Security Assessment of the Transmission Control
              Protocol (TCP)", CPNI Technical Note 3/2009, February
              2009, <https://www.si6networks.com/files/publications/tn-
              03-09-security-assessment-TCP.pdf>.

   [CVEs]     NVD, "Vulnerability Advisories for PRNGs",
              <https://www.gont.com.ar/miscellanea/prng-cves/>.

   [EFF]      EFF, "Cover your tracks: See how trackers view your
              browser", <https://coveryourtracks.eff.org/>.

   [FIPS-SHS] NIST, "Secure Hash Standard (SHS)", FIPS PUB 180-4,
              DOI 10.6028/NIST.FIPS.180-4, August 2015,
              <https://nvlpubs.nist.gov/nistpubs/FIPS/
              NIST.FIPS.180-4.pdf>.

   [Fyodor1998]
              Fyodor, "Remote OS detection via TCP/IP Stack
              FingerPrinting", Phrack Magazine, Volume 8, Issue 54,
              December 1998,
              <http://www.phrack.org/archives/issues/54/9.txt>.

   [Fyodor2003]
              Fyodor, "Idle Scanning and related IPID games", 2003,
              <https://nmap.org/presentations/CanSecWest03/CD_Content/
              idlescan_paper/idlescan.html>.

   [Fyodor2006]
              Lyon, G., "Chapter 8. Remote OS Detection", January 2009,
              <https://nmap.org/book/osdetect.html>.

   [GETENTROPY]
              Linux, "getentropy(3)", Linux Programmer's Manual, March
              2021,
              <https://man7.org/linux/man-pages/man3/getentropy.3.html>.

   [IANA-PROT]
              IANA, "Protocol Registries",
              <https://www.iana.org/protocols>.

   [IPID-DEV] Klein, A. and B. Pinkas, "From IP ID to Device ID and
              KASLR Bypass (Extended Version)",
              DOI 10.48550/arXiv.1906.10478, October 2019,
              <https://arxiv.org/pdf/1906.10478.pdf>.

   [Joncheray1995]
              Joncheray, L., "Simple Active Attack Against TCP",
              Proceedings of the Fifth USENIX UNIX Security Symposium,
              June 1995, <https://www.usenix.org/legacy/publications/lib
              rary/proceedings/security95/full_papers/joncheray.pdf>.

   [KASLR]    PaX Team, "Address Space Layout Randomization",
              <https://pax.grsecurity.net/docs/aslr.txt>.

   [Klein2007]
              Klein, A., "OpenBSD DNS Cache Poisoning and Multiple O/S
              Predictable IP ID Vulnerability", November 2007,
              <https://dl.packetstormsecurity.net/papers/attack/OpenBSD_
              DNS_Cache_Poisoning_and_Multiple_OS_Predictable_IP_ID_Vuln
              erability.pdf>.

   [Knuth1983]
              Knuth, D., "The Art of Computer Programming", Volume 2
              (Seminumerical Algorithms), 2nd Ed., Reading,
              Massachusetts, Addison-Wesley Publishing Company, January
              1981.

   [Morris1985]
              Morris, R., "A Weakness in the 4.2BSD UNIX TCP/IP
              Software", CSTR 117, AT&T Bell Laboratories, Murray Hill,
              NJ, February 1985,
              <https://pdos.csail.mit.edu/~rtm/papers/117.pdf>.

   [nmap]     nmap, "Nmap: Free Security Scanner For Network Exploration
              and Audit", 2020, <https://nmap.org/>.

   [POSIX]    IEEE, "IEEE Standard for Information Technology --
              Portable Operating System Interface (POSIX(TM)) Base
              Specifications, Issue 7", IEEE Std 1003.1-2017,
              DOI 10.1109/IEEESTD.2018.8277153, January 2018,
              <https://doi.org/10.1109/IEEESTD.2018.8277153>.

   [Press1992]
              Press, W., Teukolsky, S., Vetterling, W., and B. Flannery,
              "Numerical Recipes in C: The Art of Scientific Computing",
              2nd Ed., Cambridge University Press, ISBN 0-521-43108-5,
              December 1992.

   [RFC2104]  Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-
              Hashing for Message Authentication", RFC 2104,
              DOI 10.17487/RFC2104, February 1997,
              <https://www.rfc-editor.org/info/rfc2104>.

   [RFC3971]  Arkko, J., Ed., Kempf, J., Zill, B., and P. Nikander,
              "SEcure Neighbor Discovery (SEND)", RFC 3971,
              DOI 10.17487/RFC3971, March 2005,
              <https://www.rfc-editor.org/info/rfc3971>.

   [RFC4953]  Touch, J., "Defending TCP Against Spoofing Attacks",
              RFC 4953, DOI 10.17487/RFC4953, July 2007,
              <https://www.rfc-editor.org/info/rfc4953>.

   [RFC4963]  Heffner, J., Mathis, M., and B. Chandler, "IPv4 Reassembly
              Errors at High Data Rates", RFC 4963,
              DOI 10.17487/RFC4963, July 2007,
              <https://www.rfc-editor.org/info/rfc4963>.

   [RFC5927]  Gont, F., "ICMP Attacks against TCP", RFC 5927,
              DOI 10.17487/RFC5927, July 2010,
              <https://www.rfc-editor.org/info/rfc5927>.

   [RFC6194]  Polk, T., Chen, L., Turner, S., and P. Hoffman, "Security
              Considerations for the SHA-0 and SHA-1 Message-Digest
              Algorithms", RFC 6194, DOI 10.17487/RFC6194, March 2011,
              <https://www.rfc-editor.org/info/rfc6194>.

   [RFC6274]  Gont, F., "Security Assessment of the Internet Protocol
              Version 4", RFC 6274, DOI 10.17487/RFC6274, July 2011,
              <https://www.rfc-editor.org/info/rfc6274>.

   [RFC6973]  Cooper, A., Tschofenig, H., Aboba, B., Peterson, J.,
              Morris, J., Hansen, M., and R. Smith, "Privacy
              Considerations for Internet Protocols", RFC 6973,
              DOI 10.17487/RFC6973, July 2013,
              <https://www.rfc-editor.org/info/rfc6973>.

   [RFC6980]  Gont, F., "Security Implications of IPv6 Fragmentation
              with IPv6 Neighbor Discovery", RFC 6980,
              DOI 10.17487/RFC6980, August 2013,
              <https://www.rfc-editor.org/info/rfc6980>.

   [RFC7098]  Carpenter, B., Jiang, S., and W. Tarreau, "Using the IPv6
              Flow Label for Load Balancing in Server Farms", RFC 7098,
              DOI 10.17487/RFC7098, January 2014,
              <https://www.rfc-editor.org/info/rfc7098>.

   [RFC7258]  Farrell, S. and H. Tschofenig, "Pervasive Monitoring Is an
              Attack", BCP 188, RFC 7258, DOI 10.17487/RFC7258, May
              2014, <https://www.rfc-editor.org/info/rfc7258>.

   [RFC7707]  Gont, F. and T. Chown, "Network Reconnaissance in IPv6
              Networks", RFC 7707, DOI 10.17487/RFC7707, March 2016,
              <https://www.rfc-editor.org/info/rfc7707>.

   [RFC7721]  Cooper, A., Gont, F., and D. Thaler, "Security and Privacy
              Considerations for IPv6 Address Generation Mechanisms",
              RFC 7721, DOI 10.17487/RFC7721, March 2016,
              <https://www.rfc-editor.org/info/rfc7721>.

   [RFC7739]  Gont, F., "Security Implications of Predictable Fragment
              Identification Values", RFC 7739, DOI 10.17487/RFC7739,
              February 2016, <https://www.rfc-editor.org/info/rfc7739>.

   [RFC8446]  Rescorla, E., "The Transport Layer Security (TLS) Protocol
              Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018,
              <https://www.rfc-editor.org/info/rfc8446>.

   [RFC8937]  Cremers, C., Garratt, L., Smyshlyaev, S., Sullivan, N.,
              and C. Wood, "Randomness Improvements for Security
              Protocols", RFC 8937, DOI 10.17487/RFC8937, October 2020,
              <https://www.rfc-editor.org/info/rfc8937>.

   [RFC9414]  Gont, F. and I. Arce, "Unfortunate History of Transient
              Numeric Identifiers", RFC 9414, DOI 10.17487/RFC9414, July
              2023, <https://www.rfc-editor.org/info/rfc9414>.

   [RFC9416]  Gont, F. and I. Arce, "Security Considerations for
              Transient Numeric Identifiers Employed in Network
              Protocols", BCP 72, RFC 9416, DOI 10.17487/RFC9416, July
              2023, <https://www.rfc-editor.org/info/rfc9416>.

   [Romailler2020]
              Romailler, Y., "The Definitive Guide to "Modulo Bias and
              How to Avoid It"!", Kudelski Security Research, July 2020,
              <https://research.kudelskisecurity.com/2020/07/28/the-
              definitive-guide-to-modulo-bias-and-how-to-avoid-it/>.

   [Sanfilippo1998a]
              Sanfilippo, S., "about the ip header id", message to the
              Bugtraq mailing list, December 1998,
              <http://seclists.org/bugtraq/1998/Dec/48>.

   [Sanfilippo1998b]
              Sanfilippo, S., "new tcp scan method", message to the
              Bugtraq mailing list, 18 December 1998,
              <https://seclists.org/bugtraq/1998/Dec/79>.

   [Sanfilippo1999]
              Sanfilippo, S., "more ip id", message to the Bugtraq
              mailing list, November 1999,
              <https://github.com/antirez/hping/raw/master/docs/MORE-
              FUN-WITH-IPID>.

   [Schuba1993]
              Schuba, C., "Addressing Weakness in the Domain Name System
              Protocol", August 1993,
              <http://ftp.cerias.purdue.edu/pub/papers/christoph-schuba/
              schuba-DNS-msthesis.pdf>.

   [Shimomura1995]
              Shimomura, T., "Technical details of the attack described
              by Markoff in NYT", message to the USENET
              comp.security.misc newsgroup, 25 January 1995,
              <https://www.gont.com.ar/files/post-shimomura-usenet.txt>.

   [Silbersack2005]
              Silbersack, M., "Improving TCP/IP security through
              randomization without sacrificing interoperability",
              EuroBSDCon 2005 Conference,
              <https://www.silby.com/eurobsdcon05/
              eurobsdcon_silbersack.pdf>.

   [SipHash]  "SipHash: a fast short-input PRF", February 2023,
              <https://github.com/veorq/SipHash>.

   [TBIT]     TBIT, "TBIT, the TCP Behavior Inference Tool", 2001,
              <https://www.icir.org/tbit/>.

   [TCPT-uptime]
              McDanel, B., "TCP Timestamping - Obtaining System Uptime
              Remotely", message to the Bugtraq mailing list, March
              2001, <https://seclists.org/bugtraq/2001/Mar/182>.

   [Zalewski2001]
              Zalewski, M., "Strange Attractors and TCP/IP Sequence
              Number Analysis", April 2001,
              <https://lcamtuf.coredump.cx/oldtcp/tcpseq.html>.

   [Zalewski2002]
              Zalewski, M., "Strange Attractors and TCP/IP Sequence
              Number Analysis - One Year Later (2002)",
              <https://lcamtuf.coredump.cx/newtcp/>.

   [Zalewski2012]
              Zalewski, M., "p0f v3 (3.09b)",
              <https://lcamtuf.coredump.cx/p0f.shtml>.

Appendix A. Algorithms and Techniques with Known Issues ๐ŸŽ€

okay so this appendix is basically the "don't do this, bestie" section ๐Ÿ’€ it covers algorithms and techniques with known negative security and privacy implications. yikes.

   |  NOTE: As discussed in Section 1, the use of cryptographic
   |  techniques might allow for the safe use of some of these
   |  algorithms and techniques.  However, this should be evaluated
   |  on a case-by-case basis.
NOTE: crypto might make some of these safe-ish, but you have to evaluate each one case by case. no shortcuts ๐Ÿ™ˆ

A.1. Predictable Linear Identifiers Algorithm ๐Ÿฆ‹

one of the most basic ways to get uniqueness with a low identifier reuse frequency is to just make a linear sequence. this kind of algorithm has been used in the past to generate identifiers of Categories #1, #2, and #4 (check Section 6 for the breakdown of those categories, it's giving analysis ๐Ÿ“Š).

for example, the following algorithm has shown up (see, e.g., [Morris1985], [Shimomura1995], [Silbersack2005], and [CPNI-TCP]) in a bunch of operating systems for picking IP IDs, TCP ephemeral port numbers, etc. ๐ŸŒธ

/* Initialization code */

next_id = min_id;
id_inc= 1;


/* Transient Numeric ID selection function */

id_range = max_id - min_id + 1;
retry = id_range;

do {
    if (next_id == max_id) {
        next_id = min_id;
    }
    else {
        next_id = next_id + id_inc;
    }

    if (suitable_id(next_id)) {
        return next_id;
    }

    retry--;

} while (retry > 0);

return ERROR;
NOTE: suitable_id() checks whether a candidate numeric identifier is suitable (e.g., whether it is unique or not).

okay so for obvious reasons, this algorithm gives you predictable sequences ๐Ÿ˜ญ. since one global counter makes the transient numeric identifiers (that's next_id in the example above), anyone who learns one numeric identifier can work out past ones and predict future values from the same algorithm. the increment is known (it's 1 here), so an attacker can sample two values and figure out how many identifiers were generated in between. and if the counter gets initialized to some known value (like when the system boots), the algorithm leaks even more info, like how many fragmented datagrams were sent in the case of an IP ID generator [Sanfilippo1998a], or the system uptime in the case of TCP timestamps [TCPT-uptime]. the way this leaks everything is literally iconic for all the wrong reasons ๐Ÿ’€

A.2. Random-Increments Algorithm ๐Ÿ“

this one is kind of a middle ground between the algorithms that generate randomized transient numeric identifiers (like the ones in Sections 7.1.1 and 7.1.2) and the ones that generate identifiers with a predictable monotonically increasing function (see Appendix A.1). okay that's a whole vibe ๐Ÿงš

/* Initialization code */

next_id = random();        /* Initialization value */
id_rinc = 500;             /* Determines the trade-off */


/* Transient Numeric ID selection function */

id_range = max_id - min_id + 1;
retry = id_range;


do {
    /* Random increment */
    id_inc = (random() % id_rinc) + 1;

    if ( (max_id - next_id) >= id_inc){
        next_id = next_id + id_inc;
    }
    else {
        next_id = min_id + id_inc - (max_id - next_id);
    }

    if (suitable_id(next_id)) {
       return next_id;
    }

    retry = retry - id_inc;

} while (retry > 0);

return ERROR;
NOTE: random() is a PRNG that returns a pseudorandom unsigned integer number of appropriate size. Beware that "adapting" the length of the output of random() with a modulo operator (e.g., C language's %) may change the distribution of the PRNG. To preserve a uniform distribution, the rejection sampling technique [Romailler2020] can be used. suitable_id() is a function that checks whether a candidate identifier is suitable (e.g., whether it is unique or not).

the goal here is to get a global monotonically increasing sequence of transient numeric identifiers while avoiding fixed increments, since those would be trivially predictable ๐Ÿ”ฎ. the value id_rinc lets you directly control the trade-off between unpredictability and identifier reuse frequency. the smaller id_rinc is, the more it acts like a predictable, global linear identifier generator (like the one in Appendix A.1). the bigger id_rinc is, the more it acts like the algorithm in Section 7.1.1 of this document. โœจ

when the identifiers wrap around, there's a risk of collisions (aka identifier reuse), so id_rinc should be picked using these criteria:

  • It should maximize the wrapping time of the identifier space.
  • It should minimize identifier reuse frequency.
  • It should maximize unpredictability.

these goals are literally competing with each other, so picking id_rinc is a trade-off. that's why its value is sometimes a configurable parameter, so system administrators can make the call for themselves ๐Ÿซถ. we also note that the alternative algorithms discussed throughout this document offer better interoperability, security, and privacy properties than this one, so implementation of this algorithm is discouraged ๐Ÿ™…โ€โ™€๏ธ.

A.3. Reusing Identifiers Across Different Contexts ๐ŸŒˆ

using the same identifier across contexts where stability isn't required (aka overloading the semantics of transient numeric identifiers) usually has negative security and privacy implications. the vibes are not it ๐Ÿ‘Ž

for example, when you want to generate transient numeric identifiers of Category #2 or #3, an implementation or spec might be tempted to use a source that's known to give unique values but that could also be predictable or leak info about the entity generating the identifier. this has happened before, e.g., generating IPv6 IIDs by reusing the MAC address of the underlying network interface card. but as noted in [RFC7721] and [RFC7707], embedding link-layer addresses in IPv6 IIDs doesn't just give you predictable values, it also leaks info about the manufacturer of the NIC, allows network activity correlation, and makes address-based scanning attacks feasible. bestie no ๐Ÿ˜ญ๐Ÿ”ฅ


Acknowledgements โœจ

the authors want to thank (in alphabetical order) Bernard Aboba, Jean-Philippe Aumasson, Steven Bellovin, Luis Leรณn Cรกrdenas Graide, Spencer Dawkins, Theo de Raadt, Guillermo Gont, Joseph Lorenzo Hall, Gre Norcie, Colin Perkins, Vincent Roca, Shivan Sahib, Rich Salz, Martin Thomson, and Michael Tรผxen for giving super valuable comments on earlier draft versions of this document ๐Ÿซถ๐Ÿ’œ.

the authors also want to thank Shivan Sahib and Christopher Wood for their guidance during the publication process ๐ŸŽ€.

the authors want to thank Jean-Philippe Aumasson and Mathew D. Green (John Hopkins University) for kindly answering a bunch of questions ๐Ÿงš.

the authors want to thank Diego Armando Maradona for his magic and inspiration โญโšฝ๐Ÿ’….

Authors' Addresses ๐ŸŒธ

Fernando Gont
SI6 Networks
Segurola y Habana 4310 7mo piso
Ciudad Autonoma de Buenos Aires
Argentina
Email: fgont@si6networks.com
URI:   https://www.si6networks.com


Ivan Arce
Quarkslab
Segurola y Habana 4310 7mo piso
Ciudad Autonoma de Buenos Aires
Argentina
Email: iarce@quarkslab.com
URI:   https://www.quarkslab.com
๐Ÿ“ฆ where this page comes from