RFC 8492

Secure Password Ciphersuites for Transport Layer Security (TLS)

๐Ÿ“… published February 2019, from ietf

Secure Password Ciphersuites for Transport Layer Security (TLS) ๐ŸŽ€

okay so this one is an Independent Submission (aka it came in from outside the usual IETF stream ๐ŸŒธ), written by D. Harkins, Ed. over at HP Enterprise, and it's dated February 2019. It's labeled Informational, which means it's published for info and isn't an Internet Standard, and it's RFC 8492 with ISSN 2070-1721. It doesn't list anything it obsoletes or updates. That's the whole tea on the title block โ˜•


Abstract โœจ

bestie, this memo defines a few new ciphersuites for TLS so you can do certificateless, secure auth using just a simple, low-entropy password ๐Ÿ” The exchange is called "TLS-PWD", and all the ciphersuites are built on a protocol called "dragonfly", which is resistant to offline dictionary attacks. the girlies at the back are screaming ๐Ÿ˜ญ


Status of This Memo ๐Ÿ“œ

this document is not an Internet Standards Track spec. it's just published for informational purposes ๐Ÿ’…

it's a contribution to the RFC Series, independent of any other RFC stream. the RFC Editor chose to publish it at their discretion, and they make no statement about its value for implementation or deployment ๐Ÿซถ documents approved by the RFC Editor aren't candidates for any level of Internet Standard. see Section 2 of RFC 7841 for that.

if you want the current status, any errata, or a way to give feedback, check https://www.rfc-editor.org/info/rfc8492 ๐Ÿฆ‹


Copyright (c) 2019 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 in effect on the date of publication. please actually read these, because they spell out your rights and restrictions for this doc ๐Ÿ™ˆ


Table of Contents ๐Ÿงš

1. Introduction and Motivation .....................................3
   1.1. The Case for Certificateless Authentication ................3
   1.2. Resistance to Dictionary Attacks ...........................3
2. Key Words .......................................................4
3. Notation and Background .........................................4
   3.1. Notation ...................................................4
   3.2. Discrete Logarithm Cryptography ............................5
        3.2.1. Elliptic Curve Cryptography .........................5
        3.2.2. Finite Field Cryptography ...........................7
   3.3. Instantiating the Random Function ..........................8
   3.4. Passwords ..................................................8
   3.5. Assumptions ................................................9
4. Specification of the TLS-PWD Handshake .........................10
   4.1. TLS-PWD Pre-TLS 1.3 .......................................10
   4.2. TLS-PWD in TLS 1.3 ........................................11
   4.3. Protecting the Username ...................................11
        4.3.1. Construction of a Protected Username ...............12
        4.3.2. Recovery of a Protected Username ...................13
   4.4. Fixing the Password Element ...............................14
        4.4.1. Computing an ECC Password Element ..................16
        4.4.2. Computing an FFC Password Element ..................18
        4.4.3. Password Naming ....................................19
        4.4.4. Generating TLS-PWD Commit ..........................20
   4.5. Changes to Handshake Message Contents .....................20
        4.5.1. Pre-1.3 TLS ........................................20
               4.5.1.1. ClientHello Changes .......................20
               4.5.1.2. ServerKeyExchange Changes .................21
               4.5.1.3. ClientKeyExchange Changes .................23
        4.5.2. TLS 1.3 ............................................24
               4.5.2.1. TLS 1.3 KeyShare ..........................24
               4.5.2.2. ClientHello Changes .......................24
               4.5.2.3. ServerHello Changes .......................25
               4.5.2.4. HelloRetryRequest Changes .................25
   4.6. Computing the Shared Secret ...............................26
5. Ciphersuite Definition .........................................26
6. IANA Considerations ............................................27
7. Security Considerations ........................................27
8. Human Rights Considerations ....................................30
9. Implementation Considerations ..................................31
10. References ....................................................32
    10.1. Normative References .....................................32
    10.2. Informative References ...................................33
Appendix A. Example Exchange ......................................35
Acknowledgements ..................................................40
Author's Address ..................................................40

1. Introduction and Motivation ๐Ÿฆ‹

1.1. The Case for Certificateless Authentication ๐Ÿ’–

okay so TLS usually uses public key certificates for auth [RFC5246] [RFC8446]. and that's kinda messy in some cases, ngl:

  • honestly, TLS [RFC5246] often ends up on devices that are owned, operated, and set up by people who don't have the skills to use certificates properly. they just want a secure connection using a more natural credential, like a simple password ๐Ÿ™ˆ the explosion of setups using a self-signed server certificate in TLS [RFC5246], followed by a basic password exchange over the unauthenticated channel, really proves this point.
  • the other options for certificateless TLS auth are pre-shared keys (which are vulnerable to dictionary attacks) or a Secure Remote Password (SRP) exchange. SRP makes users commit up front to one specific Finite Field Cryptography (FFC) group for all future connections. neither works for modern apps that need both security and cryptographic agility ๐Ÿ’€
  • a password is a way more natural credential than a certificate (people learn what a shared secret is from early childhood ๐Ÿงธ). so a password-based TLS ciphersuite can protect an HTTP-based certificate enrollment scheme like Enrollment over Secure Transport (EST) [RFC7030]. that lets you turn a simple password into a certificate for later use with any certificate-based auth protocol. this solves a big "chicken-and-egg" problem you get with certificate-only use of [RFC5246] ๐Ÿ”ฅ
  • some PIN-code readers send the entered PIN to a smart card in cleartext. assuming a hostile environment, that's a bad practice ๐Ÿ˜ฌ a password-based TLS ciphersuite can set up an authenticated connection between the reader and the card based on the PIN.

1.2. Resistance to Dictionary Attacks ๐ŸŒธ

it's a super common misconception that a protocol authenticating with a shared, secret credential is resistant to dictionary attacks just because the credential is an N-bit uniformly random secret, where N is big enough. but resistance to dictionary attacks has nothing to do with whether the secret shows up in a dictionary of real words (like, a language's defined words, i.e., a dictionary ๐Ÿ“–). it's about how an adversary gets an advantage when attacking the protocol โœจ

for a protocol to be resistant to dictionary attacks, any advantage an adversary gains must be a function of the number of interactions she makes with an honest protocol participant, and not a function of the amount of computation she uses. so the adversary can't learn anything about the password except whether one single guess from one protocol run she took part in is correct or incorrect. slay ๐Ÿ’…

it's assumed the attacker has access to a pool of data the secret was drawn from. it could be all numbers between 1 and 2^N, or all defined words in a dictionary. the key thing is that the attacker can't attack, then go offline and run through the pool of potential secrets (computation) to see if one is right. she has to do an active attack for each secret she wants to try (interaction), and the only info she gets from that attack is whether the secret used in that particular attack is correct or not ๐Ÿซถ


2. Key Words ๐Ÿ”‘

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 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. only the all-caps versions count, so no lowercase sneaking in ๐Ÿ‘‘


3. Notation and Background ๐Ÿงš

3.1. Notation ๐Ÿ’œ

here's the notation used in this memo:

  • password: a secret (and potentially low-entropy) word, phrase, code, or key used as a credential for authentication. the password is shared between the TLS client and TLS server ๐Ÿ—๏ธ
  • y = H(x): a binary string of arbitrary length, x, is given to a function H, which produces a fixed-length output, y.
  • a | b: denotes concatenation of string "a" with string "b".
  • [a]b: indicates a string consisting of the single bit "a" repeated "b" times.
  • x mod y: indicates the remainder of division of x by y. the result will be between 0 and y.
  • len(x): indicates the length in bits of the string "x".
  • lgr(a, b): takes "a" and a prime, b, and returns the Legendre symbol (a/b).
  • LSB(x): returns the least-significant bit of the bitstring "x".
  • G.x: indicates the x-coordinate of a point, G, on an elliptic curve.

3.2. Discrete Logarithm Cryptography ๐ŸŒˆ

the ciphersuites defined in this memo use discrete logarithm cryptography (see [SP800-56A]) to produce an authenticated and shared secret value. that value is an Element in a group defined by a set of domain parameters. the domain parameters can be based on either FFC or Elliptic Curve Cryptography (ECC) โญ

elements in a group, either an FFC or ECC group, are written in uppercase, and scalar values are written in lowercase. that's the vibe for the rest of the spec ๐ŸŽ€

3.2.1. Elliptic Curve Cryptography โœจ

okay bestie, this part is about ECC ๐Ÿฆ‹ the authenticated key exchange in this memo is built on the fundamental elliptic curve algorithms over GF(p), as described in [RFC6090]. the big rule here is that ciphersuites in this memo SHALL only use ECC curves based on the Weierstrass equation y^2 = x^3 + a*x + b. no other curve shapes allowed ๐Ÿ™…โ€โ™€๏ธ

Domain parameters for the ECC groups used by this memo are:

  • A prime, p, that sets up a prime field GF(p). The cryptographic group is a subgroup of the full elliptic curve group. That full group is made of points on the curve (Elements from GF(p) that satisfy the curve's equation) plus the "point at infinity," which is the identity Element ๐ŸŒธ
  • Elements a and b from GF(p) that define the curve's equation. The point (x, y) in GF(p) x GF(p) is on the elliptic curve if and only if (y^2 - x^3 - a*x - b) mod p equals zero (0).
  • A point, G, on the elliptic curve, which serves as a generator for the ECC group. G is chosen so that its order, with respect to elliptic curve addition, is a sufficiently large prime.
  • A prime, q, which is the order of G. That makes it the size of the cryptographic subgroup generated by G ๐Ÿ’œ
  • A co-factor, f, defined by the requirement that the size of the full elliptic curve group (including the "point at infinity") be the product of f and q.

This memo uses the following ECC functions:

  • Z = elem-op(X, Y) = X + Y: two points on the curve, X and Y, get summed to make another point on the curve, Z. This is the group operation for ECC groups.
  • Z = scalar-op(x, Y) = x * Y: an integer scalar, x, acts on a point on the curve, Y, through repeated addition (Y is added to itself x times) to produce another ECC Element, Z.
  • Y = inverse(X): a point on the curve, X, has an inverse, Y, which is also a point on the curve, when their sum is the "point at infinity" (the identity for elliptic curve addition). In other words, R + inverse(R) = "0".
  • z = F(X): the x-coordinate of a point (x, y) on the curve is returned. This is a mapping function that turns a group Element into an integer ๐Ÿงš

Only ECC groups over GF(p) can be used with TLS-PWD. Characteristic-2 curves SHALL NOT be used by TLS-PWD. ECC groups over GF(2^m) SHALL NOT be used by TLS-PWD. Also, ECC groups with a co-factor greater than one (1) SHALL NOT be used by TLS-PWD. ๐Ÿ’€

A composite (x, y) pair can be validated as a point on the elliptic curve by checking that 1) both coordinates x and y are greater than zero (0) and less than the prime defining the underlying field, 2) coordinates x and y satisfy the equation of the curve, and 3) they do not represent the "point at infinity." If any of those conditions are not true, the (x, y) pair is not a valid point on the curve.

A compliant implementation of TLS-PWD SHALL support group twenty-three (23) and SHOULD support group twenty-four (24) from the "TLS Supported Groups" registry; see [TLS_REG]. ๐ŸŽ€

3.2.2. Finite Field Cryptography ๐ŸŒˆ

Domain parameters for the FFC groups used by this memo are:

  • A prime, p, that determines a prime field GF(p) (i.e., the integers modulo p). The FFC group is a subgroup of GF(p)* (i.e., the multiplicative group of non-zero Elements in GF(p)).
  • An Element, G, in GF(p)*, which serves as a generator for the FFC group. G is chosen so that its multiplicative order is a sufficiently large prime divisor of ((p - 1)/2).
  • A prime, q, which is the multiplicative order of G. That makes it the size of the cryptographic subgroup of GF(p)* generated by G ๐Ÿ“

This memo uses the following FFC functions:

  • Z = elem-op(X, Y) = (X * Y) mod p: two FFC Elements, X and Y, get multiplied modulo the prime, p, to produce another FFC Element, Z. This is the group operation for FFC groups.
  • Z = scalar-op(x, Y) = Y^x mod p: an integer scalar, x, acts on an FFC group Element, Y, through exponentiation modulo the prime, p, to produce another FFC Element, Z.
  • Y = inverse(X): a group Element, X, has an inverse, Y, when the product of the Element and its inverse modulo the prime equals one (1). In other words, (X * inverse(X)) mod p = 1.
  • z = F(X): the identity function, since an Element in an FFC group is already an integer. It's included here so the specification stays consistent ๐Ÿ’…

Many FFC groups used in IETF protocols are based on safe primes and do not define an order (q). For these groups, the order (q) used in this memo shall be the prime of the group minus one divided by two -- (p - 1)/2. ๐Ÿ™ˆ

An integer can be validated as an Element in an FFC group by checking that 1) it is between one (1) and the prime, p, exclusive, and 2) modular exponentiation of the integer by the group order, q, equals one (1). If either of these conditions is not true, the integer is not an Element in the group.

A compliant implementation of TLS-PWD SHOULD support group two hundred fifty-six (256) and group two hundred fifty-eight (258) from the "TLS Supported Groups" registry on [TLS_REG]. ๐Ÿฆ‹

3.3. Instantiating the Random Function ๐ŸŽ€

The protocol described in this memo uses a random function, H, which is modeled as a "random oracle." At first glance, you might think of it as a hash function. As noted in [RANDOR], though, hash functions are too structured to be used directly as a random oracle. But they can be used to instantiate the random oracle ๐Ÿ”ฎ

The random function, H, in this memo is instantiated by using the hash algorithm defined by the particular TLS-PWD ciphersuite in Hashed Message Authentication Code (HMAC) mode, with a key whose length is equal to the block size of the hash algorithm and whose value is zero. For example, if the ciphersuite is TLS_ECCPWD_WITH_AES_128_GCM_SHA256, then H will be instantiated with SHA256 as:

H(x) = HMAC-SHA256([0]32, x)

3.4. Passwords ๐Ÿ”

The authenticated key exchange used in TLS-PWD requires each side to have a common view of a shared credential. To protect the server's database of stored passwords, a password MAY be salted. When [RFC5246] or earlier is used, the password SHALL be salted. When [RFC8446] is used, a password MAY be stored with a salt or without. The password, username, and, optionally, the salt can create an irreversible digest called the "base," which is used in the authenticated key exchange. ๐Ÿง‚

The salting function is defined as:

base = HMAC-SHA256(salt, username | password)

The unsalted function is defined as:

base = SHA256(username | password)

The password used for generating the base SHALL be represented as a UTF-8 encoded character string, processed according to the rules of the OpaqueString profile of [RFC8265], and the salt SHALL be a 32-octet random number. The server SHALL store a tuple of the form:

{ username, base, salt }

if the password is salted, and:

{ username, base }

if it is not. When password salting is being used, the client generates the base upon receiving the salt from the server. Otherwise, it may store the base at the time the username and password are provisioned. ๐ŸŒธ

3.5. Assumptions ๐Ÿง 

The security properties of the authenticated key exchange defined in this memo are based on a number of assumptions:

  1. The random function, H, is a "random oracle" as defined in [RANDOR].
  2. The discrete logarithm problem for the chosen group is hard. That is, given g, p, and y = g^x mod p, it is computationally infeasible to determine x. Similarly, for an ECC group, given the curve definition, a generator G, and Y = x * G, it is computationally infeasible to determine x. ๐Ÿ‘‘
  3. Quality random numbers with sufficient entropy can be created. This may entail the use of specialized hardware. If such hardware is unavailable, a cryptographic mixing function (like a strong hash function) may be needed to distill entropy from multiple, uncorrelated sources of information and events. A very good discussion of this can be found in [RFC4086]. โœจ

If the server supports username protection (see Section 4.3), it is assumed that the server has chosen a domain parameter set and generated a username-protection keypair. The chosen domain parameter set and public key are assumed to be conveyed to the client at the time the client's username and password were provisioned. ๐Ÿซถ

4. Specification of the TLS-PWD Handshake ๐Ÿค

The key exchange underlying TLS-PWD is the "dragonfly" password-authenticated key exchange (PAKE) as defined in [RFC7664]. ๐Ÿ‰

The authenticated key exchange is accomplished by each side deriving a Password Element (PE) [RFC7664] in the chosen group, making a "commitment" to a single guess of the password using the PE, and generating a shared secret. The ability of each side to produce a valid finished message using a key derived from the shared secret allows each side to authenticate itself to the other side. It's giving proof without sharing the password ๐Ÿ˜ญ

The authenticated key exchange is dropped into the standard TLS message handshake by defining extensions to some of the messages. ๐Ÿ’œ

4.1. TLS-PWD Pre-TLS 1.3 ๐ŸŒ™

          Client                                            Server
         --------                                          --------

          ClientHello (name)      -------->

                                                        ServerHello
                                         ServerKeyExchange (commit)
                                  <--------        ServerHello Done

          ClientKeyExchange (commit)
          ChangeCipherSpec
          Finished                -------->

                                                   ChangeCipherSpec
                                  <--------                Finished

          Application Data        <------->        Application Data

Figure 1: Pre-TLS 1.3 TLS-PWD Handshake

4.2. TLS-PWD in TLS 1.3 โญ

         Client                                            Server
        --------                                          --------
         ClientHello (name)
         + key_share (commit)       -------->
                                                        ServerHello
                                               + key_share (commit)
                                              {EncryptedExtensions}
                                                         {Finished}
                                    <--------   [Application Data*]
         {Finished}                 -------->
         [Application Data]         <------->    [Application Data]

Figure 2: TLS 1.3 TLS-PWD Handshake

4.3. Protecting the Username ๐Ÿ”โœจ

okay so the client has to tell the server who she is before the server can even look up the right credential for the authenticated key exchange ๐Ÿ˜ฌ. That's a privacy problem, ngl. It makes her trackable and way more monitored. So it's lowkey essential that she can hide her username from passive monitors watching the exchange, and from an active attack by a shady server. TLS-PWD has a mechanism for exactly this ๐Ÿฆ‹. Support for protected usernames is RECOMMENDED.

To turn on username protection, the server picks a domain parameter set and makes an ephemeral public/private keypair. This keypair SHALL only be used for username protection. For efficiency, the domain parameter set used for username protection MUST be based on ECC. Any ECC group that is appropriate for TLS-PWD (see Section 3.2.1) works here, but for interoperability, prime256v1 (aka NIST's p256 curve) MUST be supported. The domain parameter set chosen for username protection is independent of the domain parameter set chosen for the underlying key exchange -- i.e., they need not be the same. ๐Ÿ’…

When the client's username and password are provisioned on the server, the chosen group and its public key are provisioned on the client. This gets stored on the client along with the server-specific state (e.g., the hostname) it uses to start a TLS-PWD exchange. The server uses the same group and public key with all clients. ๐ŸŒธ

To protect a username, the client and server do a static-ephemeral Diffie-Hellman exchange. Since the y-coordinate isn't necessary and dropping it shrinks the message size, compact representation (and therefore compact output; see [RFC6090]) is used in the static-ephemeral Diffie-Hellman exchange. The result of the Diffie-Hellman exchange gets passed to the HMAC-based Key Derivation Function (HKDF) [RFC5869] to create a key-encrypting key suitable for AES-SIV [RFC5297] (where "AES" stands for "Advanced Encryption Standard" and "SIV" stands for "Synthetic Initialization Vector") in its deterministic authenticated encryption mode. The length of the key-encrypting key (1) and the hash function to use with the HKDF depend on the length of the prime, p, of the group used to provide username protection:

  • SHA-256, SIV-128, l=256 bits: when len(p) <= 256
  • SHA-384, SIV-192, l=384 bits: when 256 < len(p) <= 384
  • SHA-512, SIV-256, l=512 bits: when len(p) > 384

4.3.1. Construction of a Protected Username ๐ŸŽ€

Before starting a TLS-PWD exchange, the client picks a random secret, c, such that 1 < c < (q - 1), where q is the order of the group the server's public key was generated from. Then she uses scalar-op() with the group's generator to make a public key, C. She uses scalar-op() with the server's public key and c to make a shared secret, and derives a key-encrypting key, k, using the "saltless" mode of the HKDF [RFC5869]:

C = scalar-op(c, G)

Z = scalar-op(c, S)

k = HKDF-expand(HKDF-extract(NULL, Z.x), "", l)

where NULL indicates the salt-free invocation and "" indicates an empty string (i.e., there is no "context" passed to the HKDF).

The client's username SHALL be represented as a UTF-8 encoded character string processed according to the rules of the OpaqueString profile of [RFC8265]. The output of OpaqueString then gets passed with the key, k, to SIV-encrypt with no Additional Authenticated Data (AAD) and no nonce, to produce an encrypted username, u:

u = SIV-encrypt(k, username)

Note: The format of the ciphertext output includes the authenticating SIV.

The protected username SHALL be the concatenation of the x-coordinate of the client's public key, C, and the encrypted username, u. The length of the x-coordinate of C MUST be equal to the length of the group's prime, p, prepended with zeros, if necessary. The protected username is inserted into the extension_data field of the pwd_protect extension (see Section 4.4.3). ๐Ÿงš

To keep the username confidential, the random secret, c, MUST be generated from a source of random entropy; see Section 3.5. ๐Ÿ”’

The length of the ciphertext output from SIV, minus the synthetic initialization vector, will equal the length of the input plaintext -- in this case, the username. To further foil traffic analysis, it is RECOMMENDED that clients append a series of NULL bytes to their usernames before passing them to SIV-encrypt() so that the padded username is at least 128 octets long. ๐Ÿ™ˆ

4.3.2. Recovery of a Protected Username ๐Ÿ•ต๏ธโ€โ™€๏ธ

A server that gets a protected username needs to recover the client's username before doing the key exchange. To do that, the server computes the client's public key, completes the static-ephemeral Diffie-Hellman exchange, derives the key-encrypting key, k, and decrypts the username.

The length of the x-coordinate of the client's public key is known (it's the length of the prime from the domain parameter set used to protect usernames) and can easily be split off from the ciphertext in the pwd_name extension in the ClientHello -- the first len(p) bits are the x-coordinate of the client's public key, and the remaining bits are the ciphertext.

Since the client uses compressed representation, the server MUST compute the y-coordinate of the client's public key using the equation of the curve:

y^2 = x^3 + ax + b

and solve for y. There are two solutions for y, but since compressed output is also being used, the selection is irrelevant. The server reconstructs the client's public value, C, from (x, y). If there is no solution for y or if (x, y) is not a valid point on the elliptic curve (see Section 3.2.1), the server MUST treat the ClientHello as if it did not have a password for a given username (see Section 4.5.1.1).

The server then uses scalar-op() with the reconstructed point C and the private key it uses for protected passwords, s, to generate a shared secret, and derives a key-encrypting key, k, the same way as described in Section 4.3.1.

Z = scalar-op(s, C)

k = HKDF-expand(HKDF-extract(NULL, Z.x), "", l)

The key, k, and the ciphertext portion of the pwd_name extension, u, get passed to SIV-decrypt with no AAD and no nonce, to produce the username:

username = SIV-decrypt(k, u)

If SIV-decrypt returns the symbol FAIL, which means decryption and verification didn't work out, the server MUST treat the ClientHello as if it did not have a password for a given username (see Section 4.5.1.1). If it works, the server has the client's username and can process it as needed. Any NULL octets the client added before encryption can be easily stripped off the string that represents the username. โœจ

4.4. Fixing the Password Element ๐Ÿ’–

Prior to making a "commitment", both sides must generate a secret Element (PE) in the chosen group, using the common password-derived base. The server generates the PE after it receives the ClientHello and chooses the group to use. The client generates the PE before sending the ClientHello in TLS 1.3, and upon receipt of the ServerKeyExchange in TLS pre-1.3. ๐Ÿ“

Fixing the PE involves an iterative "hunting-and-pecking" technique using the prime from the negotiated group's domain parameter set and an ECC-specific or FFC-specific operation, depending on the negotiated group. ๐Ÿฆ‹

To thwart side-channel attacks that try to figure out how many iterations of the hunting-and-pecking loop were used to find the PE for a given password, a security parameter, m, is used to make sure that at least m iterations are always performed. ๐Ÿ’€

First, an 8-bit counter is set to the value one (1). Then, H is used to generate a password seed from the counter, the prime of the selected group, and the base (which is derived from the username, password, and, optionally, the salt; see Section 3.4):

pwd-seed = H(base | counter | p)

Next, a context is generated consisting of random information. For versions of TLS less than 1.3, the context is a concatenation of the ClientHello random and the ServerHello random. For TLS 1.3, the context is the ClientHello random:

if (version < 1.3) {
  context = ClientHello.random | ServerHello.random
} else {
  context = ClientHello.random
}

Then, using the technique from Appendix B.5.1 of [FIPS186-4], the pwd-seed is expanded, using the Pseudorandom Function (PRF), to the length of the prime from the negotiated group's domain parameter set plus a constant, sixty-four (64), to produce an intermediate pwd-tmp, which is modularly reduced to create the pwd-value:

n = len(p) + 64
pwd-tmp = PRF(pwd-seed, "TLS-PWD Hunting And Pecking",
              context) [0..n];
pwd-value = (pwd-tmp mod (p - 1)) + 1

The pwd-value is then passed to the group-specific operation, which either returns the selected PE or fails. If the group-specific operation fails, the counter is incremented, a new pwd-seed is generated, and the hunting-and-pecking process continues. This procedure keeps going until the group-specific operation returns the PE. After the PE has been chosen, the base is changed to a random number, the counter is incremented, and the hunting-and-pecking process continues until the counter is greater than the security parameter, m. ๐ŸŽฏ

The probability that one requires more than n iterations of the hunting-and-pecking loop to find an ECC PE is roughly (q/2p)^n, and to find an FFC PE is roughly (q/p)^n. Both of these rapidly approach zero (0) as n increases. The security parameter, m, SHOULD be set sufficiently large such that the probability that finding the PE would take more than m iterations is sufficiently small (see Section 7). ๐Ÿ‘‘

When the PE has been discovered, pwd-seed, pwd-tmp, and pwd-value SHALL be irretrievably destroyed. no peeking at the leftovers after that, bestie ๐Ÿ™…โ€โ™€๏ธ

4.4.1. Computing an ECC Password Element โœจ

okay so for ECC groups, the group-specific step uses pwd-value, pwd-seed, and the curve equation to cook up the PE ๐Ÿ’…. First, pwd-value gets used straight up as the x-coordinate, x. It goes into the elliptic curve equation, with a and b from the curve's domain parameter set, to solve for a y-coordinate, y. If there's no solution to that quadratic equation, the operation fails and the hunting-and-pecking process just keeps going ๐Ÿ™ˆ. If there IS a solution, there's an ambiguity, because technically there are two of them. So pwd-seed is used to pick one unambiguously ๐Ÿฆ‹. If the low-order bit of pwd-seed matches the low-order bit of y, the candidate PE is the point (x, y). If they don't match, the candidate PE is (x, p - y), where p is the prime the curve is defined over. The candidate becomes the PE, a random number is used instead of the base, and the hunting-and-pecking keeps looping until it has gone through m iterations. m is a suitably large number, so it helps prevent side-channel attacks (see [RFC7664]) ๐Ÿ”ฅ.

Algorithmically, it looks like this:

found = 0
counter = 0
n = len(p) + 64
if (version < 1.3)
  context = ClientHello.random | ServerHello.random
} else {
  context = ClientHello.random
}
do {
  counter = counter + 1
  seed = H(base | counter | p)
  tmp = PRF(seed, "TLS-PWD Hunting And Pecking", context) [0..n]
  val = (tmp mod (p - 1)) + 1
  if ( (val^3 + a*val + b) mod p is a quadratic residue)
    then
    if (found == 0)
    then
      x = val
      save = seed
      found = 1
      base = random()
    fi
  fi
} while ((found == 0) || (counter <= m))
y = sqrt(x^3 + a*x + b) mod p
if ( lsb(y) == lsb(save))
then
  PE = (x, y)
else
  PE = (x, p - y)
fi
                Figure 3: Fixing PE for ECC Groups

Okay, here's the spicy part ๐ŸŒถ๏ธ. Checking whether a value is a quadratic residue modulo a prime can leak information about that value in a side-channel attack ๐Ÿ˜ญ. So it is RECOMMENDED that the technique first blind the value with a random number. That way, the blinded value can take on all numbers between 1 and (p - 1) with equal probability. The leak-resistant way to figure out the residue is to flip a coin and multiply the blinded value by either a random quadratic residue or a random quadratic nonresidue. Then you check whether the multiplied value is a quadratic residue or a quadratic nonresidue modulo p, respectively. The random residue and nonresidue can be worked out before hunting and pecking even starts, by calculating the Legendre symbol on random values until they show up:

do {
  qr = random()
} while ( lgr(qr, p) != 1)

do {
  qnr = random()
} while ( lgr(qnr, p) != -1)

Here's the masking technique for checking whether a value is a quadratic residue modulo a prime:

is_quadratic_residue (val, p) {
    r = (random() mod (p - 1)) + 1
    num = (val * r * r) mod p
    if ( lsb(r) == 1 )
       num = (num * qr) mod p
       if ( lgr(num, p) == 1)
       then
          return TRUE
       fi
    else
       num = (num * qnr) mod p
       if ( lgr(num, p) == -1)
       then
          return TRUE
       fi
    fi
    return FALSE
}

The random quadratic residue and quadratic nonresidue (qr and qnr above) can be reused across all the hunting-and-pecking loops. But the blinding value, r, MUST be chosen randomly for each loop ๐Ÿ’–.


4.4.2. Computing an FFC Password Element ๐Ÿฆ‹

For FFC groups, the group-specific step takes the prime (p) and the order (q) from the group's domain parameter set, plus the variable pwd-value. It directly makes a candidate PE by raising pwd-value to the power ((p - 1)/q) modulo p. If the order isn't part of the defined domain parameter set, see Section 3.2.2. If the result is greater than one (1), the candidate becomes the PE. Otherwise the hunting-and-pecking keeps going until it has looped through m iterations, where m is a suitably large number to prevent side-channel attacks (see [RFC7664]) ๐ŸŒธ.

Algorithmically, the process looks like this:

found = 0
counter = 0
n = len(p) + 64
if (version < 1.3)
  context = ClientHello.random | ServerHello.random
} else {
  context = ClientHello.random
}
do {
  counter = counter + 1
  pwd-seed = H(base | counter | p)
  pwd-tmp = PRF(pwd-seed, "TLS-PWD Hunting And Pecking",
                context) [0..n]
  pwd-value = (pwd-tmp mod (p - 1)) + 1
  PE = pwd-value^((p - 1)/q) mod p
  if (PE > 1)
  then
    found = 1
    base = random()
  fi
} while ((found == 0) || (counter <= m))
                Figure 4: Fixing PE for FFC Groups

4.4.3. Password Naming ๐ŸŽ€

The client is required to identify herself to the server. She does this by adding either a pwd_protect or a pwd_clear extension to her ClientHello, depending on whether she wants to protect her username (see Section 4.3) or not. The pwd_protect and pwd_clear extensions use the standard mechanism defined in [RFC5246]. The "extension data" field of the extension SHALL contain a pwd_name, which is what identifies the password shared between client and server. If username protection is performed and the ExtensionType is pwd_protect, the contents of the pwd_name SHALL be constructed according to Section 4.3.1 ๐Ÿ’….

   enum { pwd_protect(29), pwd_clear(30) } ExtensionType;

   opaque pwd_name<1..2^8-1>;

An unprotected pwd_name SHALL be a UTF-8 encoded character string, processed according to the rules of the OpaqueString profile of [RFC8265]. A protected pwd_name SHALL be a string of bits ๐Ÿงš.


4.4.4. Generating TLS-PWD Commit ๐ŸŒˆ

Each peer's "commitment" is made of a scalar and an Element, and they're generated like this. First, two random numbers, called "private" and "mask", get generated. Each is between zero and the order of the group (exclusive). If their sum modulo the order of the group, q, equals zero (0) or one (1), those numbers have to be thrown away and new random numbers generated. If their sum modulo the order of the group, q, is greater than one, that sum becomes the scalar:

   scalar = (private + mask) mod q

The Element is then calculated as the inverse of the group's scalar operation (see the group-specific operations discussed in Section 3.2) with the mask and PE:

   Element = inverse(scalar-op(mask, PE))

Once the scalar and Element are calculated, the mask SHALL be irretrievably destroyed ๐Ÿซถ.


4.5. Changes to Handshake Message Contents ๐Ÿ’œ

4.5.1. Pre-1.3 TLS ๐ŸŒธ

4.5.1.1. ClientHello Changes ๐Ÿ’–

A client offering a PWD ciphersuite MUST include one of the pwd_name extensions from Section 4.4.3 in her ClientHello.

Now, if a server doesn't have a password for a client identified by the username (either extracted from the pwd_name if it's unprotected, or recovered using the technique in Section 4.3.2 if it's protected), or if recovering a protected username fails, the server SHOULD hide that fact ๐Ÿ™ˆ. It does this by simulating the protocol, which means putting random data in the PWD-specific components of the ServerKeyExchange, and then rejecting the client's finished message with a "bad_record_mac" alert [RFC8446]. To properly effect a simulated TLS-PWD exchange, an appropriate delay SHOULD be inserted between receipt of the ClientHello and response of the ServerHello. Alternately, a server MAY choose to terminate the exchange if a password is not found. Just know that terminating the exchange exposes to an attacker whether a username is valid or not ๐Ÿ˜ญ.

The server decides on a group to use with the named user (see Section 9) and generates the PE according to Section 4.4.2 ๐Ÿ‘‘.

4.5.1.2. ServerKeyExchange Changes ๐Ÿฆ‹

The domain parameter set for the selected group MUST be explicitly specified by name in the ServerKeyExchange. ECC groups are specified using the NamedCurve enumeration of [RFC8422]. FFC groups are specified using the NamedGroup extensions added by [RFC7919] to the "TLS Supported Groups" registry in [TLS_REG]. On top of the group specification, the ServerKeyExchange also contains the server's "commitment" in the form of a scalar and Element, plus the salt that was used to store the user's password ๐Ÿ”ฅ.

Two new values have been added to the enumerated KeyExchangeAlgorithm to indicate TLS-PWD using FFC and TLS-PWD using ECC: ff_pwd and ec_pwd, respectively.

                enum { ff_pwd, ec_pwd } KeyExchangeAlgorithm;

                struct {
                  opaque salt<1..2^8-1>;
                  NamedGroup ff_group;
                  opaque ff_selement<1..2^16-1>;
                  opaque ff_sscalar<1..2^16-1>;
                } ServerFFPWDParams;

                struct {
                  opaque salt<1..2^8-1>;
                  ECParameters curve_params;
                  ECPoint ec_selement;
                  opaque ec_sscalar<1..2^8-1>;
                } ServerECPWDParams;

                struct {
                  select (KeyExchangeAlgorithm) {
                    case ec_pwd:
                      ServerECPWDParams params;
                    case ff_pwd:
                      ServerFFPWDParams params;
                  };
                } ServerKeyExchange;

4.5.1.2.1. Generation of ServerKeyExchange ๐Ÿงš

The scalar and Element referenced in this section are derived according to Section 4.4.4.

4.5.1.2.1.1. ECC ServerKeyExchange ๐Ÿ’…

ECC domain parameters are specified in the ECParameters component of the ECC-specific ServerKeyExchange, as defined in [RFC8422]. The scalar SHALL become the ec_sscalar component, and the Element SHALL become the ec_selement of the ServerKeyExchange. If the client requested a specific point format (compressed or uncompressed) with the Supported Point Formats Extension (see [RFC8422]) in its ClientHello, the Element MUST be formatted in the ec_selement to conform to that request. If the client offered (an) elliptic curve(s) in its ClientHello using the Supported Elliptic Curves Extension, the server MUST include (one of the) named curve(s) in the ECParameters field in the ServerKeyExchange, and the key exchange operations specified in Section 4.5.1.2.1 MUST use that group โœจ.

As mentioned in Section 3.2.1, characteristic-2 curves and curves with a co-factor greater than one (1) SHALL NOT be used by TLS-PWD ๐Ÿ™…โ€โ™€๏ธ.

4.5.1.2.1.2. FFC ServerKeyExchange ๐ŸŒˆ

FFC domain parameters use the NamedGroup extension specified in [RFC7919]. The scalar SHALL become the ff_sscalar component, and the Element SHALL become the ff_selement in the FFC-specific ServerKeyExchange ๐Ÿ’–.

As mentioned in Section 3.2.2, if the prime is a safe prime and no order is included in the domain parameter set, the order added to the ServerKeyExchange SHALL be the prime minus one divided by two -- (p - 1)/2 ๐ŸŽ€.

4.5.1.2.2. Processing of ServerKeyExchange โœจ

Okay so when the ServerKeyExchange lands, the client gets to decide if it actually wants to support the group the server picked ๐Ÿ’…. If it does, the server's "commitment" MUST be validated. That means checking 1) the server's scalar is greater than one (1) and less than the order of the group, q, and 2) the Element is valid for the chosen group (see Sections 3.2.1 and 3.2.2 for how to check that for the particular group). Note that if the Element is a compressed point on an elliptic curve, it MUST be uncompressed before checking its validity ๐Ÿซถ

If the group is acceptable and the server's "commitment" passes validation, the client pulls the salt out of the ServerKeyExchange and generates the PE following Sections 3.4 and 4.4.2 ๐ŸŒธ If the group isn't acceptable, or the "commitment" fails validation, the exchange MUST be aborted ๐Ÿ’€

4.5.1.3. ClientKeyExchange Changes

When KeyExchangeAlgorithm is either ff_pwd or ec_pwd, the ClientKeyExchange is how the client sends its "commitment" to the server ๐ŸŽ€ So it carries a scalar and an Element, bestie.

struct {
  opaque ff_celement<1..2^16-1>;
  opaque ff_cscalar<1..2^16-1>;
} ClientFFPWDParams;

struct {
  ECPoint ec_celement;
  opaque ec_cscalar<1..2^8-1>;
} ClientECPWDParams;

struct {
  select (KeyExchangeAlgorithm) {
    case ff_pwd: ClientFFPWDParams;
    case ec_pwd: ClientECPWDParams;
  } exchange_keys;
} ClientKeyExchange;

4.5.1.3.1. Generation of ClientKeyExchange

The client's scalar and Element get generated the same way as in Section 4.5.1.2.1, so no surprises there โœจ

For an FFC group, the scalar SHALL become the ff_cscalar component, and the Element SHALL become the ff_celement in the FFC-specific ClientKeyExchange ๐Ÿงš

For an ECC group, the scalar SHALL become the ec_cscalar component, and the Element SHALL become the ec_celement in the ECC-specific ClientKeyExchange. Now here's the important bit: if the client asked for a specific point format (compressed or uncompressed) with the Supported Point Formats Extension in its ClientHello, then the Element MUST be formatted in ec_celement to match that original request ๐Ÿ™ˆ

4.5.1.3.2. Processing of ClientKeyExchange

When the ClientKeyExchange shows up, the server has to check the client's "commitment" ๐Ÿ” It does that by making sure that 1) the client's scalar and Element differ from the server's scalar and Element, 2) the client's scalar is greater than one (1) and less than the order of the group, q, and 3) the Element is valid for the chosen group (see Sections 3.2.1 and 3.2.2 for how to determine whether an Element is valid for a particular group. Note that if the Element is a compressed point on an elliptic curve, it MUST be uncompressed before checking its validity). If any of those three conditions aren't met, the server MUST abort the exchange ๐Ÿ’…

4.5.2. TLS 1.3 ๐Ÿฆ‹

4.5.2.1. TLS 1.3 KeyShare

TLS 1.3 clients and servers carry their commit values in a "key_share" extension. The structure of this extension SHALL be:

enum { ff_pwd, ec_pwd } KeyExchangeAlgorithm;

struct {
    select (KeyExchangeAlgorithm) {
        case ec_pwd:
            opaque elemX[coordinate_length];
            opaque elemY[coordinate_length];
        case ff_pwd:
            opaque elem[coordinate_length];
     };
     opaque scalar<1..2^8-1>
} PWDKeyShareEntry;

struct {
     NamedGroup group;
     PWDKeyShareEntry pwd_key_exchange<1..2^16-1>;
} KeyShareEntry;

4.5.2.2. ClientHello Changes

The ClientHello MUST include a pwd_name extension from Section 4.4.3, and it MUST include a key_share extension from Section 4.5.2.1. Main character energy, required ๐Ÿ‘‘

When the server gets a ClientHello, it MUST validate the key_share extension_data [RFC8446] to make sure the scalar is greater than one (1) and less than the order of the group q, and that the Element is valid for the chosen group (see Sections 3.2.1 and 3.2.2) โœจ

Now the spicy part ๐ŸŒถ๏ธ If a server doesn't have a password for the client identified by the username, whether that username came from the pwd_name (if unprotected) or was recovered using the technique in Section 4.3.2 (if protected), or if recovering a protected username fails, the server SHOULD hide that fact by simulating the protocol. That means putting random data in the PWD-specific components of its KeyShareEntry, and then rejecting the client's finished message with a "bad_record_mac" alert ๐Ÿ™ˆ To properly fake a TLS-PWD exchange, an appropriate delay SHOULD be inserted between receiving the ClientHello and sending the ServerHello. Alternately, a server MAY choose to terminate the exchange if a password isn't found. Just know that terminating the exchange exposes to an attacker whether a username is valid or not, so it's a real tradeoff ๐Ÿ’€

4.5.2.3. ServerHello Changes

If the server supports TLS-PWD, agrees with the group the client chose, and finds an unsalted password indicated by the pwd_name extension of the received ClientHello, then its ServerHello MUST contain a key_share extension from Section 4.5.2.1 in the same group the client chose ๐ŸŽ€

When the client receives a ServerHello, it MUST validate the key_share extension_data to make sure the scalar is greater than one (1) and less than the order of the group q, and that the Element is valid for the chosen group (see Sections 3.2.1 and 3.2.2) ๐Ÿซถ

4.5.2.4. HelloRetryRequest Changes

The server sends this message in response to a ClientHello if it wants a different group, or if the password named by the client's pwd_name is salted ๐Ÿง

A different group is signalled by adding the KeyShareHelloRetryRequest extension to the HelloRetryRequest. A salted password, and the salt used, is indicated by adding the following structure:

enum { password_salt(31) } ExtensionType;

struct {
    opaque pwd_salt<2^16-1>;
} password_salt;

A client that gets a HelloRetryRequest indicating the password salt SHALL delete its computed PE and derive another version using the salt before sending another ClientHello ๐Ÿ”„

4.6. Computing the Shared Secret ๐Ÿ”

The client and server use their private value, as calculated in Section 4.4.4, together with the other party's Element and scalar from the ServerHello or ClientHello, respectively (here called "Peer_Element" and "peer_scalar"), to generate the shared secret z. It's giving math, periodt ๐Ÿงฎ

z = F(scalar-op(private,
                elem-op(Peer_Element,
                        scalar-op(peer_scalar, PE))))

For TLS versions prior to 1.3, the intermediate value z is then used as the premaster secret, after any leading bytes of z that are all zero bits have been stripped off. For TLS 1.3, leading zero bytes are kept, and the intermediate value z is used as the (EC)DHE input in the key schedule โœจ

5. Ciphersuite Definition ๐ŸŒˆ

This memo adds the following ciphersuites:

CipherSuite TLS_ECCPWD_WITH_AES_128_GCM_SHA256 = (0xC0,0xB0);

CipherSuite TLS_ECCPWD_WITH_AES_256_GCM_SHA384 = (0xC0,0xB1);

CipherSuite TLS_ECCPWD_WITH_AES_128_CCM_SHA256 = (0xC0,0xB2);

CipherSuite TLS_ECCPWD_WITH_AES_256_CCM_SHA384 = (0xC0,0xB3);

Implementations conforming to this specification MUST support the TLS_ECCPWD_WITH_AES_128_GCM_SHA256 ciphersuite. They SHOULD support the remaining ciphersuites, so please don't skip them ๐Ÿซถ

When it's negotiated with a version of TLS prior to 1.2, the PRF from that earlier version is used. When the negotiated version is TLS 1.2, the PRF is the TLS 1.2 PRF [RFC5246], using the hash function indicated by the ciphersuite. When the negotiated version is TLS 1.3, the PRF is the Derive-Secret function from Section 7.1 of [RFC8446]. Regardless of TLS version, the TLS-PWD random function, H, is always instantiated with the hash algorithm the ciphersuite indicates ๐Ÿ”ฅ

For those ciphersuites that use Cipher Block Chaining (CBC) [SP800-38A] mode, the MAC is HMAC [RFC2104] with the hash function the ciphersuite indicates ๐Ÿ’œ

6. IANA Considerations ๐Ÿฆ‹

IANA has assigned three values for new TLS extension types from the "TLS ExtensionType Values" registry defined in [RFC8446] and [RFC8447]. They are pwd_protect (29), pwd_clear (30), and password_salt (31). See Sections 4.5.1.1 and 4.5.2.2 for more info ๐Ÿงš

In summary, these rows have been added to the "TLS ExtensionType Values" registry:

+-------+----------------+-------------+-----------+
| Value | Extension Name |   TLS 1.3   | Reference |
+-------+----------------+-------------+-----------+
|   29  |  pwd_protect   |      CH     |  RFC 8492 |
|   30  |   pwd_clear    |      CH     |  RFC 8492 |
|   31  | password_salt  | CH, SH, HRR |  RFC 8492 |
+-------+----------------+-------------+-----------+

IANA has also assigned the following ciphersuites from the "TLS Cipher Suites" registry defined in [RFC8446] and [RFC8447]:

CipherSuite TLS_ECCPWD_WITH_AES_128_GCM_SHA256 = (0xC0,0xB0);

CipherSuite TLS_ECCPWD_WITH_AES_256_GCM_SHA384 = (0xC0,0xB1);

CipherSuite TLS_ECCPWD_WITH_AES_128_CCM_SHA256 = (0xC0,0xB2);

CipherSuite TLS_ECCPWD_WITH_AES_256_CCM_SHA384 = (0xC0,0xB3);

The "DTLS-OK" column in the registry has been set to "Y", and the "Recommended" column has been set to "N" for all ciphersuites defined in this memo ๐Ÿ’–

7. Security Considerations ๐Ÿ”โœจ

okay so the security proof for this key exchange in the random oracle model is over in [lanskro] ๐Ÿง  go read it bestie, it's giving rigor.

A passive attacker against this protocol will see the ServerKeyExchange and the ClientKeyExchange (in TLS pre-1.3), or the KeyShare (from TLS 1.3), containing the scalar and Element of the server and the client, respectively. ๐Ÿซถ The client and server basically hide their secret private value by masking it modulo the order of the selected group. If the order is q, then there are approximately q distinct pairs of numbers that will sum to the scalar values observed. An attacker could iterate through all of those values, but for a large q this exhaustive search is computationally infeasible ๐Ÿ’€ The attacker would have a better shot at solving the discrete logarithm problem, which we already assumed (see Section 3.5) is an intractable problem.

A passive attacker can take the Element from the ServerKeyExchange or the ClientKeyExchange (in TLS pre-1.3), or from the KeyShare (from TLS 1.3), and try to figure out the random "mask" value used in its construction, and then recover the other party's "private" value from the scalar in the same message. But this requires the attacker to solve the discrete logarithm problem, which we assumed is intractable. not happening ๐Ÿ™…โ€โ™€๏ธ

Both the client and the server get a shared secret based on a secret group Element and the private information they each contributed to the exchange. The secret group Element is based on the password. If they don't share the same password, they won't be able to derive the same secret group Element, and if they don't generate the same secret group Element, they won't be able to generate the same shared secret. Seeing a finished message gives no extra advantage for an attack, since it's generated with the unknowable secret ๐Ÿ”’

In TLS pre-1.3, an active attacker impersonating the client can induce a server to send a ServerKeyExchange containing the server's scalar and Element. The attacker can try to generate a ClientKeyExchange and send it to the server, but she is required to send a finished message first. So the only info she can get from this attack is less than what she'd get from a passive attack, which makes this particular active attack not very fruitful ๐Ÿฅฑ

In TLS pre-1.3, an active attacker can impersonate the server and send a forged ServerKeyExchange after receiving the ClientHello. The attacker then waits until it receives the ClientKeyExchange and finished message from the client. Now the attacker can try running through all possible values of the password, computing the PE (see Section 4.4), computing candidate premaster secrets (see Section 4.6), and attempting to recreate the client's finished message ๐Ÿ•ต๏ธโ€โ™€๏ธ

But the attacker committed to a single guess of the password with her forged ServerKeyExchange. That value was used by the client in computing the premaster secret, which was then used to produce the finished message. Any guess of the password that differs from the one used in the forged ServerKeyExchange makes each side use a different PE in the premaster secret computation. So the finished message can't be verified as correct, even if a later guess (while running through all possible values) was the right one. The attacker gets one guess, and one guess only, per active attack. ๐ŸŽฏ

Instead of guessing at the password, an attacker could try to determine the PE and then launch an attack. But the PE is determined by the output of the random function, H, which is indistinguishable from a random source, since H is assumed to be a "random oracle" (Section 3.5). So every Element of the finite cyclic group has an equal probability of being the PE. The probability of guessing the PE is 1/q, where q is the order of the group. For a large q, this is computationally infeasible ๐Ÿ™ˆ

The implications of resistance to dictionary attacks are big. An implementation can provision a password in a practical, realistic way (it MAY be a character string, and it MAY be relatively short) and still stay secure ๐Ÿ’… The nature of the pool of potential passwords determines the size of that pool, D, and countermeasures can stop an attacker from finding the password in the only possible way: repeated, active, guessing attacks. For example, a simple four-character string using lowercase English characters, assuming random selection of those characters, gives a D of over four hundred thousand. An attacker would need to mount over one hundred thousand active, guessing attacks (which will easily be detected) before getting any real advantage in determining the pre-shared key ๐Ÿšจ

Countermeasures against successive active, guessing attacks are only possible by noticing that a certain username keeps failing over a certain period of time. Attacks that try to find a password for a random user are harder to detect. For instance, if a device uses a serial number as a username and the pool of potential passwords is small enough, a more effective attack would be to pick one password and try all the potential "users," spreading the attack out and confusing the countermeasures ๐ŸŒ€ It is RECOMMENDED that implementations of TLS-PWD keep track of the total number of failed authentications, regardless of username, to detect and thwart this type of attack. ๐Ÿ›ก๏ธ

The benefits of resistance to dictionary attacks can be weakened if a client uses the same password with multiple servers. An attacker could redirect a session from one server to the other if the attacker knew that the intended server stored the same password for the client as another server. ๐Ÿ˜ฌ

An adversary with access to, and a lot of control over, a client or server could try a side-channel attack to figure out how many times it took for a certain password (plus client random and server random) to select a PE. Each such attack could result in a step-by-step "paring down" of the pool of potential passwords, leaving a manageably small set to launch a series of active attacks against in order to determine the password ๐Ÿ‘€ A security parameter, m, is used to normalize the amount of work needed to determine the PE (see Section 4.4). The probability that a password will require more than m iterations is roughly (q/2p)^m for ECC groups and (q/p)^m for FFC groups, so it is possible to mitigate side-channel attacks at the expense of a constant cost per connection attempt. But if a particular password requires more than k iterations, it will leak k bits of information to the side-channel attacker, and for some dictionaries, this will uniquely identify the password. So the security parameter, m, needs to be set with great care ๐Ÿ˜ญ It is RECOMMENDED that an implementation set the security parameter, m, to a value of at least forty (40), which puts the probability that more than forty iterations are needed in the order of one in one trillion (1:1,000,000,000,000). ๐Ÿ“

A database of salted passwords stops an adversary who gets into the database from learning the client's password, but it does not stop that adversary from impersonating the client back to the server. Each side uses the salted password, called the base, as the authentication credential, so the database of salted passwords MUST be afforded the security of a database of plaintext passwords. ๐Ÿ”‘

Authentication is performed by proving knowledge of the password. Any third party that knows the password shared by the client and server can impersonate one to the other. ๐ŸŽญ

The static-ephemeral Diffie-Hellman exchange used to protect usernames requires the server to reuse its Diffie-Hellman public key. To prevent an "invalid curve" attack, an entity that reuses its Diffie-Hellman public key needs to check whether the received ephemeral public key is actually a point on the curve. This is done explicitly as part of the server's reconstruction of the client's public key out of only its x-coordinate ("compact representation"). โœ…


8. Human Rights Considerations ๐Ÿ•Š๏ธ๐ŸŒˆ

okay this section is so important bestie. At the time this document was published, there was a growing interest in looking at the impacts that IETF (and IRTF) work can have on human rights. Some related research is discussed in [RFC8280]. So the human rights considerations of TLS-PWD are presented here ๐Ÿซถ

The key exchange underlying TLS-PWD uses public key cryptography to perform authentication and authenticated key exchange. The keys it produces can be used to set up secure connections between two people to protect their communication. Implementations of TLS-PWD, like implementations of other TLS ciphersuites that perform authentication and authenticated key establishment, are considered "armaments" or "munitions" by many governments around the world ๐ŸŒ

The most fundamental of human rights is the right to protect oneself. โœจ The right to keep and bear arms is an example of this right. Implementations of TLS-PWD can be used as arms, kept and borne, to defend oneself against all manner of attackers: criminals, governments, lawyers, etc. TLS-PWD is a powerful tool in the promotion and defense of universal human rights. ๐Ÿ‘‘๐Ÿ’–

9. Implementation Considerations ๐ŸŽ€

Okay so bestie, the picking of the ciphersuite and the picking of the particular finite cyclic group to use with it are kept separate in this memo, but they are literally so close to each other ๐Ÿซถ they're basically attached at the hip.

It is RECOMMENDED that implementations take note of the strength estimates of particular groups and select a ciphersuite providing commensurate security with its hash and encryption algorithms. A ciphersuite whose encryption algorithm has a keylength less than the strength estimate or whose hash algorithm has a block size that is less than twice the strength estimate SHOULD NOT be used. Don't be that girl who pairs a weak cipher with a strong group ๐Ÿ’€

For example, the elliptic curve named "brainpoolP256r1" (whose IANA-assigned number is 26) [RFC7027] provides an estimated 128 bits of strength and would be compatible with 1) an encryption algorithm supporting a key of that length and 2) a hash algorithm that has at least a 256-bit block size. Therefore, a suitable ciphersuite to use with brainpoolP256r1 could be TLS_ECCPWD_WITH_AES_128_GCM_SHA256 (see Appendix A for an example of such an exchange) ๐ŸŒธโœจ

Resistance to dictionary attacks means that the attacker must launch an active attack to make a single guess at the password. If the size of the pool from which the password was extracted was D and each password in the pool has an equal probability of being chosen, then the probability of success after a single guess is 1/D. After X guesses and the removal of failed guesses from the pool of possible passwords, the probability becomes 1/(D-X). As X grows, so does the probability of success. Therefore, it is possible for an attacker to determine the password through repeated brute-force, active, guessing attacks. ๐Ÿ˜ญ Implementations SHOULD take note of this fact and choose an appropriate pool of potential passwords -- i.e., make D big. Implementations SHOULD also take countermeasures -- for instance, refusing authentication attempts by a particular username for a certain amount of time, after the number of failed authentication attempts reaches a certain threshold. No such threshold or amount of time is recommended in this memo. Bestie, make D big. Make it so big ๐Ÿ‘‘


10. References ๐Ÿ“š

10.1. Normative References ๐Ÿ’œ

10.2. Informative References ๐ŸŒˆ

Appendix A. Example Exchange ๐ŸŽ€

okay bestie, this appendix is a full worked example so you can watch TLS-PWD go from start to finish. same account, same password, same bytes, all the way through ๐Ÿ’…

the login is username: fred with password: barney. before the handshake even starts, the server makes a salt and a base. these are the exact values:

username: fred
password: barney

---- prior to running TLS-PWD ----

server generates salt:

96 3c 77 cd c1 3a 2a 8d 75 cd dd d1 e0 44 99 29
84 37 11 c2 1d 47 ce 6e 63 83 cd da 37 e4 7d a3

and a base:

6e 7c 79 82 1b 9f 8e 80 21 e9 e7 e8 26 e9 ed 28
c4 a1 8a ef c8 75 0c 72 6f 74 c7 09 61 d7 00 75

now the exchange is actually running ๐Ÿ”ฅ the first thing both sides agree on is the curve, brainpoolP256r1. after that, the client and server each generate the PE. here's the x-coordinate of the PE:

---- state derived during the TLS-PWD exchange ----

client and server agree to use brainpoolP256r1

client and server generate the PE:

PE.x:
29 b2 38 55 81 9f 9c 3f c3 71 ba e2 84 f0 93 a3
a4 fd 34 72 d4 bd 2e 9d f7 15 2d 22 ab 37 aa e6

next up are the private values and masks for each side. the server's first:

server private and mask:

private:
21 d9 9d 34 1c 97 97 b3 ae 72 df d2 89 97 1f 1b
74 ce 9d e6 8a d4 b9 ab f5 48 88 d8 f6 c5 04 3c
mask:
0d 96 ab 62 4d 08 2c 71 25 5b e3 64 8d cd 30 3f
6a b0 ca 61 a9 50 34 a5 53 e3 30 8d 1d 37 44 e5

client private and mask:

private:
17 1d e8 ca a5 35 2d 36 ee 96 a3 99 79 b5 b7 2f
a1 89 ae 7a 6a 09 c7 7f 7b 43 8a f1 6d f4 a8 8b
mask:
4f 74 5b df c2 95 d3 b3 84 29 f7 eb 30 25 a4 88
83 72 8b 07 d8 86 05 c0 ee 20 23 16 a0 72 d1 bd

once all of that is in place, both parties work out the premaster secret and the master secret, and they land on the same values โœจ

both parties generate premaster secret and master secret

premaster secret:
01 f7 a7 bd 37 9d 71 61 79 eb 80 c5 49 83 45 11
af 58 cb b6 dc 87 e0 18 1c 83 e7 01 e9 26 92 a4
master secret:
65 ce 15 50 ee ff 3d aa 2b f4 78 cb 84 29 88 a1
60 26 a4 be f2 2b 3f ab 23 96 e9 8a 7e 05 a1 0f
3d 8c ac 51 4d da 42 8d 94 be a9 23 89 18 4c ad

and now the receipts ๐Ÿงพ this is the ssldump capture of the whole exchange, so you can see every single message on the wire. the client is Charlene and the server is Sammy ๐Ÿ’œ

---- ssldump output of exchange ----

New TCP connection #1: Charlene Client <-> Sammy Server
1 1  0.0018 (0.0018)  C>SV3.3(173)  Handshake
      ClientHello
        Version 3.3
        random[32]=
          52 8f bf 52 17 5d e2 c8 69 84 5f db fa 83 44 f7
          d7 32 71 2e bf a6 79 d8 64 3c d3 1a 88 0e 04 3d
        ciphersuites
        TLS_ECCPWD_WITH_AES_128_GCM_SHA256_PRIV
        TLS_ECCPWD_WITH_AES_256_GCM_SHA384_PRIV
        Unknown value 0xff
        compression methods
                  NULL
        extensions
        TLS-PWD unprotected name[5]=
          04 66 72 65 64
        elliptic curve point format[4]=
          03 00 01 02
        elliptic curve list[58]=
          00 38 00 0e 00 0d 00 1c 00 19 00 0b 00 0c 00 1b
          00 18 00 09 00 0a 00 1a 00 16 00 17 00 08 00 06
          00 07 00 14 00 15 00 04 00 05 00 12 00 13 00 01
          00 02 00 03 00 0f 00 10 00 11
Packet data[178]=
  16 03 03 00 ad 01 00 00 a9 03 03 52 8f bf 52 17
  5d e2 c8 69 84 5f db fa 83 44 f7 d7 32 71 2e bf
  a6 79 d8 64 3c d3 1a 88 0e 04 3d 00 00 06 ff b3
  ff b4 00 ff 01 00 00 7a b8 aa 00 05 04 66 72 65
  64 00 0b 00 04 03 00 01 02 00 0a 00 3a 00 38 00
  0e 00 0d 00 1c 00 19 00 0b 00 0c 00 1b 00 18 00
  09 00 0a 00 1a 00 16 00 17 00 08 00 06 00 07 00
  14 00 15 00 04 00 05 00 12 00 13 00 01 00 02 00
  03 00 0f 00 10 00 11 00 0d 00 22 00 20 06 01 06
  02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03
  01 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00
  01 01

1 2  0.0043 (0.0024)  S>CV3.3(94)  Handshake
      ServerHello
        Version 3.3
        random[32]=
          52 8f bf 52 43 78 a1 b1 3b 8d 2c bd 24 70 90 72
          13 69 f8 bf a3 ce eb 3c fc d8 5c bf cd d5 8e aa
        session_id[32]=
          ef ee 38 08 22 09 f2 c1 18 38 e2 30 33 61 e3 d6
          e6 00 6d 18 0e 09 f0 73 d5 21 20 cf 9f bf 62 88
        cipherSuite         TLS_ECCPWD_WITH_AES_128_GCM_SHA256_PRIV
        compressionMethod                   NULL
        extensions
        renegotiate[1]=
          00
        elliptic curve point format[4]=
          03 00 01 02
        heartbeat[1]=
          01
Packet data[99]=
  16 03 03 00 5e 02 00 00 5a 03 03 52 8f bf 52 43
  78 a1 b1 3b 8d 2c bd 24 70 90 72 13 69 f8 bf a3
  ce eb 3c fc d8 5c bf cd d5 8e aa 20 ef ee 38 08
  22 09 f2 c1 18 38 e2 30 33 61 e3 d6 e6 00 6d 18
  0e 09 f0 73 d5 21 20 cf 9f bf 62 88 ff b3 00 00
  12 ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 0f
  00 01 01

1 3  0.0043 (0.0000)  S>CV3.3(141)  Handshake
      ServerKeyExchange
        params
          salt[32]=
            96 3c 77 cd c1 3a 2a 8d 75 cd dd d1 e0 44 99 29
            84 37 11 c2 1d 47 ce 6e 63 83 cd da 37 e4 7d a3
          EC parameters = 3
          curve id = 26
          element[65]=
            04 22 bb d5 6b 48 1d 7f a9 0c 35 e8 d4 2f cd 06
            61 8a 07 78 de 50 6b 1b c3 88 82 ab c7 31 32 ee
            f3 7f 02 e1 3b d5 44 ac c1 45 bd d8 06 45 0d 43
            be 34 b9 28 83 48 d0 3d 6c d9 83 24 87 b1 29 db
            e1
          scalar[32]=
            2f 70 48 96 69 9f c4 24 d3 ce c3 37 17 64 4f 5a
            df 7f 68 48 34 24 ee 51 49 2b b9 66 13 fc 49 21
Packet data[146]=
  16 03 03 00 8d 0c 00 00 89 00 20 96 3c 77 cd c1
  3a 2a 8d 75 cd dd d1 e0 44 99 29 84 37 11 c2 1d
  47 ce 6e 63 83 cd da 37 e4 7d a3 03 00 1a 41 04
  22 bb d5 6b 48 1d 7f a9 0c 35 e8 d4 2f cd 06 61
  8a 07 78 de 50 6b 1b c3 88 82 ab c7 31 32 ee f3
  7f 02 e1 3b d5 44 ac c1 45 bd d8 06 45 0d 43 be
  34 b9 28 83 48 d0 3d 6c d9 83 24 87 b1 29 db e1
  00 20 2f 70 48 96 69 9f c4 24 d3 ce c3 37 17 64
  4f 5a df 7f 68 48 34 24 ee 51 49 2b b9 66 13 fc
  49 21

1 4  0.0043 (0.0000)  S>CV3.3(4)  Handshake
      ServerHelloDone
Packet data[9]=
  16 03 03 00 04 0e 00 00 00

1 5  0.0086 (0.0043)  C>SV3.3(104)  Handshake
      ClientKeyExchange
        element[65]=
          04 a0 c6 9b 45 0b 85 ae e3 9f 64 6b 6e 64 d3 c1
          08 39 5f 4b a1 19 2d bf eb f0 de c5 b1 89 13 1f
          59 5d d4 ba cd bd d6 83 8d 92 19 fd 54 29 91 b2
          c0 b0 e4 c4 46 bf e5 8f 3c 03 39 f7 56 e8 9e fd
          a0
        scalar[32]=
          66 92 44 aa 67 cb 00 ea 72 c0 9b 84 a9 db 5b b8
          24 fc 39 82 42 8f cd 40 69 63 ae 08 0e 67 7a 48
Packet data[109]=
  16 03 03 00 68 10 00 00 64 41 04 a0 c6 9b 45 0b
  85 ae e3 9f 64 6b 6e 64 d3 c1 08 39 5f 4b a1 19
  2d bf eb f0 de c5 b1 89 13 1f 59 5d d4 ba cd bd
  d6 83 8d 92 19 fd 54 29 91 b2 c0 b0 e4 c4 46 bf
  e5 8f 3c 03 39 f7 56 e8 9e fd a0 00 20 66 92 44
  aa 67 cb 00 ea 72 c0 9b 84 a9 db 5b b8 24 fc 39
  82 42 8f cd 40 69 63 ae 08 0e 67 7a 48

1 6  0.0086 (0.0000)  C>SV3.3(1)  ChangeCipherSpec
Packet data[6]=
  14 03 03 00 01 01

1 7  0.0086 (0.0000)  C>SV3.3(40)  Handshake
Packet data[45]=
  16 03 03 00 28 44 cd 3f 26 ed 64 9a 1b bb 07 c7
  0c 6d 3e 28 af e6 32 b1 17 29 49 a1 14 8e cb 7a
  0b 4b 70 f5 1f 39 c2 9c 7b 6c cc 57 20

1 8  0.0105 (0.0018)  S>CV3.3(1)  ChangeCipherSpec
Packet data[6]=
  14 03 03 00 01 01

1 9  0.0105 (0.0000)  S>CV3.3(40)  Handshake
Packet data[45]=
  16 03 03 00 28 fd da 3c 9e 48 0a e7 99 ba 41 8c
  9f fd 47 c8 41 2c fd 22 10 77 3f 0f 78 54 5e 41
  a2 21 94 90 12 72 23 18 24 21 c3 60 a4

1 10 0.0107 (0.0002)  C>SV3.3(100)  application_data
Packet data....

that's the whole thing, start to finish ๐Ÿฆ‹ the handshake wraps up and the app data starts flowing.

Acknowledgements โœจ

this key exchange didn't just stay in one spec, it's also been defined for 802.11 networks as an Extensible Authentication Protocol (EAP) method, and as an authentication method for the Internet Key Exchange Protocol (IKE). every one of those specs brought in really helpful comments from a huge crowd of people, and that feedback is what made the key exchange as refined and polished as it is ๐ŸŒธ

the author wants to thank Scott Fluhrer ๐Ÿ™ˆ for spotting the "password as exponent" attack that was possible in an early version of this key exchange, and for his super helpful ideas on how to fix the PE so that attack wasn't possible. the author also says thanks to Hideyuki Suzuki for his insight in finding an attack against an earlier version of the underlying key exchange protocol. special thanks to Lily Chen for her helpful chats about hashing into an elliptic curve ๐Ÿ’œ and Rich Davis gets a shoutout for suggesting the defensive checks that are part of processing the ServerKeyExchange and ClientKeyExchange messages. his various comments made this memo, and the key exchange it's built on, so much better ๐Ÿ‘‘

Martin Rex, Peter Gutmann, Marsh Ray, and Rene Struik had a discussion on the TLS mailing list about whether someone could pull off a side-channel attack against the hunting-and-pecking loop. that conversation is what led to adding the security parameter, m, to the hunting-and-pecking loop ๐Ÿ”ฅ and Scott Fluhrer came up with the blinding technique for testing whether a value is a quadratic residue modulo a prime, in a way that doesn't leak information about the value being tested. iconic teamwork, periodt ๐Ÿ’…

Author's Address ๐Ÿงš

Dan Harkins (editor) HP Enterprise 3333 Scott Blvd. Santa Clara, CA 95054 United States of America

Email: dharkins@lounge.org

๐Ÿ“ฆ where this page comes from