Subject: [kitten] SPAKE preauth: deriving RFC3961 encryption keys

From: Greg Hudson <[email-masked]>
Date: Fri, 12 Jun 2015 13:06:28 -0400

In the current design of the SPAKE preauth mechanism, once the client
generates its public value, the client and KDC need to derive a series
of RFC 3961 encryption keys K'[n].  Keys in this series are used for
confirmation in the SPAKEResponse, to encrypt any subsequent
second-factor challenges and responses, and finally for the reply key.
The basic inputs for this derivation are the computed shared value K,
the transcript checksum, and the encoded KDC-REQ-BODY for the request
being sent or processed.  The initial reply key (typically the client
principal long-term key) can also be used as an input, although it was
already used as an input to the SPAKE negotiation.

The current draft in github [1] specifies, basically, that K'[n] is
random-to-key(PRF+(initial-reply-key, "SPAKEKey"||K||cksum||body||n)).
This method is convenient in that it uses only RFC 3961 operations.  But
it relies on the security properties of the PRF in a weird way; the
assumed high-entropy information (K) is in the PRF input string, while
the PRF key is assumed to be low-entropy.

Let's call that alternative 1.  Here are two other alternatives:

2. Each group profile [2] designates an unkeyed hash function H (e.g.
SHA-256).  Following a similar method to RFC 4556, we derive K'[n] as
follows:

  H+(x, k) = k-truncate(H(1||x) || H(2||x) || ...)
  K'[n] = random-to-key(H+(n||"SPAKEKey"||K||cksum||body), seedlen)

3. As in (2), with the additional step of combining the result with the
additional reply key using KRB-FX-CF2:

  H+(x, k) = k-truncate(H(1||x) || H(2||x) || ...)
  Ki[n] = random-to-key(H+(n||"SPAKEKey"||K||cksum||body), seedlen)
  K'[n] = KRB-FX-CF2(initial-reply-key, Ki[n], "pepper1", "pepper2")

I don't believe this additional step is necessary, because K is already
derived from the initial reply key via the SPAKE algorithm.  But
depending on how one reads the language of RFC 6113 section 3.2, that
step might be required in order to say that we implement the
"strengthening reply key" facility.  That section begins:

   Particularly when dealing with keys based on passwords, it is
   desirable to increase the strength of the key by adding additional
   secrets to it.  Examples of sources of additional secrets include the
   results of a Diffie-Hellman key exchange or key bits from the output
   of a smart card [KRB-WG.SAM].  Typically, these additional secrets
   can be first combined with the existing reply key and then converted
   to a protocol key using tools defined in Section 5.1.

Section 5.1 defines KRB-FX-CF1() (which combines two passphrases),
KRB-FX-CF2(), and PRF+ as an intermediate step of defining
KRB-FX-CF2().

Do people have opinions on which option is best?  Have I missed anything
else?

[1] https://github.com/npmccallum/ietf

[2] Group profiles don't exist in the current draft, but we are planning
to shift to numbered, registered group profiles in order to avoid
interop issues with calculating M and N, representing points and
producing scalars, etc.

---

From: Simo Sorce <[email-masked]>
Date: Mon, 15 Jun 2015 09:47:57 -0400

> the PRF key is assumed to be low-entropy.

Why don't we just swap them, then ?

>    to a protocol key using tools defined in Section 5.1.

Doesn't this confirm that additional step are not required ?
It seem that adding more computational requirements without a clear need
is not desirable, given the SPAKE algorithm is already computationally
heavier than current pre-auth mechanisms.

> Do people have opinions on which option is best?  Have I missed anything

I would like to understand better why we should add more work here, is
it necessary, or is it just abundance of caution due to the definition
in 6113 not perfectly matching this new, unforeseen at the time,
mechanism ?

Simo.

> _______________________________________________
> Kitten mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/kitten

-- 
Simo Sorce * Red Hat, Inc * New York

---

From: Greg Hudson <[email-masked]>
Date: Mon, 15 Jun 2015 16:06:52 -0400

> Why don't we just swap them, then ?

We can't, because K is not an RFC 3961 key.  It is the octet string
representation of a group element.

>>   K'[n] = random-to-key(H+(n||"SPAKEKey"||K||cksum||body), seedlen)

This was a braino on my part; it would be SPAKE1 rather than SPAKE2.  We
would need to hash in some form of the w value (probably the
un-preprocessed PRF+ result).

> heavier than current pre-auth mechanisms.

I don't know what the precise intent of the RFC 6113 language is, so I'm
asking.  It may be safe to assume that any cryptographically secure
derivative of the initial reply key can be termed strengthening.

> in 6113 not perfectly matching this new, unforeseen at the time,

I am primarily asking whether people think it is okay to use the
existing PRF+ method with a low-entropy key and a high-entropy input
string, or whether we need to add an unkeyed hash function to the
profile and use H+(n||"SPAKEKey"||K||w||cksum||body).

---

From: Nico Williams <[email-masked]>
Date: Tue, 16 Jun 2015 15:02:37 -0500

> profile and use H+(n||"SPAKEKey"||K||w||cksum||body).

Thanks for summarizing it so well.

The PRF+() comes from RFC6113, and relies on the RFC3961 pseudo-random().
The latter has specific requirements.

The requirements for pseudo-random() do not make it entirely clear that
using a low-entropy ("public") key and high-entropy (confidential) input
is safe.  But for the simplified profile it's clear that it can only be
safe to use pseudo-random() with low-entropy keys / high-entropy inputs
when the output of pseudo-random() is kept confidential.

For the particular purpose of generating confidential keys, then, I
think PRF+() with low-entropy key and high-entropy input seems OK.
Asking a cryptographer seems like a good idea though!

Nico
--

---

From: Benjamin Kaduk <[email-masked]>
Date: Mon, 22 Jun 2015 12:11:56 -0400 (EDT)

> Asking a cryptographer seems like a good idea though!

The problem is that we cannot assume the use of the simplified profile
(indeed, the pending aes-sha2 enctype does not use the simplified
profile), and the requirements in 3961 for the pseudo-random function are
not worded in a particularly stringent way:

%   pseudo-random (protocol-key, octet-string)->(octet-string)
%      This pseudo-random function should generate an octet string of
%      some size that is independent of the octet string input.  The PRF
%      output string should be suitable for use in key generation, even
%      if the octet string input is public.  It should not reveal the
%      input key, even if the output is made public.

While it should certainly be the case that the output string is useful for
key generation when the input string is private, there is not really
anything there to indicate how much of the input must be "mixed" into the
output, or to indicate that the output when a low-entropy input key can
have more entropy when such is present in the input octet string.

Thus, while I believe proposal #1 is safe with all exisiting public
enctypes (and proposed enctypes that are WG documents), I do not feel
comfortable claiming that it will always be safe, in a formal manner.
That said, introducing an unkeyed hash as for proposals #2 and #3 seems
like overkill.  I think I'd be more inclined to make this document update
3961 and provide more clarity for the pseudo-random function requirements.

-Ben

P.S. for completeness, I don't think the additional combining in #3 is
needed; #2 seems to comply with the spirit of 6113.