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

Mike Hamburg <mike@shiftleft.org> Wed, 03 April 2024 15:40 UTC

Return-Path: <mike@SHIFTLEFT.ORG>
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 2B2C8C14F5F9 for <cfrg@ietfa.amsl.com>; Wed, 3 Apr 2024 08:40:06 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -7.095
X-Spam-Level:
X-Spam-Status: No, score=-7.095 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_DNSWL_HI=-5, 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 (1024-bit key) header.d=shiftleft.org
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 3BOK6X3o6QbI for <cfrg@ietfa.amsl.com>; Wed, 3 Apr 2024 08:40:01 -0700 (PDT)
Received: from wanderer.shiftleft.org (wanderer.shiftleft.org [45.79.68.162]) (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 6F5DCC14F5F6 for <cfrg@irtf.org>; Wed, 3 Apr 2024 08:40:00 -0700 (PDT)
Received: from localhost (localhost [127.0.0.1]) (Authenticated sender: mike) by wanderer.shiftleft.org (Postfix) with ESMTPSA id C68E242245; Wed, 3 Apr 2024 15:39:58 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=shiftleft.org; s=sldo; t=1712158799; bh=Ft5xHN+Gx2YLXQqrR+0ASbDdbO8xNoyBohY8T9jysPY=; h=From:Subject:Date:In-Reply-To:Cc:To:References:From; b=cjPKhsZ18QxQYLM4UavUVEDDeq+3OCx00etWn4x+xAPC+uljXVhuCTFXtzRcYhDe5 l2/LQ8aiCu4M7oiopcOqoWfplhdcd4hUSQGpnFZgMm2GB8dPFSPiGuFKQdq77dtRw6 HtqzyKaWzRZIwWt6k2KFbTcWmrJHbOOHBAnQ04XY=
From: Mike Hamburg <mike@shiftleft.org>
Message-Id: <739A462E-D02A-4B36-871E-19C282A09F90@shiftleft.org>
Content-Type: multipart/alternative; boundary="Apple-Mail=_9432CAB4-F271-4B23-B58C-93ED5CFB1C9B"
Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3774.500.171.1.1\))
Date: Wed, 03 Apr 2024 11:39:47 -0400
In-Reply-To: <a5ec7b9e-62d3-4bd0-8bc9-ad23c9818e2b@aaa-sec.com>
Cc: Jack Grigg <ietf@jackgrigg.com>, stef <f3o09vld@ctrlc.hu>, IRTF CFRG <cfrg@irtf.org>
To: Stefan Santesson <stefan@aaa-sec.com>
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>
Archived-At: <https://mailarchive.ietf.org/arch/msg/cfrg/Y3UTOB9mtp2P-TJ4lLlkhvg4-Q8>
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 15:40:06 -0000

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 <mailto: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 <mailto: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