Re: [CFRG] Does OPRF/OPAQUE require full implementation of RFC 9380

Stefan Santesson <stefan@aaa-sec.com> Wed, 03 April 2024 22:02 UTC

Return-Path: <stefan@aaa-sec.com>
X-Original-To: cfrg@ietfa.amsl.com
Delivered-To: cfrg@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id AC863C14F680 for <cfrg@ietfa.amsl.com>; Wed, 3 Apr 2024 15:02:03 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -2.093
X-Spam-Level:
X-Spam-Status: No, score=-2.093 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, HTML_MESSAGE=0.001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_ZEN_BLOCKED_OPENDNS=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001, URIBL_DBL_BLOCKED_OPENDNS=0.001, URIBL_ZEN_BLOCKED_OPENDNS=0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (2048-bit key) header.d=aaa-sec.com
Received: from mail.ietf.org ([50.223.129.194]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 4jAQTZrQhwf6 for <cfrg@ietfa.amsl.com>; Wed, 3 Apr 2024 15:01:59 -0700 (PDT)
Received: from smtp.outgoing.loopia.se (smtp.outgoing.loopia.se [93.188.3.37]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id B8320C14F5F6 for <cfrg@irtf.org>; Wed, 3 Apr 2024 15:01:58 -0700 (PDT)
Received: from s807.loopia.se (localhost [127.0.0.1]) by s807.loopia.se (Postfix) with ESMTP id 723C6300B834 for <cfrg@irtf.org>; Thu, 4 Apr 2024 00:01:56 +0200 (CEST)
Received: from s979.loopia.se (unknown [172.22.191.6]) by s807.loopia.se (Postfix) with ESMTP id 621662E2EFCF; Thu, 4 Apr 2024 00:01:56 +0200 (CEST)
Received: from s898.loopia.se (unknown [172.22.191.6]) by s979.loopia.se (Postfix) with ESMTP id 5FDFF10BC346; Thu, 4 Apr 2024 00:01:56 +0200 (CEST)
X-Virus-Scanned: amavisd-new at amavis.loopia.se
Authentication-Results: s898.loopia.se (amavisd-new); dkim=pass (2048-bit key) header.d=aaa-sec.com
Received: from s934.loopia.se ([172.22.191.6]) by s898.loopia.se (s898.loopia.se [172.22.190.17]) (amavisd-new, port 10024) with UTF8LMTP id vcv1uWrv884b; Thu, 4 Apr 2024 00:01:55 +0200 (CEST)
X-Loopia-Auth: user
X-Loopia-User: mailstore2@aaa-sec.com
X-Loopia-Originating-IP: 90.228.170.155
Received: from [10.10.0.158] (unknown [90.228.170.155]) (Authenticated sender: mailstore2@aaa-sec.com) by s934.loopia.se (Postfix) with ESMTPSA id CF8177CEA3A; Thu, 4 Apr 2024 00:01:54 +0200 (CEST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aaa-sec.com; s=loopiadkim1707241022; t=1712181714; bh=TLg2J1fsqF/7lFLqFh3J98bObM2IdP5s3KnFbTCVmEk=; h=Date:Subject:From:To:Cc:References:In-Reply-To; b=HkClpWpcBD/H/FYqfWpWCvdEQCzHE/cLEgAGupeRytJfz4ayCRzJcWj9eIGSn+4Br +3sWPhZj589bSyxuHMwxfTB9+iC9+UNoDbiDf5AeaC/ysB5qg4nRuD7a/9eCwtv6G+ I+kF+jBIGTsNzszDtmMtzVpy0cz0Mam7L3KqCOJU6VZG8tScfFwnrasnzdyMsOY3YM TByDkYldXLhI7Yv4RMWRtJHeu2KDujdobBYOqd+VPB6glmzg9/oR47rpzaanxTReIP 4C9r6VMQeumjb/pZQaNpWmrzem0qeQJnlm/gfK2hUe3SQNrhfpvgeg/8Ovu+NhqbSw KExHQVSJ1cDBw==
Content-Type: multipart/alternative; boundary="------------RzYoRoNTjkSRkOG8ycMUAvof"
Message-ID: <4976080c-12eb-4bfe-8301-19fafb20661d@aaa-sec.com>
Date: Thu, 04 Apr 2024 00:01:54 +0200
MIME-Version: 1.0
User-Agent: Mozilla Thunderbird Beta
From: Stefan Santesson <stefan@aaa-sec.com>
To: Mike Hamburg <mike@shiftleft.org>
Cc: IRTF CFRG <cfrg@irtf.org>
References: <410a0800-78ff-422f-8ca3-5a0211478cbd@aaa-sec.com> <ZggHSDs5bRweThW5@localhost> <CAPC=aNUSTv=JtpkG71vhu25jgpVqzL5XS81543ntLMUuXcchqw@mail.gmail.com> <a5ec7b9e-62d3-4bd0-8bc9-ad23c9818e2b@aaa-sec.com> <739A462E-D02A-4B36-871E-19C282A09F90@shiftleft.org> <eb7dd447-adab-47cc-870a-51c31d4b42b4@aaa-sec.com>
Content-Language: sv-SE, en-GB
Autocrypt: addr=stefan@aaa-sec.com; keydata= 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 4831tbIM6eKC9gY3xUsE4vSV/CPdPKjV
Organization: 3xA Security AB
In-Reply-To: <eb7dd447-adab-47cc-870a-51c31d4b42b4@aaa-sec.com>
Archived-At: <https://mailarchive.ietf.org/arch/msg/cfrg/QjjZ0CeQAc3NEU-KXVFeST4j-FY>
Subject: Re: [CFRG] Does OPRF/OPAQUE require full implementation of RFC 9380
X-BeenThere: cfrg@irtf.org
X-Mailman-Version: 2.1.39
Precedence: list
List-Id: Crypto Forum Research Group <cfrg.irtf.org>
List-Unsubscribe: <https://mailman.irtf.org/mailman/options/cfrg>, <mailto:cfrg-request@irtf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/cfrg/>
List-Post: <mailto:cfrg@irtf.org>
List-Help: <mailto:cfrg-request@irtf.org?subject=help>
List-Subscribe: <https://mailman.irtf.org/mailman/listinfo/cfrg>, <mailto:cfrg-request@irtf.org?subject=subscribe>
X-List-Received-Date: Wed, 03 Apr 2024 22:02:03 -0000

I just have to post a correction.

That experimental test I posted is not correct. There is no reason to 
reveal through the Y value if you succeeded on an odd or even attempt.

The correct version of the algorithm we tested was:

loop a fixed amount (e.g. 0 -> 64) {

  test and increment {

      compressed (y,x) = hkdf(hash(pw), counter)

      if (point(y,x) == valid)  also test an invalid point

      if (point(y,x) != valid) also test a valid point

   }

   save first valid point

}

/Stefan




On 2024-04-03 23:36, Stefan Santesson wrote:
>
> Mike,
>
> Thank you very much for this great answer.
>
> Yes, we were looking at that type of attacks where the knowledge of 
> the input scalar allows you to reconstruct multiple OPRF responses for 
> arbitrary input.
>
> However, in that analysis I didn't consider the client as the 
> adversary. But when you do, that attack is quite obvious and a good 
> reason not to go there!
>
>
> I totally agree on the constant-time issue. We made some 
> experimenting, just for the fun of it, and we ended up in something 
> like this as our best attempt:
>
>
> loop a fixed amount (e.g. 0 -> 64) {
>
>  test and increment {
>
>      x = hkdf(hash(pw), counter)
>
>      y = counter % 2 == 0 ? 0x02 : 0x03 // compressed
>
>      if (point(y,x) == valid)  also test an invalid point
>
>      if (point(y,x) != valid) also test a valid point
>
>   }
>
>   save first valid point
>
> }
>
>
> This way we always make almost exactly the same amount of work. For 
> each iteration in the loop we test one valid point and one invalid point.
>
> But still I could detect statistically detectable difference over many 
> consecutive tests of different passwords. But to detect this you 
> needed quite some attempts.
>
> I don't think there is a way to make this perfect. But for simplistic 
> implementations where this is not an active threat, it does offer a 
> very easy implementation alternative.
>
> One we won't use of course ;)
>
>
> Once you have hash to curve implemented, making it any other way makes 
> no sense.
>
>
> Thanks again. This was very helpful!
>
> /Stefan
>
>
> On 2024-04-03 17:39, Mike Hamburg wrote:
>> Hello Stefan,
>>
>> Yes, I believe that if you used the Java code implementing
>>
>> NOPRF(x) := g^(hash(x) * k)
>>
>> then this would directly lead to a complete failure in the security 
>> goals of both OPRF and OPAQUE.  (I’m calling it NOPRF because the 
>> problem is it’s not a PRF.)  This is because one of OPRF’s security 
>> goals is that it cannot be evaluated offline without the server’s 
>> key, and this goal is violated for NOPRF once a single interaction 
>> has taken place (leading to the recovery of g^k).  That goal is in 
>> turn required for OPAQUE; if the PRF were weak and could be evaluated 
>> offline, then a malicious client could brute-force the password 
>> offline after one interaction with the server.
>>
>> This is because, when using OPRF, the client’s first message commits 
>> to a guess of the password, and then the server’s first message gives 
>> enough information to check that guess.  With NOPRF, the client's 
>> first message does not commit to a guess of the password, so the 
>> client can then use the server’s first message to check any guess 
>> (i.e. to brute-force the password offline).  That said, while I have 
>> worked on similar PAKEs in the past, I have not studied the issue in 
>> detail for OPAQUE, so I might be missing something.
>>
>>
>> Regarding “constant-time” behavior of try-and-increment, it is 
>> generally considered poor practice to try to plaster over 
>> non-constant-time behavior by setting min/max timers, because this 
>> usually doesn’t hide the timing as well as you want (the timers 
>> aren’t as precise as you want; the number of iterations still affects 
>> system load which affects timing of other tasks; etc).  Best 
>> practices in this area require a more disciplined approach where 
>> secrets do not affect branches, memory addresses, arguments to 
>> certain instructions (such as division), etc.  This difficulty was a 
>> significant part of the motivation for developing the existing 
>> hashToCurve methods: those methods were developed in order to be 
>> simpler to implement in constant time than try-and-increment.
>>
>> Unlike using NOPRF, having a non-constant-time hash won’t immediately 
>> and catastrophically break the system: it will be a meaningful 
>> vulnerability, but one which requires effort to exploit, instead of 
>> simply trying one login and then brute-forcing the password.  Leaking 
>> even a small amount of information about a password (through timing) 
>> is a problem, because the whole point of PAKE is that passwords don’t 
>> have much entropy.
>>
>> Regards,
>> — Mike
>>
>>> On Apr 2, 2024, at 2:36 AM, Stefan Santesson <stefan@aaa-sec.com> wrote:
>>>
>>> Thanks Jack,
>>>
>>> Your answer is very helpful.
>>>
>>> To clarify, my questions here are hypothetical questions to help 
>>> understand exactly where the boundaries are. My sample code is the 
>>> worst possible way to do it and nothing we plan to use. But I'm 
>>> still curious about whether it would work.
>>>
>>> I fully understand the problem of deriving a point from an input 
>>> scalar and I can see many situations where that would be 
>>> catastrophic. But AFAIK that catastrophic failure is as far as I 
>>> understand related to one of two events:
>>>
>>> 1) You actually do an operation with the input scalar as a private key
>>>
>>> 2) The derivation process can be reproduced by an adversary
>>>
>>> It seems to me that in OPRF neither of these are the case when a 
>>> password is hashed to a point and then blinded. Because of the 
>>> blinding, the point is never known and the input scalar is never used.
>>>
>>> That's why I'm curious if there is any explicit known threat here, 
>>> rather than this is considered good practice (which I fully agree with).
>>>
>>>
>>> Regarding the "try-and-increment", I have also experimented with 
>>> constant time variants of this working simply like:
>>>
>>>   - Make attempts and increment until you reached minimum constant 
>>> time, then take first successful result
>>>
>>> A variant  of this is:
>>>
>>>  - Find the first working point by "try-and-increment" and return 
>>> result after constant time has passed:
>>>
>>> The former seems better as it would require a more uniform workload, 
>>> but the precision of the constant time is better with the latter.
>>>
>>>
>>> Again. Thanks for the replies. I personally plan to implement the 
>>> standard RFC9380, but these questions are helpful to internal 
>>> debates on whether you could do this simpler with a good security 
>>> result.
>>>
>>> /Stefan
>>>
>>>
>>>
>>>
>>> On 2024-03-30 21:01, Jack Grigg wrote:
>>>> Hi all,
>>>>
>>>> On Sat, Mar 30, 2024 at 6:56 AM Stefan Santesson 
>>>> <stefan@aaa-sec.com> wrote:
>>>>
>>>>     Section 2.1 in OPR (RFC 9497) states:
>>>>
>>>>     "HashToGroup(x):  Deterministically maps an array of bytes x to
>>>>     an element of Group.  The map must ensure that, for any
>>>>     adversary receiving R = HashToGroup(x), it is computationally
>>>>     difficult to reverse the mapping."
>>>>
>>>>     [..]
>>>>
>>>>     It continues to say that "Security properties of this function
>>>>     are described in [RFC9380]".
>>>>
>>>>     [..]
>>>>
>>>>     I would really appreciate help. Has this been discussed already
>>>>     to any detail. Is there any guidance available?
>>>>
>>>> As Mike Hamburg alludes to in another message in this thread, the 
>>>> security property of HashToGroup relied upon here is that the 
>>>> output of the function must be a uniformly random element of the 
>>>> group, with no easily-determined relation to any canonical 
>>>> generator of the group (more precisely, HashToGroup should be 
>>>> indifferentiable from a random oracle; see Sections 2.2.3 and 10.1 
>>>> of RFC 9380). The proposed approach in your email makes inputScalar 
>>>> a known quantity, which directly breaks this property (inputScalar 
>>>> is the easily-determined relation to the canonical generator, 
>>>> because outputElement = [inputScalar] G).
>>>>
>>>> Regardless of RFC 9497 using "must" instead of "MUST" when 
>>>> describing it, its reliance on this security property is clear; see 
>>>> Sections 2.1, 4.6, and 7.2.1 of RFC 9497 for further details.
>>>>
>>>>     If this is not good enough. Can you take any simpler path than
>>>>     full RFC 9380 implementation?
>>>>
>>>> If you use ristretto255 or decaf448, then most of the work should 
>>>> already be done by the libraries implementing the group (see 
>>>> below). See Section 4.1 of RFC 9497 for an OPRF ciphersuite 
>>>> instantiated over ristretto255 and SHA-512.
>>>>
>>>> For other groups (such as elliptic curves), there are other 
>>>> approaches like "try-and-increment", but these are not 
>>>> constant-time and may have other side-channel vulnerabilities in 
>>>> your setting; you would need to consult a cryptographer.
>>>>
>>>> On Sat, Mar 30, 2024 at 7:37 AM stef <f3o09vld@ctrlc.hu> wrote:
>>>>
>>>>     tbh i also think this is overkill since for some groups, like
>>>>     ristretto255 for
>>>>     example there is a widely used hashtogroup available in most big
>>>>     implementations (like crypto_scalarmult_ed25519 and
>>>>     crypto_core_ristretto255_from_hash in libsodium).
>>>>
>>>> Just to clarify here for wider benefit: RFC 9496 (which specifies 
>>>> ristretto255, as well as decaf448) includes an Element Derivation 
>>>> function (in Section 4.3.4), which when paired with a hash function 
>>>> can be used to build a hash-to-group operation (which I believe is 
>>>> what library functions like crypto_core_ristretto255_from_hash in 
>>>> libsodium provide). Appendix B of RFC 9380 documents precisely how 
>>>> this should be done to be compatible with it (specifically using an 
>>>> expand_message function that conforms to Section 5.3 of RFC 9380).
>>>>
>>>> Cheers,
>>>> Jack
>>> _______________________________________________
>>> CFRG mailing list
>>> CFRG@irtf.org
>>> https://mailman.irtf.org/mailman/listinfo/cfrg
>>
>
> _______________________________________________
> CFRG mailing list
> CFRG@irtf.org
> https://mailman.irtf.org/mailman/listinfo/cfrg