Files
opaque-lattice/papers/opaque-rfc9807.html
2026-01-06 12:49:26 -07:00

5898 lines
294 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en" class="RFC">
<head>
<meta charset="utf-8">
<meta content="Common,Latin" name="scripts">
<meta content="initial-scale=1.0" name="viewport">
<title>RFC 9807: The OPAQUE Augmented Password-Authenticated Key Exchange (aPAKE) Protocol</title>
<meta content="Daniel Bourdrez" name="author">
<meta content="Hugo Krawczyk" name="author">
<meta content="Kevin Lewi" name="author">
<meta content="Christopher A. Wood" name="author">
<meta content="
This document describes the OPAQUE protocol, an Augmented (or Asymmetric)
Password-Authenticated Key Exchange (aPAKE) protocol that supports mutual
authentication in a client-server setting without reliance on PKI and
with security against pre-computation attacks upon server compromise.
In addition, the protocol provides forward secrecy and the ability to
hide the password from the server, even during password registration.
This document specifies the core OPAQUE protocol and one instantiation
based on 3DH. This document is a product of the Crypto Forum Research
Group (CFRG) in the IRTF.
" name="description">
<meta content="xml2rfc 3.30.0" name="generator">
<meta content="9807" name="rfc.number">
<!-- Generator version information:
xml2rfc 3.30.0
Python 3.9.15
ConfigArgParse 1.5.3
google-i18n-address 3.0.0
intervaltree 3.1.0
Jinja2 3.1.2
lxml 5.3.0
platformdirs 3.8.0
pycountry 22.3.5
PyYAML 6.0
requests 2.28.0
setuptools 44.1.1
six 1.16.0
wcwidth 0.2.5
weasyprint 65.0
-->
<link href="rfc9807.xml" rel="alternate" type="application/rfc+xml">
<link href="#copyright" rel="license">
<style type="text/css">/*
NOTE: Changes at the bottom of this file overrides some earlier settings.
Once the style has stabilized and has been adopted as an official RFC style,
this can be consolidated so that style settings occur only in one place, but
for now the contents of this file consists first of the initial CSS work as
provided to the RFC Formatter (xml2rfc) work, followed by itemized and
commented changes found necessary during the development of the v3
formatters.
*/
/* fonts */
@import url('https://fonts.googleapis.com/css?family=Noto+Sans'); /* Sans-serif */
@import url('https://fonts.googleapis.com/css?family=Noto+Serif'); /* Serif (print) */
@import url('https://fonts.googleapis.com/css?family=Roboto+Mono'); /* Monospace */
:root {
--font-sans: 'Noto Sans', Arial, Helvetica, sans-serif;
--font-serif: 'Noto Serif', 'Times', 'Times New Roman', serif;
--font-mono: 'Roboto Mono', Courier, 'Courier New', monospace;
}
@viewport {
zoom: 1.0;
}
@-ms-viewport {
width: extend-to-zoom;
zoom: 1.0;
}
/* general and mobile first */
html {
}
body {
max-width: 90%;
margin: 1.5em auto;
color: #222;
background-color: #fff;
font-size: 14px;
font-family: var(--font-sans);
line-height: 1.6;
scroll-behavior: smooth;
overflow-wrap: break-word;
}
.ears {
display: none;
}
/* headings */
#title, h1, h2, h3, h4, h5, h6 {
margin: 1em 0 0.5em;
font-weight: bold;
line-height: 1.3;
}
#title {
clear: both;
border-bottom: 1px solid #ddd;
margin: 0 0 0.5em 0;
padding: 1em 0 0.5em;
}
.author {
padding-bottom: 4px;
}
h1 {
font-size: 26px;
margin: 1em 0;
}
h2 {
font-size: 22px;
margin-top: -20px; /* provide offset for in-page anchors */
padding-top: 33px;
}
h3 {
font-size: 18px;
margin-top: -36px; /* provide offset for in-page anchors */
padding-top: 42px;
}
h4 {
font-size: 16px;
margin-top: -36px; /* provide offset for in-page anchors */
padding-top: 42px;
}
h5, h6 {
font-size: 14px;
}
#n-copyright-notice {
border-bottom: 1px solid #ddd;
padding-bottom: 1em;
margin-bottom: 1em;
}
/* general structure */
p {
padding: 0;
margin: 0 0 1em 0;
text-align: left;
}
div, span {
position: relative;
}
div {
margin: 0;
}
.alignRight.art-text {
background-color: #f9f9f9;
border: 1px solid #eee;
border-radius: 3px;
padding: 1em 1em 0;
margin-bottom: 1.5em;
}
.alignRight.art-text pre {
padding: 0;
}
.alignRight {
margin: 1em 0;
}
.alignRight > *:first-child {
border: none;
margin: 0;
float: right;
clear: both;
}
.alignRight > *:nth-child(2) {
clear: both;
display: block;
border: none;
}
svg {
display: block;
}
@media print {
svg {
max-height: 850px;
max-width: 660px;
}
}
svg[font-family~="serif" i], svg [font-family~="serif" i] {
font-family: var(--font-serif);
}
svg[font-family~="sans-serif" i], svg [font-family~="sans-serif" i] {
font-family: var(--font-sans);
}
svg[font-family~="monospace" i], svg [font-family~="monospace" i] {
font-family: var(--font-mono);
}
.alignCenter.art-text {
background-color: #f9f9f9;
border: 1px solid #eee;
border-radius: 3px;
padding: 1em 1em 0;
margin-bottom: 1.5em;
}
.alignCenter.art-text pre {
padding: 0;
}
.alignCenter {
margin: 1em 0;
}
.alignCenter > *:first-child {
display: table;
border: none;
margin: 0 auto;
}
/* lists */
ol, ul {
padding: 0;
margin: 0 0 1em 2em;
}
ol ol, ul ul, ol ul, ul ol {
margin-left: 1em;
}
li {
margin: 0 0 0.25em 0;
}
.ulCompact li {
margin: 0;
}
ul.empty, .ulEmpty {
list-style-type: none;
}
ul.empty li, .ulEmpty li {
margin-top: 0.5em;
}
ul.ulBare, li.ulBare {
margin-left: 0em !important;
}
ul.compact, .ulCompact,
ol.compact, .olCompact {
line-height: 100%;
margin: 0 0 0 2em;
}
/* definition lists */
dl {
}
dl > dt {
float: left;
margin-right: 1em;
}
/*
dl.nohang > dt {
float: none;
}
*/
dl > dd {
margin-bottom: .8em;
min-height: 1.3em;
}
dl.compact > dd, .dlCompact > dd {
margin-bottom: 0em;
}
dl > dd > dl {
margin-top: 0.5em;
margin-bottom: 0em;
}
/* links */
a {
text-decoration: none;
}
a[href] {
color: #22e; /* Arlen: WCAG 2019 */
}
a[href]:hover {
background-color: #f2f2f2;
}
figcaption a[href],
a[href].selfRef {
color: #222;
}
/* XXX probably not this:
a.selfRef:hover {
background-color: transparent;
cursor: default;
} */
/* Figures */
tt, code, pre {
background-color: #f9f9f9;
font-family: var(--font-mono);
}
pre {
border: 1px solid #eee;
margin: 0;
padding: 1em;
}
img {
max-width: 100%;
}
figure {
margin: 0;
}
figure blockquote {
margin: 0.8em 0.4em 0.4em;
}
figcaption {
font-style: italic;
margin: 0 0 1em 0;
}
@media screen {
pre {
overflow-x: auto;
max-width: 100%;
max-width: calc(100% - 22px);
}
}
/* aside, blockquote */
aside, blockquote {
margin-left: 0;
padding: 1.2em 2em;
}
blockquote {
background-color: #f9f9f9;
color: #111; /* Arlen: WCAG 2019 */
border: 1px solid #ddd;
border-radius: 3px;
margin: 1em 0;
}
blockquote > *:last-child {
margin-bottom: 0;
}
cite {
display: block;
text-align: right;
font-style: italic;
}
.xref {
overflow-wrap: normal;
}
/* tables */
table {
width: 100%;
margin: 0 0 1em;
border-collapse: collapse;
border: 1px solid #eee;
}
th, td {
text-align: left;
vertical-align: top;
padding: 0.5em 0.75em;
}
th {
text-align: left;
background-color: #e9e9e9;
}
tr:nth-child(2n+1) > td {
background-color: #f5f5f5;
}
table caption {
font-style: italic;
margin: 0;
padding: 0;
text-align: left;
}
table p {
/* XXX to avoid bottom margin on table row signifiers. If paragraphs should
be allowed within tables more generally, it would be far better to select on a class. */
margin: 0;
}
/* pilcrow */
a.pilcrow {
color: #666; /* Arlen: AHDJ 2019 */
text-decoration: none;
visibility: hidden;
user-select: none;
-ms-user-select: none;
-o-user-select:none;
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
-webkit-touch-callout: none;
}
@media screen {
aside:hover > a.pilcrow,
p:hover > a.pilcrow,
blockquote:hover > a.pilcrow,
div:hover > a.pilcrow,
li:hover > a.pilcrow,
pre:hover > a.pilcrow {
visibility: visible;
}
a.pilcrow:hover {
background-color: transparent;
}
}
/* misc */
hr {
border: 0;
border-top: 1px solid #eee;
}
.bcp14 {
font-variant: small-caps;
}
.role {
font-variant: all-small-caps;
}
/* info block */
#identifiers {
margin: 0;
font-size: 0.9em;
}
#identifiers dt {
width: 3em;
clear: left;
}
#identifiers dd {
float: left;
margin-bottom: 0;
}
/* Fix PDF info block run off issue */
@media print {
#identifiers dd {
max-width: 100%;
}
}
#identifiers .authors .author {
display: inline-block;
margin-right: 1.5em;
}
#identifiers .authors .org {
font-style: italic;
}
/* The prepared/rendered info at the very bottom of the page */
.docInfo {
color: #666; /* Arlen: WCAG 2019 */
font-size: 0.9em;
font-style: italic;
margin-top: 2em;
}
.docInfo .prepared {
float: left;
}
.docInfo .prepared {
float: right;
}
/* table of contents */
#toc {
padding: 0.75em 0 2em 0;
margin-bottom: 1em;
}
nav.toc ul {
margin: 0 0.5em 0 0;
padding: 0;
list-style: none;
}
nav.toc li {
line-height: 1.3em;
margin: 0.75em 0;
padding-left: 1.2em;
text-indent: -1.2em;
}
/* references */
.references dt {
text-align: right;
font-weight: bold;
min-width: 7em;
}
.references dd {
margin-left: 8em;
overflow: auto;
}
.refInstance {
margin-bottom: 1.25em;
}
.refSubseries {
margin-bottom: 1.25em;
}
.references .ascii {
margin-bottom: 0.25em;
}
/* index */
.index ul {
margin: 0 0 0 1em;
padding: 0;
list-style: none;
}
.index ul ul {
margin: 0;
}
.index li {
margin: 0;
text-indent: -2em;
padding-left: 2em;
padding-bottom: 5px;
}
.indexIndex {
margin: 0.5em 0 1em;
}
.index a {
font-weight: 700;
}
/* make the index two-column on all but the smallest screens */
@media (min-width: 600px) {
.index ul {
-moz-column-count: 2;
-moz-column-gap: 20px;
}
.index ul ul {
-moz-column-count: 1;
-moz-column-gap: 0;
}
}
/* authors */
address.vcard {
font-style: normal;
margin: 1em 0;
}
address.vcard .nameRole {
font-weight: 700;
margin-left: 0;
}
address.vcard .label {
font-family: var(--font-sans);
margin: 0.5em 0;
}
address.vcard .type {
display: none;
}
.alternative-contact {
margin: 1.5em 0 1em;
}
hr.addr {
border-top: 1px dashed;
margin: 0;
color: #ddd;
max-width: calc(100% - 16px);
}
/* temporary notes */
.rfcEditorRemove::before {
position: absolute;
top: 0.2em;
right: 0.2em;
padding: 0.2em;
content: "The RFC Editor will remove this note";
color: #9e2a00; /* Arlen: WCAG 2019 */
background-color: #ffd; /* Arlen: WCAG 2019 */
}
.rfcEditorRemove {
position: relative;
padding-top: 1.8em;
background-color: #ffd; /* Arlen: WCAG 2019 */
border-radius: 3px;
}
.cref {
background-color: #ffd; /* Arlen: WCAG 2019 */
padding: 2px 4px;
}
.crefSource {
font-style: italic;
}
/* alternative layout for smaller screens */
@media screen and (max-width: 1023px) {
body {
padding-top: 2em;
}
#title {
padding: 1em 0;
}
h1 {
font-size: 24px;
}
h2 {
font-size: 20px;
margin-top: -18px; /* provide offset for in-page anchors */
padding-top: 38px;
}
#identifiers dd {
max-width: 60%;
}
#toc {
position: fixed;
z-index: 2;
top: 0;
right: 0;
padding: 0;
margin: 0;
background-color: inherit;
border-bottom: 1px solid #ccc;
}
#toc h2 {
margin: -1px 0 0 0;
padding: 4px 0 4px 6px;
padding-right: 1em;
min-width: 190px;
font-size: 1.1em;
text-align: right;
background-color: #444;
color: white;
cursor: pointer;
}
#toc h2::before { /* css hamburger */
float: right;
position: relative;
width: 1em;
height: 1px;
left: -164px;
margin: 6px 0 0 0;
background: white none repeat scroll 0 0;
box-shadow: 0 4px 0 0 white, 0 8px 0 0 white;
content: "";
}
#toc nav {
display: none;
padding: 0.5em 1em 1em;
overflow: auto;
height: calc(100vh - 48px);
border-left: 1px solid #ddd;
}
}
/* alternative layout for wide screens */
@media screen and (min-width: 1024px) {
body {
max-width: 724px;
margin: 42px auto;
padding-left: 1.5em;
padding-right: 29em;
}
#toc {
position: fixed;
top: 42px;
right: 42px;
width: 25%;
margin: 0;
padding: 0 1em;
z-index: 1;
}
#toc h2 {
border-top: none;
border-bottom: 1px solid #ddd;
font-size: 1em;
font-weight: normal;
margin: 0;
padding: 0.25em 1em 1em 0;
}
#toc nav {
display: block;
height: calc(90vh - 84px);
bottom: 0;
padding: 0.5em 0 0;
overflow: auto;
}
img { /* future proofing */
max-width: 100%;
height: auto;
}
}
/* pagination */
@media print {
body {
width: 100%;
}
p {
orphans: 3;
widows: 3;
}
#n-copyright-notice {
border-bottom: none;
}
#toc, #n-introduction {
page-break-before: always;
}
#toc {
border-top: none;
padding-top: 0;
}
figure, pre {
page-break-inside: avoid;
}
figure {
overflow: scroll;
}
.breakable pre {
break-inside: auto;
}
h1, h2, h3, h4, h5, h6 {
page-break-after: avoid;
}
h2+*, h3+*, h4+*, h5+*, h6+* {
page-break-before: avoid;
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
font-size: 10pt;
}
table {
border: 1px solid #ddd;
}
td {
border-top: 1px solid #ddd;
}
}
/* This is commented out here, as the string-set: doesn't
pass W3C validation currently */
/*
.ears thead .left {
string-set: ears-top-left content();
}
.ears thead .center {
string-set: ears-top-center content();
}
.ears thead .right {
string-set: ears-top-right content();
}
.ears tfoot .left {
string-set: ears-bottom-left content();
}
.ears tfoot .center {
string-set: ears-bottom-center content();
}
.ears tfoot .right {
string-set: ears-bottom-right content();
}
*/
@page :first {
padding-top: 0;
@top-left {
content: normal;
border: none;
}
@top-center {
content: normal;
border: none;
}
@top-right {
content: normal;
border: none;
}
}
@page {
size: A4;
margin-bottom: 45mm;
padding-top: 20px;
/* The following is commented out here, but set appropriately by in code, as
the content depends on the document */
/*
@top-left {
content: 'Internet-Draft';
vertical-align: bottom;
border-bottom: solid 1px #ccc;
}
@top-left {
content: string(ears-top-left);
vertical-align: bottom;
border-bottom: solid 1px #ccc;
}
@top-center {
content: string(ears-top-center);
vertical-align: bottom;
border-bottom: solid 1px #ccc;
}
@top-right {
content: string(ears-top-right);
vertical-align: bottom;
border-bottom: solid 1px #ccc;
}
@bottom-left {
content: string(ears-bottom-left);
vertical-align: top;
border-top: solid 1px #ccc;
}
@bottom-center {
content: string(ears-bottom-center);
vertical-align: top;
border-top: solid 1px #ccc;
}
@bottom-right {
content: '[Page ' counter(page) ']';
vertical-align: top;
border-top: solid 1px #ccc;
}
*/
}
/* Changes introduced to fix issues found during implementation */
/* Make sure links are clickable even if overlapped by following H* */
a {
z-index: 2;
}
/* Separate body from document info even without intervening H1 */
section {
clear: both;
}
/* Top align author divs, to avoid names without organization dropping level with org names */
.author {
vertical-align: top;
}
/* Leave room in document info to show Internet-Draft on one line */
#identifiers dt {
width: 8em;
}
/* Don't waste quite as much whitespace between label and value in doc info */
#identifiers dd {
margin-left: 1em;
}
/* Give floating toc a background color (needed when it's a div inside section */
#toc {
background-color: white;
}
/* Make the collapsed ToC header render white on gray also when it's a link */
@media screen and (max-width: 1023px) {
#toc h2 a,
#toc h2 a:link,
#toc h2 a:focus,
#toc h2 a:hover,
#toc a.toplink,
#toc a.toplink:hover {
color: white;
background-color: #444;
text-decoration: none;
}
}
/* Give the bottom of the ToC some whitespace */
@media screen and (min-width: 1024px) {
#toc {
padding: 0 0 1em 1em;
}
}
/* Style section numbers with more space between number and title */
.section-number {
padding-right: 0.5em;
}
/* prevent monospace from becoming overly large */
tt, code, pre {
font-size: 95%;
}
/* Fix the height/width aspect for ascii art*/
.sourcecode pre,
.art-text pre {
line-height: 1.12;
}
/* Add styling for a link in the ToC that points to the top of the document */
a.toplink {
float: right;
margin-right: 0.5em;
}
/* Fix the dl styling to match the RFC 7992 attributes */
dl > dt,
dl.dlParallel > dt {
float: left;
margin-right: 1em;
}
dl.dlNewline > dt {
float: none;
}
/* Provide styling for table cell text alignment */
table td.text-left,
table th.text-left {
text-align: left;
}
table td.text-center,
table th.text-center {
text-align: center;
}
table td.text-right,
table th.text-right {
text-align: right;
}
/* Make the alternative author contact information look less like just another
author, and group it closer with the primary author contact information */
.alternative-contact {
margin: 0.5em 0 0.25em 0;
}
address .non-ascii {
margin: 0 0 0 2em;
}
/* With it being possible to set tables with alignment
left, center, and right, { width: 100%; } does not make sense */
table {
width: auto;
}
/* Avoid reference text that sits in a block with very wide left margin,
because of a long floating dt label.*/
.references dd {
overflow: visible;
}
/* Control caption placement */
caption {
caption-side: bottom;
}
/* Limit the width of the author address vcard, so names in right-to-left
script don't end up on the other side of the page. */
address.vcard {
max-width: 30em;
margin-right: auto;
}
/* For address alignment dependent on LTR or RTL scripts */
address div.left {
text-align: left;
}
address div.right {
text-align: right;
}
/* Provide table alignment support. We can't use the alignX classes above
since they do unwanted things with caption and other styling. */
table.right {
margin-left: auto;
margin-right: 0;
}
table.center {
margin-left: auto;
margin-right: auto;
}
table.left {
margin-left: 0;
margin-right: auto;
}
/* Give the table caption label the same styling as the figcaption */
caption a[href] {
color: #222;
}
@media print {
.toplink {
display: none;
}
/* avoid overwriting the top border line with the ToC header */
#toc {
padding-top: 1px;
}
/* Avoid page breaks inside dl and author address entries */
.vcard {
page-break-inside: avoid;
}
}
/* Tweak the bcp14 keyword presentation */
.bcp14 {
font-variant: small-caps;
font-weight: bold;
font-size: 0.9em;
}
/* Tweak the invisible space above H* in order not to overlay links in text above */
h2 {
margin-top: -18px; /* provide offset for in-page anchors */
padding-top: 31px;
}
h3 {
margin-top: -18px; /* provide offset for in-page anchors */
padding-top: 24px;
}
h4 {
margin-top: -18px; /* provide offset for in-page anchors */
padding-top: 24px;
}
/* Float artwork pilcrow to the right */
@media screen {
.artwork a.pilcrow {
display: block;
line-height: 0.7;
margin-top: 0.15em;
}
}
/* Make pilcrows on dd visible */
@media screen {
dd:hover > a.pilcrow {
visibility: visible;
}
}
/* Make the placement of figcaption match that of a table's caption
by removing the figure's added bottom margin */
.alignLeft.art-text,
.alignCenter.art-text,
.alignRight.art-text {
margin-bottom: 0;
}
.alignLeft,
.alignCenter,
.alignRight {
margin: 1em 0 0 0;
}
/* In print, the pilcrow won't show on hover, so prevent it from taking up space,
possibly even requiring a new line */
@media print {
a.pilcrow {
display: none;
}
}
/* Styling for the external metadata */
div#external-metadata {
background-color: #eee;
padding: 0.5em;
margin-bottom: 0.5em;
display: none;
}
div#internal-metadata {
padding: 0.5em; /* to match the external-metadata padding */
}
/* Styling for title RFC Number */
h1#rfcnum {
clear: both;
margin: 0 0 -1em;
padding: 1em 0 0 0;
}
/* Make .olPercent look the same as <ol><li> */
dl.olPercent > dd {
margin-bottom: 0.25em;
min-height: initial;
}
/* Give aside some styling to set it apart */
aside {
border-left: 1px solid #ddd;
margin: 1em 0 1em 2em;
padding: 0.2em 2em;
}
aside > dl,
aside > ol,
aside > ul,
aside > table,
aside > p {
margin-bottom: 0.5em;
}
/* Additional page break settings */
@media print {
figcaption, table caption {
page-break-before: avoid;
}
}
/* Font size adjustments for print */
@media print {
body { font-size: 10pt; line-height: normal; max-width: 96%; }
h1 { font-size: 1.72em; padding-top: 1.5em; } /* 1*1.2*1.2*1.2 */
h2 { font-size: 1.44em; padding-top: 1.5em; } /* 1*1.2*1.2 */
h3 { font-size: 1.2em; padding-top: 1.5em; } /* 1*1.2 */
h4 { font-size: 1em; padding-top: 1.5em; }
h5, h6 { font-size: 1em; margin: initial; padding: 0.5em 0 0.3em; }
}
/* Sourcecode margin in print, when there's no pilcrow */
@media print {
.artwork,
.artwork > pre,
.sourcecode {
margin-bottom: 1em;
}
}
/* Avoid narrow tables forcing too narrow table captions, which may render badly */
table {
min-width: 20em;
}
/* ol type a */
ol.type-a { list-style-type: lower-alpha; }
ol.type-A { list-style-type: upper-alpha; }
ol.type-i { list-style-type: lower-roman; }
ol.type-I { list-style-type: upper-roman; }
/* Apply the print table and row borders in general, on request from the RPC,
and increase the contrast between border and odd row background slightly */
table {
border: 1px solid #ddd;
}
td {
border-top: 1px solid #ddd;
}
tr {
break-inside: avoid;
}
tr:nth-child(2n+1) > td {
background-color: #f8f8f8;
}
/* Use style rules to govern display of the TOC. */
@media screen and (max-width: 1023px) {
#toc nav { display: none; }
#toc.active nav { display: block; }
}
/* Add support for keepWithNext */
.keepWithNext {
break-after: avoid-page;
break-after: avoid-page;
}
/* Add support for keepWithPrevious */
.keepWithPrevious {
break-before: avoid-page;
}
/* Change the approach to avoiding breaks inside artwork etc. */
figure, pre, table, .artwork, .sourcecode {
break-before: auto;
break-after: auto;
}
/* Avoid breaks between <dt> and <dd> */
dl {
break-before: auto;
break-inside: auto;
}
dt {
break-before: auto;
break-after: avoid-page;
}
dd {
break-before: avoid-page;
break-after: auto;
orphans: 3;
widows: 3
}
span.break, dd.break {
margin-bottom: 0;
min-height: 0;
break-before: auto;
break-inside: auto;
break-after: auto;
}
/* Undo break-before ToC */
@media print {
#toc {
break-before: auto;
}
}
/* Text in compact lists should not get extra bottom margin space,
since that would makes the list not compact */
ul.compact p, .ulCompact p,
ol.compact p, .olCompact p {
margin: 0;
}
/* But the list as a whole needs the extra space at the end */
section ul.compact,
section .ulCompact,
section ol.compact,
section .olCompact {
margin-bottom: 1em; /* same as p not within ul.compact etc. */
}
/* The tt and code background above interferes with for instance table cell
backgrounds. Changed to something a bit more selective. */
tt, code {
background-color: transparent;
}
p tt, p code, li tt, li code, dt tt, dt code {
background-color: #f8f8f8;
}
/* Tweak the pre margin -- 0px doesn't come out well */
pre {
margin-top: 0.5px;
}
/* Tweak the compact list text */
ul.compact, .ulCompact,
ol.compact, .olCompact,
dl.compact, .dlCompact {
line-height: normal;
}
/* Don't add top margin for nested lists */
li > ul, li > ol, li > dl,
dd > ul, dd > ol, dd > dl,
dl > dd > dl {
margin-top: initial;
}
/* Elements that should not be rendered on the same line as a <dt> */
/* This should match the element list in writer.text.TextWriter.render_dl() */
dd > div.artwork:first-child,
dd > aside:first-child,
dd > blockquote:first-child,
dd > figure:first-child,
dd > ol:first-child,
dd > div.sourcecode:first-child,
dd > table:first-child,
dd > ul:first-child {
clear: left;
}
/* fix for weird browser behaviour when <dd/> is empty */
dt+dd:empty::before{
content: "\00a0";
}
/* Make paragraph spacing inside <li> smaller than in body text, to fit better within the list */
li > p {
margin-bottom: 0.5em
}
/* Don't let p margin spill out from inside list items */
li > p:last-of-type:only-child {
margin-bottom: 0;
}
</style>
<link href="rfc-local.css" rel="stylesheet" type="text/css">
<link href="https://datatracker.ietf.org/doc/draft-irtf-cfrg-opaque-18" rel="prev">
<link href="https://dx.doi.org/10.17487/rfc9807" rel="alternate">
<link href="urn:issn:2070-1721" rel="alternate">
</head>
<body class="xml2rfc">
<script src="https://www.rfc-editor.org/js/metadata.min.js"></script>
<table class="ears">
<thead><tr>
<td class="left">RFC 9807</td>
<td class="center">OPAQUE</td>
<td class="right">July 2025</td>
</tr></thead>
<tfoot><tr>
<td class="left">Bourdrez, et al.</td>
<td class="center">Informational</td>
<td class="right">[Page]</td>
</tr></tfoot>
</table>
<div id="external-metadata" class="document-information"></div>
<div id="internal-metadata" class="document-information">
<dl id="identifiers">
<dt class="label-stream">Stream:</dt>
<dd class="stream">Internet Research Task Force (IRTF)</dd>
<dt class="label-rfc">RFC:</dt>
<dd class="rfc"><a href="https://www.rfc-editor.org/rfc/rfc9807" class="eref">9807</a></dd>
<dt class="label-category">Category:</dt>
<dd class="category">Informational</dd>
<dt class="label-published">Published:</dt>
<dd class="published">
<time datetime="2025-07" class="published">July 2025</time>
</dd>
<dt class="label-issn">ISSN:</dt>
<dd class="issn">2070-1721</dd>
<dt class="label-authors">Authors:</dt>
<dd class="authors">
<div class="author">
<div class="author-name">D. Bourdrez</div>
</div>
<div class="author">
<div class="author-name">H. Krawczyk</div>
<div class="org">AWS</div>
</div>
<div class="author">
<div class="author-name">K. Lewi</div>
<div class="org">Meta</div>
</div>
<div class="author">
<div class="author-name">C. A. Wood</div>
<div class="org">Cloudflare, Inc.</div>
</div>
</dd>
</dl>
</div>
<h1 id="rfcnum">RFC 9807</h1>
<h1 id="title">The OPAQUE Augmented Password-Authenticated Key Exchange (aPAKE) Protocol</h1>
<section id="section-abstract">
<h2 id="abstract"><a href="#abstract" class="selfRef">Abstract</a></h2>
<p id="section-abstract-1">This document describes the OPAQUE protocol, an Augmented (or Asymmetric)
Password-Authenticated Key Exchange (aPAKE) protocol that supports mutual
authentication in a client-server setting without reliance on PKI and
with security against pre-computation attacks upon server compromise.
In addition, the protocol provides forward secrecy and the ability to
hide the password from the server, even during password registration.
This document specifies the core OPAQUE protocol and one instantiation
based on 3DH. This document is a product of the Crypto Forum Research
Group (CFRG) in the IRTF.<a href="#section-abstract-1" class="pilcrow"></a></p>
</section>
<div id="status-of-memo">
<section id="section-boilerplate.1">
<h2 id="name-status-of-this-memo">
<a href="#name-status-of-this-memo" class="section-name selfRef">Status of This Memo</a>
</h2>
<p id="section-boilerplate.1-1">
This document is not an Internet Standards Track specification; it is
published for informational purposes.<a href="#section-boilerplate.1-1" class="pilcrow"></a></p>
<p id="section-boilerplate.1-2">
This document is a product of the Internet Research Task Force
(IRTF). The IRTF publishes the results of Internet-related
research and development activities. These results might not be
suitable for deployment. This RFC represents the consensus of the Crypto Forum
Research Group of the Internet Research Task Force (IRTF).
Documents approved for publication by the IRSG are not
candidates for any level of Internet Standard; see Section 2 of RFC
7841.<a href="#section-boilerplate.1-2" class="pilcrow"></a></p>
<p id="section-boilerplate.1-3">
Information about the current status of this document, any
errata, and how to provide feedback on it may be obtained at
<span><a href="https://www.rfc-editor.org/info/rfc9807">https://www.rfc-editor.org/info/rfc9807</a></span>.<a href="#section-boilerplate.1-3" class="pilcrow"></a></p>
</section>
</div>
<div id="copyright">
<section id="section-boilerplate.2">
<h2 id="name-copyright-notice">
<a href="#name-copyright-notice" class="section-name selfRef">Copyright Notice</a>
</h2>
<p id="section-boilerplate.2-1">
Copyright (c) 2025 IETF Trust and the persons identified as the
document authors. All rights reserved.<a href="#section-boilerplate.2-1" class="pilcrow"></a></p>
<p id="section-boilerplate.2-2">
This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents
(<span><a href="https://trustee.ietf.org/license-info">https://trustee.ietf.org/license-info</a></span>) in effect on the date of
publication of this document. Please review these documents
carefully, as they describe your rights and restrictions with
respect to this document.<a href="#section-boilerplate.2-2" class="pilcrow"></a></p>
</section>
</div>
<div id="toc">
<section id="section-toc.1">
<a href="#" onclick="scroll(0,0)" class="toplink"></a><h2 id="name-table-of-contents">
<a href="#name-table-of-contents" class="section-name selfRef">Table of Contents</a>
</h2>
<nav class="toc"><ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.1">
<p id="section-toc.1-1.1.1" class="keepWithNext"><a href="#section-1" class="auto internal xref">1</a>.  <a href="#name-introduction" class="internal xref">Introduction</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.1.2.1">
<p id="section-toc.1-1.1.2.1.1" class="keepWithNext"><a href="#section-1.1" class="auto internal xref">1.1</a>.  <a href="#name-requirements-notation" class="internal xref">Requirements Notation</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.1.2.2">
<p id="section-toc.1-1.1.2.2.1" class="keepWithNext"><a href="#section-1.2" class="auto internal xref">1.2</a>.  <a href="#name-notation" class="internal xref">Notation</a></p>
</li>
</ul>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.2">
<p id="section-toc.1-1.2.1"><a href="#section-2" class="auto internal xref">2</a>.  <a href="#name-cryptographic-dependencies" class="internal xref">Cryptographic Dependencies</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.2.2.1">
<p id="section-toc.1-1.2.2.1.1"><a href="#section-2.1" class="auto internal xref">2.1</a>.  <a href="#name-oblivious-pseudorandom-func" class="internal xref">Oblivious Pseudorandom Function</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.2.2.2">
<p id="section-toc.1-1.2.2.2.1"><a href="#section-2.2" class="auto internal xref">2.2</a>.  <a href="#name-key-derivation-function-and" class="internal xref">Key Derivation Function and Message Authentication Code</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.2.2.3">
<p id="section-toc.1-1.2.2.3.1"><a href="#section-2.3" class="auto internal xref">2.3</a>.  <a href="#name-hash-functions" class="internal xref">Hash Functions</a></p>
</li>
</ul>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.3">
<p id="section-toc.1-1.3.1"><a href="#section-3" class="auto internal xref">3</a>.  <a href="#name-protocol-overview" class="internal xref">Protocol Overview</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.3.2.1">
<p id="section-toc.1-1.3.2.1.1"><a href="#section-3.1" class="auto internal xref">3.1</a>.  <a href="#name-setup" class="internal xref">Setup</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.3.2.2">
<p id="section-toc.1-1.3.2.2.1"><a href="#section-3.2" class="auto internal xref">3.2</a>.  <a href="#name-registration" class="internal xref">Registration</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.3.2.3">
<p id="section-toc.1-1.3.2.3.1"><a href="#section-3.3" class="auto internal xref">3.3</a>.  <a href="#name-online-authenticated-key-ex" class="internal xref">Online Authenticated Key Exchange</a></p>
</li>
</ul>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.4">
<p id="section-toc.1-1.4.1"><a href="#section-4" class="auto internal xref">4</a>.  <a href="#name-client-credential-storage-a" class="internal xref">Client Credential Storage and Key Recovery</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.4.2.1">
<p id="section-toc.1-1.4.2.1.1"><a href="#section-4.1" class="auto internal xref">4.1</a>.  <a href="#name-key-recovery" class="internal xref">Key Recovery</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.4.2.1.2.1">
<p id="section-toc.1-1.4.2.1.2.1.1"><a href="#section-4.1.1" class="auto internal xref">4.1.1</a>.  <a href="#name-envelope-structure" class="internal xref">Envelope Structure</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.4.2.1.2.2">
<p id="section-toc.1-1.4.2.1.2.2.1"><a href="#section-4.1.2" class="auto internal xref">4.1.2</a>.  <a href="#name-envelope-creation" class="internal xref">Envelope Creation</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.4.2.1.2.3">
<p id="section-toc.1-1.4.2.1.2.3.1"><a href="#section-4.1.3" class="auto internal xref">4.1.3</a>.  <a href="#name-envelope-recovery" class="internal xref">Envelope Recovery</a></p>
</li>
</ul>
</li>
</ul>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.5">
<p id="section-toc.1-1.5.1"><a href="#section-5" class="auto internal xref">5</a>.  <a href="#name-registration-2" class="internal xref">Registration</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.5.2.1">
<p id="section-toc.1-1.5.2.1.1"><a href="#section-5.1" class="auto internal xref">5.1</a>.  <a href="#name-registration-messages" class="internal xref">Registration Messages</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.5.2.2">
<p id="section-toc.1-1.5.2.2.1"><a href="#section-5.2" class="auto internal xref">5.2</a>.  <a href="#name-registration-functions" class="internal xref">Registration Functions</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.5.2.2.2.1">
<p id="section-toc.1-1.5.2.2.2.1.1"><a href="#section-5.2.1" class="auto internal xref">5.2.1</a>.  <a href="#name-createregistrationrequest" class="internal xref">CreateRegistrationRequest</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.5.2.2.2.2">
<p id="section-toc.1-1.5.2.2.2.2.1"><a href="#section-5.2.2" class="auto internal xref">5.2.2</a>.  <a href="#name-createregistrationresponse" class="internal xref">CreateRegistrationResponse</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.5.2.2.2.3">
<p id="section-toc.1-1.5.2.2.2.3.1"><a href="#section-5.2.3" class="auto internal xref">5.2.3</a>.  <a href="#name-finalizeregistrationrequest" class="internal xref">FinalizeRegistrationRequest</a></p>
</li>
</ul>
</li>
</ul>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.6">
<p id="section-toc.1-1.6.1"><a href="#section-6" class="auto internal xref">6</a>.  <a href="#name-online-authenticated-key-exc" class="internal xref">Online Authenticated Key Exchange</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.6.2.1">
<p id="section-toc.1-1.6.2.1.1"><a href="#section-6.1" class="auto internal xref">6.1</a>.  <a href="#name-ake-messages" class="internal xref">AKE Messages</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.6.2.2">
<p id="section-toc.1-1.6.2.2.1"><a href="#section-6.2" class="auto internal xref">6.2</a>.  <a href="#name-ake-functions" class="internal xref">AKE Functions</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.6.2.2.2.1">
<p id="section-toc.1-1.6.2.2.2.1.1"><a href="#section-6.2.1" class="auto internal xref">6.2.1</a>.  <a href="#name-generateke1" class="internal xref">GenerateKE1</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.6.2.2.2.2">
<p id="section-toc.1-1.6.2.2.2.2.1"><a href="#section-6.2.2" class="auto internal xref">6.2.2</a>.  <a href="#name-generateke2" class="internal xref">GenerateKE2</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.6.2.2.2.3">
<p id="section-toc.1-1.6.2.2.2.3.1"><a href="#section-6.2.3" class="auto internal xref">6.2.3</a>.  <a href="#name-generateke3" class="internal xref">GenerateKE3</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.6.2.2.2.4">
<p id="section-toc.1-1.6.2.2.2.4.1"><a href="#section-6.2.4" class="auto internal xref">6.2.4</a>.  <a href="#name-serverfinish" class="internal xref">ServerFinish</a></p>
</li>
</ul>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.6.2.3">
<p id="section-toc.1-1.6.2.3.1"><a href="#section-6.3" class="auto internal xref">6.3</a>.  <a href="#name-credential-retrieval" class="internal xref">Credential Retrieval</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.6.2.3.2.1">
<p id="section-toc.1-1.6.2.3.2.1.1"><a href="#section-6.3.1" class="auto internal xref">6.3.1</a>.  <a href="#name-credential-retrieval-messag" class="internal xref">Credential Retrieval Messages</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.6.2.3.2.2">
<p id="section-toc.1-1.6.2.3.2.2.1"><a href="#section-6.3.2" class="auto internal xref">6.3.2</a>.  <a href="#name-credential-retrieval-functi" class="internal xref">Credential Retrieval Functions</a></p>
</li>
</ul>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.6.2.4">
<p id="section-toc.1-1.6.2.4.1"><a href="#section-6.4" class="auto internal xref">6.4</a>.  <a href="#name-3dh-protocol" class="internal xref">3DH Protocol</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.6.2.4.2.1">
<p id="section-toc.1-1.6.2.4.2.1.1"><a href="#section-6.4.1" class="auto internal xref">6.4.1</a>.  <a href="#name-3dh-key-exchange-functions" class="internal xref">3DH Key Exchange Functions</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.6.2.4.2.2">
<p id="section-toc.1-1.6.2.4.2.2.1"><a href="#section-6.4.2" class="auto internal xref">6.4.2</a>.  <a href="#name-key-schedule-functions" class="internal xref">Key Schedule Functions</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.6.2.4.2.3">
<p id="section-toc.1-1.6.2.4.2.3.1"><a href="#section-6.4.3" class="auto internal xref">6.4.3</a>.  <a href="#name-3dh-client-functions" class="internal xref">3DH Client Functions</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.6.2.4.2.4">
<p id="section-toc.1-1.6.2.4.2.4.1"><a href="#section-6.4.4" class="auto internal xref">6.4.4</a>.  <a href="#name-3dh-server-functions" class="internal xref">3DH Server Functions</a></p>
</li>
</ul>
</li>
</ul>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.7">
<p id="section-toc.1-1.7.1"><a href="#section-7" class="auto internal xref">7</a>.  <a href="#name-configurations" class="internal xref">Configurations</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.8">
<p id="section-toc.1-1.8.1"><a href="#section-8" class="auto internal xref">8</a>.  <a href="#name-application-considerations" class="internal xref">Application Considerations</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.9">
<p id="section-toc.1-1.9.1"><a href="#section-9" class="auto internal xref">9</a>.  <a href="#name-implementation-consideratio" class="internal xref">Implementation Considerations</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.9.2.1">
<p id="section-toc.1-1.9.2.1.1"><a href="#section-9.1" class="auto internal xref">9.1</a>.  <a href="#name-implementation-safeguards" class="internal xref">Implementation Safeguards</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.9.2.2">
<p id="section-toc.1-1.9.2.2.1"><a href="#section-9.2" class="auto internal xref">9.2</a>.  <a href="#name-handling-online-guessing-at" class="internal xref">Handling Online Guessing Attacks</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.9.2.3">
<p id="section-toc.1-1.9.2.3.1"><a href="#section-9.3" class="auto internal xref">9.3</a>.  <a href="#name-error-considerations" class="internal xref">Error Considerations</a></p>
</li>
</ul>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.10">
<p id="section-toc.1-1.10.1"><a href="#section-10" class="auto internal xref">10</a>. <a href="#name-security-considerations" class="internal xref">Security Considerations</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.10.2.1">
<p id="section-toc.1-1.10.2.1.1"><a href="#section-10.1" class="auto internal xref">10.1</a>.  <a href="#name-notable-design-differences" class="internal xref">Notable Design Differences</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.10.2.2">
<p id="section-toc.1-1.10.2.2.1"><a href="#section-10.2" class="auto internal xref">10.2</a>.  <a href="#name-security-analysis" class="internal xref">Security Analysis</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.10.2.3">
<p id="section-toc.1-1.10.2.3.1"><a href="#section-10.3" class="auto internal xref">10.3</a>.  <a href="#name-identities" class="internal xref">Identities</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.10.2.4">
<p id="section-toc.1-1.10.2.4.1"><a href="#section-10.4" class="auto internal xref">10.4</a>.  <a href="#name-export-key-usage" class="internal xref">Export Key Usage</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.10.2.5">
<p id="section-toc.1-1.10.2.5.1"><a href="#section-10.5" class="auto internal xref">10.5</a>.  <a href="#name-static-diffie-hellman-oracl" class="internal xref">Static Diffie-Hellman Oracles</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.10.2.6">
<p id="section-toc.1-1.10.2.6.1"><a href="#section-10.6" class="auto internal xref">10.6</a>.  <a href="#name-random-key-robust-macs" class="internal xref">Random-Key Robust MACs</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.10.2.7">
<p id="section-toc.1-1.10.2.7.1"><a href="#section-10.7" class="auto internal xref">10.7</a>.  <a href="#name-input-validation" class="internal xref">Input Validation</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.10.2.8">
<p id="section-toc.1-1.10.2.8.1"><a href="#section-10.8" class="auto internal xref">10.8</a>.  <a href="#name-oprf-key-stretching" class="internal xref">OPRF Key Stretching</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.10.2.9">
<p id="section-toc.1-1.10.2.9.1"><a href="#section-10.9" class="auto internal xref">10.9</a>.  <a href="#name-client-enumeration" class="internal xref">Client Enumeration</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.10.2.10">
<p id="section-toc.1-1.10.2.10.1"><a href="#section-10.10" class="auto internal xref">10.10</a>. <a href="#name-protecting-the-registration" class="internal xref">Protecting the Registration Masking Key</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.10.2.11">
<p id="section-toc.1-1.10.2.11.1"><a href="#section-10.11" class="auto internal xref">10.11</a>. <a href="#name-password-salt-and-storage-i" class="internal xref">Password Salt and Storage Implications</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.10.2.12">
<p id="section-toc.1-1.10.2.12.1"><a href="#section-10.12" class="auto internal xref">10.12</a>. <a href="#name-ake-private-key-storage" class="internal xref">AKE Private Key Storage</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.10.2.13">
<p id="section-toc.1-1.10.2.13.1"><a href="#section-10.13" class="auto internal xref">10.13</a>. <a href="#name-client-authentication-using" class="internal xref">Client Authentication Using Credentials</a></p>
</li>
</ul>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.11">
<p id="section-toc.1-1.11.1"><a href="#section-11" class="auto internal xref">11</a>. <a href="#name-iana-considerations" class="internal xref">IANA Considerations</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.12">
<p id="section-toc.1-1.12.1"><a href="#section-12" class="auto internal xref">12</a>. <a href="#name-references" class="internal xref">References</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.12.2.1">
<p id="section-toc.1-1.12.2.1.1"><a href="#section-12.1" class="auto internal xref">12.1</a>.  <a href="#name-normative-references" class="internal xref">Normative References</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.12.2.2">
<p id="section-toc.1-1.12.2.2.1"><a href="#section-12.2" class="auto internal xref">12.2</a>.  <a href="#name-informative-references" class="internal xref">Informative References</a></p>
</li>
</ul>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.13">
<p id="section-toc.1-1.13.1"><a href="#appendix-A" class="auto internal xref">Appendix A</a>.  <a href="#name-alternate-key-recovery-mech" class="internal xref">Alternate Key Recovery Mechanisms</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.14">
<p id="section-toc.1-1.14.1"><a href="#appendix-B" class="auto internal xref">Appendix B</a>.  <a href="#name-alternate-ake-instantiation" class="internal xref">Alternate AKE Instantiations</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.14.2.1">
<p id="section-toc.1-1.14.2.1.1"><a href="#appendix-B.1" class="auto internal xref">B.1</a>.  <a href="#name-hmqv-instantiation-sketch" class="internal xref">HMQV Instantiation Sketch</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.14.2.2">
<p id="section-toc.1-1.14.2.2.1"><a href="#appendix-B.2" class="auto internal xref">B.2</a>.  <a href="#name-sigma-i-instantiation-sketc" class="internal xref">SIGMA-I Instantiation Sketch</a></p>
</li>
</ul>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.15">
<p id="section-toc.1-1.15.1"><a href="#appendix-C" class="auto internal xref">Appendix C</a>.  <a href="#name-test-vectors" class="internal xref">Test Vectors</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.15.2.1">
<p id="section-toc.1-1.15.2.1.1"><a href="#appendix-C.1" class="auto internal xref">C.1</a>.  <a href="#name-real-test-vectors" class="internal xref">Real Test Vectors</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.15.2.1.2.1">
<p id="section-toc.1-1.15.2.1.2.1.1"><a href="#appendix-C.1.1" class="auto internal xref">C.1.1</a>.  <a href="#name-opaque-3dh-real-test-vector" class="internal xref">OPAQUE-3DH Real Test Vector 1</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.15.2.1.2.2">
<p id="section-toc.1-1.15.2.1.2.2.1"><a href="#appendix-C.1.2" class="auto internal xref">C.1.2</a>.  <a href="#name-opaque-3dh-real-test-vector-" class="internal xref">OPAQUE-3DH Real Test Vector 2</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.15.2.1.2.3">
<p id="section-toc.1-1.15.2.1.2.3.1"><a href="#appendix-C.1.3" class="auto internal xref">C.1.3</a>.  <a href="#name-opaque-3dh-real-test-vector-3" class="internal xref">OPAQUE-3DH Real Test Vector 3</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.15.2.1.2.4">
<p id="section-toc.1-1.15.2.1.2.4.1"><a href="#appendix-C.1.4" class="auto internal xref">C.1.4</a>.  <a href="#name-opaque-3dh-real-test-vector-4" class="internal xref">OPAQUE-3DH Real Test Vector 4</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.15.2.1.2.5">
<p id="section-toc.1-1.15.2.1.2.5.1"><a href="#appendix-C.1.5" class="auto internal xref">C.1.5</a>.  <a href="#name-opaque-3dh-real-test-vector-5" class="internal xref">OPAQUE-3DH Real Test Vector 5</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.15.2.1.2.6">
<p id="section-toc.1-1.15.2.1.2.6.1"><a href="#appendix-C.1.6" class="auto internal xref">C.1.6</a>.  <a href="#name-opaque-3dh-real-test-vector-6" class="internal xref">OPAQUE-3DH Real Test Vector 6</a></p>
</li>
</ul>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.15.2.2">
<p id="section-toc.1-1.15.2.2.1"><a href="#appendix-C.2" class="auto internal xref">C.2</a>.  <a href="#name-fake-test-vectors" class="internal xref">Fake Test Vectors</a></p>
<ul class="compact toc ulBare ulEmpty">
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.15.2.2.2.1">
<p id="section-toc.1-1.15.2.2.2.1.1"><a href="#appendix-C.2.1" class="auto internal xref">C.2.1</a>.  <a href="#name-opaque-3dh-fake-test-vector" class="internal xref">OPAQUE-3DH Fake Test Vector 1</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.15.2.2.2.2">
<p id="section-toc.1-1.15.2.2.2.2.1"><a href="#appendix-C.2.2" class="auto internal xref">C.2.2</a>.  <a href="#name-opaque-3dh-fake-test-vector-" class="internal xref">OPAQUE-3DH Fake Test Vector 2</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.15.2.2.2.3">
<p id="section-toc.1-1.15.2.2.2.3.1"><a href="#appendix-C.2.3" class="auto internal xref">C.2.3</a>.  <a href="#name-opaque-3dh-fake-test-vector-3" class="internal xref">OPAQUE-3DH Fake Test Vector 3</a></p>
</li>
</ul>
</li>
</ul>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.16">
<p id="section-toc.1-1.16.1"><a href="#appendix-D" class="auto internal xref"></a><a href="#name-acknowledgments" class="internal xref">Acknowledgments</a></p>
</li>
<li class="compact toc ulBare ulEmpty" id="section-toc.1-1.17">
<p id="section-toc.1-1.17.1"><a href="#appendix-E" class="auto internal xref"></a><a href="#name-authors-addresses" class="internal xref">Authors' Addresses</a></p>
</li>
</ul>
</nav>
</section>
</div>
<div id="intro">
<section id="section-1">
<h2 id="name-introduction">
<a href="#section-1" class="section-number selfRef">1. </a><a href="#name-introduction" class="section-name selfRef">Introduction</a>
</h2>
<p id="section-1-1">Password authentication is ubiquitous in many applications. In a common
implementation, a client authenticates to a server by sending its client
ID and password to the server over a secure connection. This makes
the password vulnerable to server mishandling, including accidentally
logging the password or storing it in plaintext in a database. Server
compromise resulting in access to these plaintext passwords is not an
uncommon security incident, even among security-conscious organizations. Moreover, plaintext password authentication over secure channels such as
TLS is also vulnerable in cases where TLS may fail, including PKI
attacks, certificate mishandling, termination outside the security
perimeter, visibility to TLS-terminating intermediaries, and more.<a href="#section-1-1" class="pilcrow"></a></p>
<p id="section-1-2">Augmented (or Asymmetric) Password Authenticated Key Exchange (aPAKE)
protocols are designed to provide password authentication and
mutually authenticated key exchange in a client-server setting without
relying on PKI (except during client registration) and without
disclosing passwords to servers or other entities other than the client
machine. A secure aPAKE should provide the best possible security for a
password protocol. Indeed, some attacks are inevitable, such as
online impersonation attempts with guessed client passwords and offline
dictionary attacks upon the compromise of a server and leakage of its
credential file. In the latter case, the attacker learns a mapping of
a client's password under a one-way function and uses such a mapping to
validate potential guesses for the password. It is crucially important for the password protocol to use an unpredictable one-way mapping.
Otherwise, the attacker can pre-compute a deterministic list of mapped
passwords leading to almost instantaneous leakage of passwords upon
server compromise.<a href="#section-1-2" class="pilcrow"></a></p>
<p id="section-1-3">This document describes OPAQUE, an aPAKE protocol that is secure against
pre-computation attacks (as defined in <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span>). OPAQUE provides forward
secrecy with respect to password leakage while also hiding the password from
the server, even during password registration. OPAQUE allows applications
to increase the difficulty of offline dictionary attacks via iterated
hashing or other key-stretching schemes. OPAQUE is also extensible, allowing
clients to safely store and retrieve arbitrary application data on servers
using only their password.<a href="#section-1-3" class="pilcrow"></a></p>
<p id="section-1-4">OPAQUE is defined and proven as the composition of three functionalities:
an Oblivious Pseudorandom Function (OPRF), a key recovery mechanism,
and an authenticated key exchange (AKE) protocol. It can be seen
as a "compiler" for transforming any suitable AKE protocol into a secure
aPAKE protocol. (See <a href="#security-considerations" class="auto internal xref">Section 10</a> for requirements of the
OPRF and AKE protocols.) This document specifies one OPAQUE instantiation
based on <span>[<a href="#TripleDH" class="cite xref">TripleDH</a>]</span>. Other instantiations are possible, as discussed in
<a href="#alternate-akes" class="auto internal xref">Appendix B</a>, but their details are out of scope for this document.
In general, the modularity of OPAQUE's design makes it easy to integrate with
additional AKE protocols, e.g., TLS or HMQV (Hashed Menezes-Qu-Vanstone), and
with future AKE protocols such as those based on post-quantum techniques.<a href="#section-1-4" class="pilcrow"></a></p>
<p id="section-1-5">OPAQUE consists of two stages: registration and authenticated key exchange.
In the first stage, a client registers its password with the server and stores
information used to recover authentication credentials on the server. Recovering these
credentials can only be done with knowledge of the client password. In the second
stage, a client uses its password to recover those credentials and subsequently
uses them as input to an AKE protocol. This stage has additional mechanisms to
prevent an active attacker from interacting with the server to guess or confirm
clients registered via the first phase. Servers can use this mechanism to safeguard
registered clients against this type of enumeration attack; see
<a href="#preventing-client-enumeration" class="auto internal xref">Section 10.9</a> for more discussion.<a href="#section-1-5" class="pilcrow"></a></p>
<p id="section-1-6">The name "OPAQUE" is a homonym of O-PAKE, where O is for Oblivious. The name
"OPAKE" was taken.<a href="#section-1-6" class="pilcrow"></a></p>
<p id="section-1-7">This document complies with the requirements for PAKE protocols set forth in
<span>[<a href="#RFC8125" class="cite xref">RFC8125</a>]</span>. This document represents the consensus of the Crypto Forum
Research Group (CFRG). It is not an IETF product and is not a standard.<a href="#section-1-7" class="pilcrow"></a></p>
<div id="requirements-notation">
<section id="section-1.1">
<h3 id="name-requirements-notation">
<a href="#section-1.1" class="section-number selfRef">1.1. </a><a href="#name-requirements-notation" class="section-name selfRef">Requirements Notation</a>
</h3>
<p id="section-1.1-1">
The key words "<span class="bcp14">MUST</span>", "<span class="bcp14">MUST NOT</span>", "<span class="bcp14">REQUIRED</span>", "<span class="bcp14">SHALL</span>", "<span class="bcp14">SHALL NOT</span>", "<span class="bcp14">SHOULD</span>", "<span class="bcp14">SHOULD NOT</span>", "<span class="bcp14">RECOMMENDED</span>", "<span class="bcp14">NOT RECOMMENDED</span>",
"<span class="bcp14">MAY</span>", and "<span class="bcp14">OPTIONAL</span>" in this document are to be interpreted as
described in BCP 14 <span>[<a href="#RFC2119" class="cite xref">RFC2119</a>]</span> <span>[<a href="#RFC8174" class="cite xref">RFC8174</a>]</span>
when, and only when, they appear in all capitals, as shown here.<a href="#section-1.1-1" class="pilcrow"></a></p>
</section>
</div>
<div id="notation">
<section id="section-1.2">
<h3 id="name-notation">
<a href="#section-1.2" class="section-number selfRef">1.2. </a><a href="#name-notation" class="section-name selfRef">Notation</a>
</h3>
<p id="section-1.2-1">The following functions are used throughout this document:<a href="#section-1.2-1" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-1.2-2">
<dt id="section-1.2-2.1">I2OSP and OS2IP:</dt>
<dd style="margin-left: 1.5em" id="section-1.2-2.2">Convert a byte string to and from a non-negative
integer as described in <span><a href="https://rfc-editor.org/rfc/rfc8017#section-4" class="relref">Section 4</a> of [<a href="#RFC8017" class="cite xref">RFC8017</a>]</span>. Note
that these functions operate on byte strings in big-endian byte
order.<a href="#section-1.2-2.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-1.2-2.3">concat(x0, ..., xN):</dt>
<dd style="margin-left: 1.5em" id="section-1.2-2.4">Concatenate byte strings. For example,
<code>concat(0x01, 0x0203, 0x040506) = 0x010203040506</code>.<a href="#section-1.2-2.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-1.2-2.5">random(n):</dt>
<dd style="margin-left: 1.5em" id="section-1.2-2.6">Generates a cryptographically secure
pseudorandom byte string of length <code>n</code> bytes.<a href="#section-1.2-2.6" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-1.2-2.7">zeroes(n):</dt>
<dd style="margin-left: 1.5em" id="section-1.2-2.8">Generate a string of <code>n</code> bytes all
equal to 0 (zero).<a href="#section-1.2-2.8" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-1.2-2.9">xor(a,b):</dt>
<dd style="margin-left: 1.5em" id="section-1.2-2.10">Apply XOR to byte strings. For example, <code>xor(0xF0F0,
0x1234) = 0xE2C4</code>. It is an error to call this function with
arguments of unequal length.<a href="#section-1.2-2.10" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-1.2-2.11">ct_equal(a, b):</dt>
<dd style="margin-left: 1.5em" id="section-1.2-2.12">Return <code>true</code> if <code>a</code> is equal to
<code>b</code>, and false otherwise. The implementation of this
function must be constant-time in the length of <code>a</code> and
<code>b</code>, which are assumed to be of equal length, irrespective of
the values <code>a</code> or <code>b</code>.<a href="#section-1.2-2.12" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<p id="section-1.2-3">Except if said otherwise, random choices in this specification refer to
drawing with uniform distribution from a given set (i.e., "random" is short
for "uniformly random"). Random choices can be replaced with fresh outputs from
a cryptographically strong pseudorandom generator, according to the requirements
in <span>[<a href="#RFC4086" class="cite xref">RFC4086</a>]</span>, or a pseudorandom function. For convenience, we define <code>nil</code> as a
lack of value.<a href="#section-1.2-3" class="pilcrow"></a></p>
<p id="section-1.2-4">All protocol messages and structures defined in this document use the syntax from
<span><a href="https://rfc-editor.org/rfc/rfc8446#section-3" class="relref">Section 3</a> of [<a href="#RFC8446" class="cite xref">RFC8446</a>]</span>.<a href="#section-1.2-4" class="pilcrow"></a></p>
</section>
</div>
</section>
</div>
<div id="dependencies">
<section id="section-2">
<h2 id="name-cryptographic-dependencies">
<a href="#section-2" class="section-number selfRef">2. </a><a href="#name-cryptographic-dependencies" class="section-name selfRef">Cryptographic Dependencies</a>
</h2>
<p id="section-2-1">OPAQUE depends on the following cryptographic protocols and primitives:<a href="#section-2-1" class="pilcrow"></a></p>
<ul class="normal">
<li class="normal" id="section-2-2.1">
<p id="section-2-2.1.1">Oblivious Pseudorandom Function (OPRF); <a href="#deps-oprf" class="auto internal xref">Section 2.1</a><a href="#section-2-2.1.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-2-2.2">
<p id="section-2-2.2.1">Key Derivation Function (KDF); <a href="#deps-symmetric" class="auto internal xref">Section 2.2</a><a href="#section-2-2.2.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-2-2.3">
<p id="section-2-2.3.1">Message Authentication Code (MAC); <a href="#deps-symmetric" class="auto internal xref">Section 2.2</a><a href="#section-2-2.3.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-2-2.4">
<p id="section-2-2.4.1">Cryptographic Hash Function; <a href="#deps-hash" class="auto internal xref">Section 2.3</a><a href="#section-2-2.4.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-2-2.5">
<p id="section-2-2.5.1">Key Stretching Function (KSF); <a href="#deps-hash" class="auto internal xref">Section 2.3</a><a href="#section-2-2.5.1" class="pilcrow"></a></p>
</li>
</ul>
<p id="section-2-3">This section describes these protocols and primitives in more detail. Unless said
otherwise, all random nonces and <code>seeds</code> used in these dependencies and the rest of
the OPAQUE protocol are of length <code>Nn</code> and <code>Nseed</code> bytes, respectively, where
<code>Nn</code> = <code>Nseed</code> = 32.<a href="#section-2-3" class="pilcrow"></a></p>
<div id="deps-oprf">
<section id="section-2.1">
<h3 id="name-oblivious-pseudorandom-func">
<a href="#section-2.1" class="section-number selfRef">2.1. </a><a href="#name-oblivious-pseudorandom-func" class="section-name selfRef">Oblivious Pseudorandom Function</a>
</h3>
<p id="section-2.1-1">An Oblivious Pseudorandom Function (OPRF) is a two-party protocol between
client and server for computing a Pseudorandom Function (PRF), where the PRF key is held by the server
and the input to the function is provided by the client. The client does not
learn anything about the PRF other than the obtained output, and the server
learns nothing about the client's input or the function output.
This specification depends on the prime-order OPRF construction specified
as <code>modeOPRF</code> (<code>0x00</code>) from <span><a href="https://rfc-editor.org/rfc/rfc9497#section-3.1" class="relref">Section 3.1</a> of [<a href="#RFC9497" class="cite xref">RFC9497</a>]</span>.<a href="#section-2.1-1" class="pilcrow"></a></p>
<p id="section-2.1-2">The following OPRF client APIs are used:<a href="#section-2.1-2" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-2.1-3">
<dt id="section-2.1-3.1">Blind(element):</dt>
<dd style="margin-left: 1.5em" id="section-2.1-3.2">Create and output (<code>blind</code>,
<code>blinded_element</code>), consisting of a blinded representation of
input <code>element</code>, denoted <code>blinded_element</code>, along with
a value to revert the blinding process, denoted <code>blind</code>. This
is equivalent to the Blind function described in
<span><a href="https://rfc-editor.org/rfc/rfc9497#section-3.3.1" class="relref">Section 3.3.1</a> of [<a href="#RFC9497" class="cite xref">RFC9497</a>]</span>.<a href="#section-2.1-3.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-2.1-3.3">Finalize(element, blind, evaluated_element):</dt>
<dd style="margin-left: 1.5em" id="section-2.1-3.4">Finalize the OPRF
evaluation using input <code>element</code>, random inverter
<code>blind</code>, and evaluation output <code>evaluated_element</code>,
yielding output <code>oprf_output</code>. This is equivalent to the
Finalize function described in <span><a href="https://rfc-editor.org/rfc/rfc9497#section-3.3.1" class="relref">Section 3.3.1</a> of [<a href="#RFC9497" class="cite xref">RFC9497</a>]</span>.<a href="#section-2.1-3.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<p id="section-2.1-4">Moreover, the following OPRF server APIs are used:<a href="#section-2.1-4" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-2.1-5">
<dt id="section-2.1-5.1">BlindEvaluate(k, blinded_element):</dt>
<dd style="margin-left: 1.5em" id="section-2.1-5.2">Evaluate blinded input
<code>blinded_element</code> using input key <code>k</code>, yielding output
element <code>evaluated_element</code>. This is equivalent to the
BlindEvaluate function described in <span><a href="https://rfc-editor.org/rfc/rfc9497#section-3.3.1" class="relref">Section 3.3.1</a> of [<a href="#RFC9497" class="cite xref">RFC9497</a>]</span>, where <code>k</code> is the private key
parameter.<a href="#section-2.1-5.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-2.1-5.3">DeriveKeyPair(seed, info):</dt>
<dd style="margin-left: 1.5em" id="section-2.1-5.4">Create and output (<code>sk</code>,
<code>pk</code>), consisting of a private and public key derived
deterministically from an input <code>seed</code> and input
<code>info</code> parameter, as described in <span><a href="https://rfc-editor.org/rfc/rfc9497#section-3.2" class="relref">Section 3.2</a> of [<a href="#RFC9497" class="cite xref">RFC9497</a>]</span>.<a href="#section-2.1-5.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<p id="section-2.1-6">Finally, this specification makes use of the following shared APIs and parameters:<a href="#section-2.1-6" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-2.1-7">
<dt id="section-2.1-7.1">SerializeElement(element):</dt>
<dd style="margin-left: 1.5em" id="section-2.1-7.2">Map input <code>element</code> to a fixed-length byte array.<a href="#section-2.1-7.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-2.1-7.3">DeserializeElement(buf):</dt>
<dd style="margin-left: 1.5em" id="section-2.1-7.4">Attempt to map input byte array
<code>buf</code> to an OPRF group element. This function can raise a
DeserializeError upon failure; see <span><a href="https://rfc-editor.org/rfc/rfc9497#section-2.1" class="relref">Section 2.1</a> of [<a href="#RFC9497" class="cite xref">RFC9497</a>]</span> for more details.<a href="#section-2.1-7.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-2.1-7.5">Noe:</dt>
<dd style="margin-left: 1.5em" id="section-2.1-7.6">The size of a serialized OPRF group element output from SerializeElement.<a href="#section-2.1-7.6" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-2.1-7.7">Nok:</dt>
<dd style="margin-left: 1.5em" id="section-2.1-7.8">The size of an OPRF private key as output from DeriveKeyPair.<a href="#section-2.1-7.8" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
</section>
</div>
<div id="deps-symmetric">
<section id="section-2.2">
<h3 id="name-key-derivation-function-and">
<a href="#section-2.2" class="section-number selfRef">2.2. </a><a href="#name-key-derivation-function-and" class="section-name selfRef">Key Derivation Function and Message Authentication Code</a>
</h3>
<p id="section-2.2-1">A Key Derivation Function (KDF) is a function that takes some source of initial
keying material and uses it to derive one or more cryptographically strong keys.
This specification uses a KDF with the following API and parameters:<a href="#section-2.2-1" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-2.2-2">
<dt id="section-2.2-2.1">Extract(salt, ikm):</dt>
<dd style="margin-left: 1.5em" id="section-2.2-2.2">Extract a pseudorandom key of fixed length
<code>Nx</code> bytes from input keying material <code>ikm</code> and an
optional byte string <code>salt</code>.<a href="#section-2.2-2.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-2.2-2.3">Expand(prk, info, L):</dt>
<dd style="margin-left: 1.5em" id="section-2.2-2.4">Expand a pseudorandom key <code>prk</code>,
using the string <code>info</code>, into <code>L</code> bytes of output
keying material.<a href="#section-2.2-2.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-2.2-2.5">
<code>Nx</code>:</dt>
<dd style="margin-left: 1.5em" id="section-2.2-2.6">The output size of the <code>Extract()</code> function in bytes.<a href="#section-2.2-2.6" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<p id="section-2.2-3">This specification also makes use of a random-key robust Message Authentication Code
(MAC). See <a href="#rkr-mac" class="auto internal xref">Section 10.6</a> for more details on this property. The API and parameters for
the random-key robust MAC are as follows:<a href="#section-2.2-3" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-2.2-4">
<dt id="section-2.2-4.1">MAC(key, msg):</dt>
<dd style="margin-left: 1.5em" id="section-2.2-4.2">Compute a message authentication code
over input <code>msg</code> with key <code>key</code>, producing a
fixed-length output of <code>Nm</code> bytes.<a href="#section-2.2-4.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-2.2-4.3">
<code>Nm</code>:</dt>
<dd style="margin-left: 1.5em" id="section-2.2-4.4">The output size of the <code>MAC()</code> function in bytes.<a href="#section-2.2-4.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
</section>
</div>
<div id="deps-hash">
<section id="section-2.3">
<h3 id="name-hash-functions">
<a href="#section-2.3" class="section-number selfRef">2.3. </a><a href="#name-hash-functions" class="section-name selfRef">Hash Functions</a>
</h3>
<p id="section-2.3-1">This specification makes use of a collision-resistant hash function with the following
API and parameters:<a href="#section-2.3-1" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-2.3-2">
<dt id="section-2.3-2.1">Hash(msg):</dt>
<dd style="margin-left: 1.5em" id="section-2.3-2.2">Apply a cryptographic hash function to input
<code>msg</code>, producing a fixed-length digest of size <code>Nh</code>
bytes.<a href="#section-2.3-2.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-2.3-2.3">
<code>Nh</code>:</dt>
<dd style="margin-left: 1.5em" id="section-2.3-2.4">The output size of the <code>Hash()</code> function in bytes.<a href="#section-2.3-2.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<p id="section-2.3-3">This specification makes use of a Key Stretching Function (KSF), which is a slow
and expensive cryptographic hash function with the following API:<a href="#section-2.3-3" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-2.3-4">
<dt id="section-2.3-4.1">Stretch(msg):</dt>
<dd style="margin-left: 1.5em" id="section-2.3-4.2">Apply a key stretching function to stretch
the input <code>msg</code> and harden it against offline dictionary
attacks. This function also needs to satisfy collision
resistance.<a href="#section-2.3-4.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
</section>
</div>
</section>
</div>
<div id="protocol-overview">
<section id="section-3">
<h2 id="name-protocol-overview">
<a href="#section-3" class="section-number selfRef">3. </a><a href="#name-protocol-overview" class="section-name selfRef">Protocol Overview</a>
</h2>
<p id="section-3-1">OPAQUE consists of two stages: registration and authenticated key exchange (AKE).
In the first stage, a client registers its password with the server and stores
its credential file on the server. In the second stage (also called the
"login" or "online" stage), the client recovers its authentication material and uses it to
perform a mutually authenticated key exchange.<a href="#section-3-1" class="pilcrow"></a></p>
<div id="setup">
<section id="section-3.1">
<h3 id="name-setup">
<a href="#section-3.1" class="section-number selfRef">3.1. </a><a href="#name-setup" class="section-name selfRef">Setup</a>
</h3>
<p id="section-3.1-1">Prior to both stages, the client and server agree on a configuration that
fully specifies the cryptographic algorithm dependencies necessary to run the
protocol; see <a href="#configurations" class="auto internal xref">Section 7</a> for details.
The server chooses a pair of keys (<code>server_private_key</code> and <code>server_public_key</code>)
for the AKE protocol and chooses a <code>seed</code> (<code>oprf_seed</code>) of <code>Nh</code> bytes for the OPRF.
The server can use <code>server_private_key</code> and <code>server_public_key</code> with multiple
clients. The server can also opt to use a different <code>seed</code> for each client
(i.e., each client can be assigned a single <code>seed</code>), so long as they are maintained
across the registration and online AKE stages and kept consistent for each
client (since an inconsistent mapping of clients to <code>seeds</code> could leak information
as described in <a href="#preventing-client-enumeration" class="auto internal xref">Section 10.9</a>).<a href="#section-3.1-1" class="pilcrow"></a></p>
</section>
</div>
<div id="registration">
<section id="section-3.2">
<h3 id="name-registration">
<a href="#section-3.2" class="section-number selfRef">3.2. </a><a href="#name-registration" class="section-name selfRef">Registration</a>
</h3>
<p id="section-3.2-1">Registration is the only stage in OPAQUE that requires a server-authenticated
channel with confidentiality and integrity: either physical, out-of-band, PKI-based, etc.<a href="#section-3.2-1" class="pilcrow"></a></p>
<p id="section-3.2-2">The client inputs its credentials, which include its password and user
identifier, and the server inputs its parameters, which include its private key
and other information.<a href="#section-3.2-2" class="pilcrow"></a></p>
<p id="section-3.2-3">The client output of this stage is a single value <code>export_key</code> that the client
may use for application-specific purposes, e.g., as a symmetric key used to encrypt
additional information for storage on the server. The server does not have access to this
<code>export_key</code>.<a href="#section-3.2-3" class="pilcrow"></a></p>
<p id="section-3.2-4">The server output of this stage is a <code>record</code> corresponding to the client's
registration that it stores in a credential file alongside other clients
registrations as needed.<a href="#section-3.2-4" class="pilcrow"></a></p>
<p id="section-3.2-5">The registration flow is shown in <a href="#fig1" class="auto internal xref">Figure 1</a>, and the process is described in more detail in
<a href="#registration-phase" class="auto internal xref">Section 5</a>:<a href="#section-3.2-5" class="pilcrow"></a></p>
<div id="fig1">
<figure id="figure-1">
<div class="alignLeft art-text artwork" id="section-3.2-6.1">
<pre>
credentials parameters
| |
v v
Client Server
------------------------------------------------
registration request
-------------------------&gt;
registration response
&lt;-------------------------
record
-------------------------&gt;
------------------------------------------------
| |
v v
export_key record
</pre>
</div>
<figcaption><a href="#figure-1" class="selfRef">Figure 1</a></figcaption></figure>
</div>
<p id="section-3.2-7">These messages are named <code>RegistrationRequest</code>, <code>RegistrationResponse</code>, and
<code>RegistrationRecord</code>, respectively. Their contents and wire format are defined in
<a href="#registration-messages" class="auto internal xref">Section 5.1</a>.<a href="#section-3.2-7" class="pilcrow"></a></p>
</section>
</div>
<div id="online-authenticated-key-exchange">
<section id="section-3.3">
<h3 id="name-online-authenticated-key-ex">
<a href="#section-3.3" class="section-number selfRef">3.3. </a><a href="#name-online-authenticated-key-ex" class="section-name selfRef">Online Authenticated Key Exchange</a>
</h3>
<p id="section-3.3-1">In this second stage, a client obtains credentials previously registered
with the server, recovers private key material using the password, and
subsequently uses them as input to the AKE protocol. As in the registration
phase, the client inputs its credentials, including its password and user
identifier, and the server inputs its parameters and the credential file <code>record</code>
corresponding to the client. The client outputs two values, an <code>export_key</code>
(matching that from registration) and a <code>session_key</code>, the latter of which
is the primary AKE protocol output. The server outputs a single value <code>session_key</code>
that matches that of the client. Upon completion, clients and servers can
use these values as needed.<a href="#section-3.3-1" class="pilcrow"></a></p>
<p id="section-3.3-2">The authenticated key exchange flow is shown in <a href="#fig2" class="auto internal xref">Figure 2</a>:<a href="#section-3.3-2" class="pilcrow"></a></p>
<div id="fig2">
<figure id="figure-2">
<div class="alignLeft art-text artwork" id="section-3.3-3.1">
<pre>
credentials (parameters, record)
| |
v v
Client Server
------------------------------------------------
AKE message 1
-------------------------&gt;
AKE message 2
&lt;-------------------------
AKE message 3
-------------------------&gt;
------------------------------------------------
| |
v v
(export_key, session_key) session_key
</pre>
</div>
<figcaption><a href="#figure-2" class="selfRef">Figure 2</a></figcaption></figure>
</div>
<p id="section-3.3-4">These messages are named <code>KE1</code>, <code>KE2</code>, and <code>KE3</code>, respectively. They carry the
messages of the concurrent execution of the key recovery process (OPRF) and the
authenticated key exchange (AKE). Their corresponding wire formats are
specified in <a href="#ake-messages" class="auto internal xref">Section 6.1</a>.<a href="#section-3.3-4" class="pilcrow"></a></p>
<p id="section-3.3-5">The rest of this document describes the specifics of these stages in detail.
<a href="#client-material" class="auto internal xref">Section 4</a> describes how client credential information is
generated, encoded, and stored on the server during registration and recovered during
login. <a href="#registration-phase" class="auto internal xref">Section 5</a> describes the first registration stage of the protocol,
and <a href="#online-phase" class="auto internal xref">Section 6</a> describes the second authentication stage of the protocol.
<a href="#configurations" class="auto internal xref">Section 7</a> describes how to instantiate OPAQUE using different
cryptographic dependencies and parameters.<a href="#section-3.3-5" class="pilcrow"></a></p>
</section>
</div>
</section>
</div>
<div id="client-material">
<section id="section-4">
<h2 id="name-client-credential-storage-a">
<a href="#section-4" class="section-number selfRef">4. </a><a href="#name-client-credential-storage-a" class="section-name selfRef">Client Credential Storage and Key Recovery</a>
</h2>
<p id="section-4-1">OPAQUE makes use of a structure called <code>Envelope</code> to manage client credentials.
The client creates its <code>Envelope</code> on registration and sends it to the server for
storage. On every login, the server sends this <code>Envelope</code> to the client so it can
recover its key material for use in the AKE.<a href="#section-4-1" class="pilcrow"></a></p>
<p id="section-4-2">Applications may pin key material to identities if desired. If no identity is given
for a party, its value <span class="bcp14">MUST</span> default to its public key. The following types of
application credential information are considered:<a href="#section-4-2" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-4-3">
<dt id="section-4-3.1">
<code>client_private_key</code>:</dt>
<dd style="margin-left: 1.5em" id="section-4-3.2">The encoded client private key for the AKE protocol.<a href="#section-4-3.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-4-3.3">
<code>client_public_key</code>:</dt>
<dd style="margin-left: 1.5em" id="section-4-3.4">The encoded client public key for the AKE protocol.<a href="#section-4-3.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-4-3.5">
<code>server_public_key</code>:</dt>
<dd style="margin-left: 1.5em" id="section-4-3.6">The encoded server public key for the AKE protocol.<a href="#section-4-3.6" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-4-3.7">
<code>client_identity</code>:</dt>
<dd style="margin-left: 1.5em" id="section-4-3.8">The client identity. This is an
application-specific value, e.g., an email address or an account
name. If not specified, it defaults to the client's public key.<a href="#section-4-3.8" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-4-3.9">
<code>server_identity</code>:</dt>
<dd style="margin-left: 1.5em" id="section-4-3.10">The server identity. This is typically a domain
name, e.g., example.com. If not specified, it defaults to the
server's public key. See <a href="#identities" class="auto internal xref">Section 10.3</a> for information
about this identity.<a href="#section-4-3.10" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<p id="section-4-4">A subset of these credential values are used in the <code>CleartextCredentials</code> structure as follows:<a href="#section-4-4" class="pilcrow"></a></p>
<div class="sourcecode" id="section-4-5">
<pre>
struct {
uint8 server_public_key[Npk];
uint8 server_identity&lt;1..2^16-1&gt;;
uint8 client_identity&lt;1..2^16-1&gt;;
} CleartextCredentials;
</pre><a href="#section-4-5" class="pilcrow"></a>
</div>
<p id="section-4-6">The function CreateCleartextCredentials constructs a <code>CleartextCredentials</code> structure given
application credential information.<a href="#section-4-6" class="pilcrow"></a></p>
<div class="sourcecode" id="section-4-7">
<pre>
CreateCleartextCredentials
Input:
- server_public_key, the encoded server public key
for the AKE protocol.
- client_public_key, the encoded client public key
for the AKE protocol.
- server_identity, the optional encoded server identity.
- client_identity, the optional encoded client identity.
Output:
- cleartext_credentials, a CleartextCredentials structure.
def CreateCleartextCredentials(server_public_key, client_public_key,
server_identity, client_identity):
# Set identities as public keys if no
# application-layer identity is provided
if server_identity == nil
server_identity = server_public_key
if client_identity == nil
client_identity = client_public_key
cleartext_credentials = CleartextCredentials {
server_public_key,
server_identity,
client_identity
}
return cleartext_credentials
</pre><a href="#section-4-7" class="pilcrow"></a>
</div>
<div id="key-recovery">
<section id="section-4.1">
<h3 id="name-key-recovery">
<a href="#section-4.1" class="section-number selfRef">4.1. </a><a href="#name-key-recovery" class="section-name selfRef">Key Recovery</a>
</h3>
<p id="section-4.1-1">This specification defines a key recovery mechanism that uses the stretched OPRF
output as a <code>seed</code> to directly derive the private and public keys using the
<code>DeriveDiffieHellmanKeyPair()</code> function defined in <a href="#key-creation" class="auto internal xref">Section 6.4.1</a>.<a href="#section-4.1-1" class="pilcrow"></a></p>
<div id="envelope-structure">
<section id="section-4.1.1">
<h4 id="name-envelope-structure">
<a href="#section-4.1.1" class="section-number selfRef">4.1.1. </a><a href="#name-envelope-structure" class="section-name selfRef">Envelope Structure</a>
</h4>
<p id="section-4.1.1-1">The key recovery mechanism defines its <code>Envelope</code> as follows:<a href="#section-4.1.1-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-4.1.1-2">
<pre>
struct {
uint8 envelope_nonce[Nn];
uint8 auth_tag[Nm];
} Envelope;
</pre><a href="#section-4.1.1-2" class="pilcrow"></a>
</div>
<span class="break"></span><dl class="dlParallel" id="section-4.1.1-3">
<dt id="section-4.1.1-3.1">
<code>envelope_nonce</code>:</dt>
<dd style="margin-left: 1.5em" id="section-4.1.1-3.2">A randomly sampled nonce of length
<code>Nn</code> used to protect this <code>Envelope</code>.<a href="#section-4.1.1-3.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-4.1.1-3.3">
<code>auth_tag</code>:</dt>
<dd style="margin-left: 1.5em" id="section-4.1.1-3.4">An authentication tag protecting the
contents of the <code>Envelope</code>, covering <code>envelope_nonce</code> and
<code>CleartextCredentials</code>.<a href="#section-4.1.1-3.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
</section>
</div>
<div id="envelope-creation">
<section id="section-4.1.2">
<h4 id="name-envelope-creation">
<a href="#section-4.1.2" class="section-number selfRef">4.1.2. </a><a href="#name-envelope-creation" class="section-name selfRef">Envelope Creation</a>
</h4>
<p id="section-4.1.2-1">Clients create an <code>Envelope</code> at registration with the function <code>Store</code> defined
below. Note that <code>DeriveDiffieHellmanKeyPair</code> in this function can fail with negligible
probability. If this occurs, servers should re-run the function, sampling a
new <code>envelope_nonce</code>, to completion.<a href="#section-4.1.2-1" class="pilcrow"></a></p>
<div class="breakable sourcecode" id="section-4.1.2-2">
<pre>
Store
Input:
- randomized_password, a randomized password.
- server_public_key, the encoded server public key for
the AKE protocol.
- server_identity, the optional encoded server identity.
- client_identity, the optional encoded client identity.
Output:
- envelope, the client's Envelope structure.
- client_public_key, the client's AKE public key.
- masking_key, an encryption key used by the server with the
sole purpose of defending against client enumeration attacks.
- export_key, an additional client key.
def Store(randomized_password, server_public_key,
server_identity, client_identity):
envelope_nonce = random(Nn)
masking_key = Expand(randomized_password, "MaskingKey", Nh)
auth_key =
Expand(randomized_password, concat(envelope_nonce, "AuthKey"),
Nh)
export_key =
Expand(randomized_password, concat(envelope_nonce, "ExportKey"),
Nh)
seed =
Expand(randomized_password, concat(envelope_nonce, "PrivateKey"),
Nseed)
(_, client_public_key) = DeriveDiffieHellmanKeyPair(seed)
cleartext_credentials =
CreateCleartextCredentials(server_public_key, client_public_key,
server_identity, client_identity)
auth_tag =
MAC(auth_key, concat(
envelope_nonce,
server_public_key,
I2OSP(len(cleartext_credentials.server_identity), 2),
cleartext_credentials.server_identity,
I2OSP(len(cleartext_credentials.client_identity), 2),
cleartext_credentials.client_identity
))
envelope = Envelope {
envelope_nonce,
auth_tag
}
return (envelope, client_public_key, masking_key, export_key)
</pre><a href="#section-4.1.2-2" class="pilcrow"></a>
</div>
</section>
</div>
<div id="envelope-recovery">
<section id="section-4.1.3">
<h4 id="name-envelope-recovery">
<a href="#section-4.1.3" class="section-number selfRef">4.1.3. </a><a href="#name-envelope-recovery" class="section-name selfRef">Envelope Recovery</a>
</h4>
<p id="section-4.1.3-1">Clients recover their <code>Envelope</code> during login with the <code>Recover</code> function
defined below.<a href="#section-4.1.3-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-4.1.3-2">
<pre>
Recover
Input:
- randomized_password, a randomized password.
- server_public_key, the encoded server public key for the
AKE protocol.
- envelope, the client's Envelope structure.
- server_identity, the optional encoded server identity.
- client_identity, the optional encoded client identity.
Output:
- client_private_key, the encoded client private key for the
AKE protocol.
- cleartext_credentials, a CleartextCredentials structure.
- export_key, an additional client key.
Exceptions:
- EnvelopeRecoveryError, the Envelope fails to be recovered.
def Recover(randomized_password, server_public_key, envelope,
server_identity, client_identity):
auth_key =
Expand(randomized_password, concat(envelope.nonce, "AuthKey"),
Nh)
export_key =
Expand(randomized_password, concat(envelope.nonce, "ExportKey"),
Nh)
seed =
Expand(randomized_password, concat(envelope.nonce, "PrivateKey"),
Nseed)
(client_private_key, client_public_key) =
DeriveDiffieHellmanKeyPair(seed)
cleartext_credentials =
CreateCleartextCredentials(server_public_key, client_public_key,
server_identity, client_identity)
expected_tag =
MAC(auth_key, concat(envelope.nonce, cleartext_credentials))
If !ct_equal(envelope.auth_tag, expected_tag)
raise EnvelopeRecoveryError
return (client_private_key, cleartext_credentials, export_key)
</pre><a href="#section-4.1.3-2" class="pilcrow"></a>
</div>
<p id="section-4.1.3-3">In the case of <code>EnvelopeRecoveryError</code> being raised, all previously computed
intermediary values in this function <span class="bcp14">MUST</span> be deleted.<a href="#section-4.1.3-3" class="pilcrow"></a></p>
</section>
</div>
</section>
</div>
</section>
</div>
<div id="registration-phase">
<section id="section-5">
<h2 id="name-registration-2">
<a href="#section-5" class="section-number selfRef">5. </a><a href="#name-registration-2" class="section-name selfRef">Registration</a>
</h2>
<p id="section-5-1">The registration process proceeds as follows. The client inputs
the following values:<a href="#section-5-1" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-5-2">
<dt id="section-5-2.1">password:</dt>
<dd style="margin-left: 1.5em" id="section-5-2.2">The client's password.<a href="#section-5-2.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-5-2.3">creds:</dt>
<dd style="margin-left: 1.5em" id="section-5-2.4">The client credentials as described in <a href="#client-material" class="auto internal xref">Section 4</a>.<a href="#section-5-2.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<p id="section-5-3">The server inputs the following values:<a href="#section-5-3" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-5-4">
<dt id="section-5-4.1">
<code>server_public_key</code>:</dt>
<dd style="margin-left: 1.5em" id="section-5-4.2">The server public key for the AKE protocol.<a href="#section-5-4.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-5-4.3">
<code>credential_identifier</code>:</dt>
<dd style="margin-left: 1.5em" id="section-5-4.4">A unique identifier for the client's
credential generated by the server.<a href="#section-5-4.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-5-4.5">
<code>client_identity</code>:</dt>
<dd style="margin-left: 1.5em" id="section-5-4.6">The optional client identity as described in <a href="#client-material" class="auto internal xref">Section 4</a>.<a href="#section-5-4.6" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-5-4.7">
<code>oprf_seed</code>:</dt>
<dd style="margin-left: 1.5em" id="section-5-4.8">A <code>seed</code> used to derive per-client OPRF keys.<a href="#section-5-4.8" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<p id="section-5-5">The registration protocol then runs as shown below:<a href="#section-5-5" class="pilcrow"></a></p>
<div class="alignLeft art-text artwork" id="section-5-6">
<pre>
Client Server
------------------------------------------------------
(request, blind) = CreateRegistrationRequest(password)
request
-------------------------&gt;
response = CreateRegistrationResponse(request,
server_public_key,
credential_identifier,
oprf_seed)
response
&lt;-------------------------
(record, export_key) = FinalizeRegistrationRequest(password,
blind,
response,
server_identity,
client_identity)
record
-------------------------&gt;
</pre><a href="#section-5-6" class="pilcrow"></a>
</div>
<p id="section-5-7"><a href="#registration-messages" class="auto internal xref">Section 5.1</a> describes the formats for the above messages, and
<a href="#registration-functions" class="auto internal xref">Section 5.2</a> describes details of the functions and the
corresponding parameters referenced above.<a href="#section-5-7" class="pilcrow"></a></p>
<p id="section-5-8">At the end of this interaction, the server stores the <code>record</code> object as the
credential file for each client along with the associated <code>credential_identifier</code>
and <code>client_identity</code> (if different). Note that the values <code>oprf_seed</code> and
<code>server_private_key</code> from the server's setup phase must also be persisted.
The <code>oprf_seed</code> value <span class="bcp14">SHOULD</span> be used for all clients; see <a href="#preventing-client-enumeration" class="auto internal xref">Section 10.9</a>
for the justification behind this, along with a description of the exception in which
applications may choose to avoid the use of a global <code>oprf_seed</code> value across clients
and instead sample OPRF keys uniquely for each client. The <code>server_private_key</code> may
be unique for each client.<a href="#section-5-8" class="pilcrow"></a></p>
<p id="section-5-9">Both client and server <span class="bcp14">MUST</span> validate the other party's public key before use.
See <a href="#validation" class="auto internal xref">Section 10.7</a> for more details. Upon completion, the server stores
the client's credentials for later use. Moreover, the client <span class="bcp14">MAY</span> use the output
<code>export_key</code> for further application-specific purposes; see <a href="#export-key-usage" class="auto internal xref">Section 10.4</a>.<a href="#section-5-9" class="pilcrow"></a></p>
<div id="registration-messages">
<section id="section-5.1">
<h3 id="name-registration-messages">
<a href="#section-5.1" class="section-number selfRef">5.1. </a><a href="#name-registration-messages" class="section-name selfRef">Registration Messages</a>
</h3>
<p id="section-5.1-1">This section contains definitions of the <code>RegistrationRequest</code>,
<code>RegistrationResponse</code>, and <code>RegistrationRecord</code> messages exchanged between
client and server during registration.<a href="#section-5.1-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-5.1-2">
<pre>
struct {
uint8 blinded_message[Noe];
} RegistrationRequest;
</pre><a href="#section-5.1-2" class="pilcrow"></a>
</div>
<span class="break"></span><dl class="dlParallel" id="section-5.1-3">
<dt id="section-5.1-3.1">blinded_message:</dt>
<dd style="margin-left: 1.5em" id="section-5.1-3.2">A serialized OPRF group element.<a href="#section-5.1-3.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<div class="sourcecode" id="section-5.1-4">
<pre>
struct {
uint8 evaluated_message[Noe];
uint8 server_public_key[Npk];
} RegistrationResponse;
</pre><a href="#section-5.1-4" class="pilcrow"></a>
</div>
<span class="break"></span><dl class="dlParallel" id="section-5.1-5">
<dt id="section-5.1-5.1">evaluated_message:</dt>
<dd style="margin-left: 1.5em" id="section-5.1-5.2">A serialized OPRF group element.<a href="#section-5.1-5.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-5.1-5.3">
<code>server_public_key</code>:</dt>
<dd style="margin-left: 1.5em" id="section-5.1-5.4">The server's encoded public key that will be
used for the online AKE stage.<a href="#section-5.1-5.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<div class="sourcecode" id="section-5.1-6">
<pre>
struct {
uint8 client_public_key[Npk];
uint8 masking_key[Nh];
Envelope envelope;
} RegistrationRecord;
</pre><a href="#section-5.1-6" class="pilcrow"></a>
</div>
<span class="break"></span><dl class="dlParallel" id="section-5.1-7">
<dt id="section-5.1-7.1">
<code>client_public_key</code>:</dt>
<dd style="margin-left: 1.5em" id="section-5.1-7.2">The client's encoded public key
corresponding to the private key <code>client_private_key</code>.<a href="#section-5.1-7.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-5.1-7.3">
<code>masking_key</code>:</dt>
<dd style="margin-left: 1.5em" id="section-5.1-7.4">An encryption key used by the server with
the sole purpose of defending against client enumeration
attacks.<a href="#section-5.1-7.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-5.1-7.5">envelope:</dt>
<dd style="margin-left: 1.5em" id="section-5.1-7.6">The client's <code>Envelope</code> structure.<a href="#section-5.1-7.6" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
</section>
</div>
<div id="registration-functions">
<section id="section-5.2">
<h3 id="name-registration-functions">
<a href="#section-5.2" class="section-number selfRef">5.2. </a><a href="#name-registration-functions" class="section-name selfRef">Registration Functions</a>
</h3>
<p id="section-5.2-1">This section contains definitions of the functions used by client and server
during registration, including <code>CreateRegistrationRequest</code>, <code>CreateRegistrationResponse</code>,
and <code>FinalizeRegistrationRequest</code>.<a href="#section-5.2-1" class="pilcrow"></a></p>
<div id="createregistrationrequest">
<section id="section-5.2.1">
<h4 id="name-createregistrationrequest">
<a href="#section-5.2.1" class="section-number selfRef">5.2.1. </a><a href="#name-createregistrationrequest" class="section-name selfRef">CreateRegistrationRequest</a>
</h4>
<p id="section-5.2.1-1">To begin the registration flow, the client executes the following function. This function
can fail with an <code>InvalidInputError</code> error with negligible probability. A different input
password is necessary in the event of this error.<a href="#section-5.2.1-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-5.2.1-2">
<pre>
CreateRegistrationRequest
Input:
- password, an opaque byte string containing the client's password.
Output:
- request, a RegistrationRequest structure.
- blind, an OPRF scalar value.
Exceptions:
- InvalidInputError, when Blind fails
def CreateRegistrationRequest(password):
(blind, blinded_element) = Blind(password)
blinded_message = SerializeElement(blinded_element)
request = RegistrationRequest {
blinded_message
}
return (request, blind)
</pre><a href="#section-5.2.1-2" class="pilcrow"></a>
</div>
</section>
</div>
<div id="create-reg-response">
<section id="section-5.2.2">
<h4 id="name-createregistrationresponse">
<a href="#section-5.2.2" class="section-number selfRef">5.2.2. </a><a href="#name-createregistrationresponse" class="section-name selfRef">CreateRegistrationResponse</a>
</h4>
<p id="section-5.2.2-1">To process the client's registration request, the server executes
the following function. This function can fail with a <code>DeriveKeyPairError</code>
error with negligible probability. In this case, applications can
choose a new <code>credential_identifier</code> for this registration <code>record</code>
and rerun this function.<a href="#section-5.2.2-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-5.2.2-2">
<pre>
CreateRegistrationResponse
Input:
- request, a RegistrationRequest structure.
- server_public_key, the server's public key.
- credential_identifier, an identifier that uniquely represents
the credential.
- oprf_seed, the seed of Nh bytes used by the server to generate
an oprf_key.
Output:
- response, a RegistrationResponse structure.
Exceptions:
- DeserializeError, when OPRF element deserialization fails.
- DeriveKeyPairError, when OPRF key derivation fails.
def CreateRegistrationResponse(request, server_public_key,
credential_identifier, oprf_seed):
seed =
Expand(oprf_seed, concat(credential_identifier, "OprfKey"), Nok)
(oprf_key, _) = DeriveKeyPair(seed, "OPAQUE-DeriveKeyPair")
blinded_element = DeserializeElement(request.blinded_message)
evaluated_element = BlindEvaluate(oprf_key, blinded_element)
evaluated_message = SerializeElement(evaluated_element)
response = RegistrationResponse {
evaluated_message,
server_public_key
}
return response
</pre><a href="#section-5.2.2-2" class="pilcrow"></a>
</div>
</section>
</div>
<div id="finalize-request">
<section id="section-5.2.3">
<h4 id="name-finalizeregistrationrequest">
<a href="#section-5.2.3" class="section-number selfRef">5.2.3. </a><a href="#name-finalizeregistrationrequest" class="section-name selfRef">FinalizeRegistrationRequest</a>
</h4>
<p id="section-5.2.3-1">To create the user <code>record</code> used for subsequent authentication and complete the
registration flow, the client executes the following function.<a href="#section-5.2.3-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-5.2.3-2">
<pre>
FinalizeRegistrationRequest
Input:
- password, an opaque byte string containing the client's password.
- blind, an OPRF scalar value.
- response, a RegistrationResponse structure.
- server_identity, the optional encoded server identity.
- client_identity, the optional encoded client identity.
Output:
- record, a RegistrationRecord structure.
- export_key, an additional client key.
Exceptions:
- DeserializeError, when OPRF element deserialization fails.
def FinalizeRegistrationRequest(password, blind, response,
server_identity, client_identity):
evaluated_element = DeserializeElement(response.evaluated_message)
oprf_output = Finalize(password, blind, evaluated_element)
stretched_oprf_output = Stretch(oprf_output)
randomized_password =
Extract("", concat(oprf_output, stretched_oprf_output))
(envelope, client_public_key, masking_key, export_key) =
Store(randomized_password, response.server_public_key,
server_identity, client_identity)
record = RegistrationRecord {
client_public_key,
masking_key,
envelope
}
return (record, export_key)
</pre><a href="#section-5.2.3-2" class="pilcrow"></a>
</div>
<p id="section-5.2.3-3">See <a href="#online-phase" class="auto internal xref">Section 6</a> for details about the output <code>export_key</code> usage.<a href="#section-5.2.3-3" class="pilcrow"></a></p>
</section>
</div>
</section>
</div>
</section>
</div>
<div id="online-phase">
<section id="section-6">
<h2 id="name-online-authenticated-key-exc">
<a href="#section-6" class="section-number selfRef">6. </a><a href="#name-online-authenticated-key-exc" class="section-name selfRef">Online Authenticated Key Exchange</a>
</h2>
<p id="section-6-1">The generic outline of OPAQUE with a 3-message AKE protocol includes three
messages: <code>KE1</code>, <code>KE2</code>, and <code>KE3</code>. <code>KE1</code> and <code>KE2</code> include key exchange shares (e.g., DH
values) sent by the client and server, respectively. <code>KE3</code> provides explicit
client authentication and full forward security (without it, forward secrecy
is only achieved against eavesdroppers, which is insufficient for OPAQUE
security).<a href="#section-6-1" class="pilcrow"></a></p>
<p id="section-6-2">This section describes the online authenticated key exchange protocol flow,
message encoding, and helper functions. This stage is composed of a concurrent
OPRF and key exchange flow. The key exchange protocol is authenticated using the
client and server credentials established during registration; see <a href="#registration-phase" class="auto internal xref">Section 5</a>.
In the end, the client proves its knowledge of the password, and both client and
server agree on (1) a mutually authenticated shared secret key and (2) any optional
application information exchange during the handshake.<a href="#section-6-2" class="pilcrow"></a></p>
<p id="section-6-3">In this stage, the client inputs the following values:<a href="#section-6-3" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-6-4">
<dt id="section-6-4.1">password:</dt>
<dd style="margin-left: 1.5em" id="section-6-4.2">The client's password.<a href="#section-6-4.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6-4.3">
<code>client_identity</code>:</dt>
<dd style="margin-left: 1.5em" id="section-6-4.4">The client identity as described in <a href="#client-material" class="auto internal xref">Section 4</a>.<a href="#section-6-4.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<p id="section-6-5">The server inputs the following values:<a href="#section-6-5" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-6-6">
<dt id="section-6-6.1">
<code>server_private_key</code>:</dt>
<dd style="margin-left: 1.5em" id="section-6-6.2">The server's private key for the AKE protocol.<a href="#section-6-6.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6-6.3">
<code>server_public_key</code>:</dt>
<dd style="margin-left: 1.5em" id="section-6-6.4">The server's public key for the AKE protocol.<a href="#section-6-6.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6-6.5">
<code>server_identity</code>:</dt>
<dd style="margin-left: 1.5em" id="section-6-6.6">The server identity as described in <a href="#client-material" class="auto internal xref">Section 4</a>.<a href="#section-6-6.6" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6-6.7">
<code>record</code>:</dt>
<dd style="margin-left: 1.5em" id="section-6-6.8">The <code>RegistrationRecord</code> object corresponding to the client's registration.<a href="#section-6-6.8" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6-6.9">
<code>credential_identifier</code>:</dt>
<dd style="margin-left: 1.5em" id="section-6-6.10">An identifier that uniquely represents the credential.<a href="#section-6-6.10" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6-6.11">
<code>oprf_seed</code>:</dt>
<dd style="margin-left: 1.5em" id="section-6-6.12">The <code>seed</code> used to derive per-client OPRF keys.<a href="#section-6-6.12" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<p id="section-6-7">The client receives two outputs: a session secret and an export key. The export
key is only available to the client and may be used for additional
application-specific purposes, as outlined in <a href="#export-key-usage" class="auto internal xref">Section 10.4</a>.
Clients <span class="bcp14">MUST NOT</span> use the output <code>export_key</code> before
authenticating the peer in the authenticated key exchange protocol.
See <a href="#alternate-key-recovery" class="auto internal xref">Appendix A</a> for more details about this
requirement. The server receives a single output: a session secret matching the
client's.<a href="#section-6-7" class="pilcrow"></a></p>
<p id="section-6-8">The protocol runs as shown below:<a href="#section-6-8" class="pilcrow"></a></p>
<div class="alignLeft art-text artwork" id="section-6-9">
<pre>
Client Server
------------------------------------------------------
ke1 = GenerateKE1(password)
ke1
-------------------------&gt;
ke2 = GenerateKE2(server_identity, server_private_key,
server_public_key, record,
credential_identifier, oprf_seed, ke1)
ke2
&lt;-------------------------
(ke3,
session_key,
export_key) = GenerateKE3(client_identity,
server_identity, ke2)
ke3
-------------------------&gt;
session_key = ServerFinish(ke3)
</pre><a href="#section-6-9" class="pilcrow"></a>
</div>
<p id="section-6-10">Both client and server may use implicit internal state objects to keep necessary
material for the OPRF and AKE, <code>client_state</code>, and <code>server_state</code>, respectively.<a href="#section-6-10" class="pilcrow"></a></p>
<p id="section-6-11">The client state <code>ClientState</code> may have the following fields:<a href="#section-6-11" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-6-12">
<dt id="section-6-12.1">password:</dt>
<dd style="margin-left: 1.5em" id="section-6-12.2">The client's password.<a href="#section-6-12.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6-12.3">
<code>blind</code>:</dt>
<dd style="margin-left: 1.5em" id="section-6-12.4">The random blinding inverter returned by <code>Blind()</code>.<a href="#section-6-12.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6-12.5">client_ake_state:</dt>
<dd style="margin-left: 1.5em" id="section-6-12.6">The <code>ClientAkeState</code> as defined in <a href="#protocol-3dh" class="auto internal xref">Section 6.4</a>.<a href="#section-6-12.6" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<p id="section-6-13">The server state <code>ServerState</code> may have the following fields:<a href="#section-6-13" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-6-14">
<dt id="section-6-14.1">server_ake_state:</dt>
<dd style="margin-left: 1.5em" id="section-6-14.2">The <code>ServerAkeState</code> as defined in <a href="#protocol-3dh" class="auto internal xref">Section 6.4</a>.<a href="#section-6-14.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<p id="section-6-15">Both of these states are ephemeral and should be erased after the protocol completes.<a href="#section-6-15" class="pilcrow"></a></p>
<p id="section-6-16">The rest of this section describes these authenticated key exchange messages
and their parameters in more detail. <a href="#ake-messages" class="auto internal xref">Section 6.1</a> defines the structure of the
messages passed between client and server in the above setup. <a href="#ake-functions" class="auto internal xref">Section 6.2</a>
describes details of the functions and corresponding parameters mentioned above.
<a href="#cred-retrieval" class="auto internal xref">Section 6.3</a> discusses internal functions used for retrieving client
credentials, and <a href="#protocol-3dh" class="auto internal xref">Section 6.4</a> discusses how these functions are used to execute
the authenticated key exchange protocol.<a href="#section-6-16" class="pilcrow"></a></p>
<div id="ake-messages">
<section id="section-6.1">
<h3 id="name-ake-messages">
<a href="#section-6.1" class="section-number selfRef">6.1. </a><a href="#name-ake-messages" class="section-name selfRef">AKE Messages</a>
</h3>
<p id="section-6.1-1">In this section, we define the <code>KE1</code>, <code>KE2</code>, and <code>KE3</code> structs that make up
the AKE messages used in the protocol. <code>KE1</code> is composed of a <code>CredentialRequest</code>
and <code>AuthRequest</code>, and <code>KE2</code> is composed of a <code>CredentialResponse</code>
and <code>AuthResponse</code>.<a href="#section-6.1-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.1-2">
<pre>
struct {
uint8 client_nonce[Nn];
uint8 client_public_keyshare[Npk];
} AuthRequest;
</pre><a href="#section-6.1-2" class="pilcrow"></a>
</div>
<span class="break"></span><dl class="dlParallel" id="section-6.1-3">
<dt id="section-6.1-3.1">client_nonce:</dt>
<dd style="margin-left: 1.5em" id="section-6.1-3.2">A fresh randomly generated nonce of length <code>Nn</code>.<a href="#section-6.1-3.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6.1-3.3">client_public_keyshare:</dt>
<dd style="margin-left: 1.5em" id="section-6.1-3.4">A serialized client ephemeral public key of fixed size <code>Npk</code>.<a href="#section-6.1-3.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<div class="sourcecode" id="section-6.1-4">
<pre>
struct {
CredentialRequest credential_request;
AuthRequest auth_request;
} KE1;
</pre><a href="#section-6.1-4" class="pilcrow"></a>
</div>
<span class="break"></span><dl class="dlParallel" id="section-6.1-5">
<dt id="section-6.1-5.1">credential_request:</dt>
<dd style="margin-left: 1.5em" id="section-6.1-5.2">A <code>CredentialRequest</code> structure.<a href="#section-6.1-5.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6.1-5.3">auth_request:</dt>
<dd style="margin-left: 1.5em" id="section-6.1-5.4">An <code>AuthRequest</code> structure.<a href="#section-6.1-5.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<div class="sourcecode" id="section-6.1-6">
<pre>
struct {
uint8 server_nonce[Nn];
uint8 server_public_keyshare[Npk];
uint8 server_mac[Nm];
} AuthResponse;
</pre><a href="#section-6.1-6" class="pilcrow"></a>
</div>
<span class="break"></span><dl class="dlParallel" id="section-6.1-7">
<dt id="section-6.1-7.1">server_nonce:</dt>
<dd style="margin-left: 1.5em" id="section-6.1-7.2">A fresh randomly generated nonce of length <code>Nn</code>.<a href="#section-6.1-7.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6.1-7.3">
<code>server_public_key</code>share:</dt>
<dd style="margin-left: 1.5em" id="section-6.1-7.4">A server ephemeral public key of
fixed size <code>Npk</code>, where <code>Npk</code> depends on the
corresponding prime order group.<a href="#section-6.1-7.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6.1-7.5">server_mac:</dt>
<dd style="margin-left: 1.5em" id="section-6.1-7.6">An authentication tag computed over the
handshake transcript computed using <code>Km2</code>, which is defined
below.<a href="#section-6.1-7.6" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<div class="sourcecode" id="section-6.1-8">
<pre>
struct {
CredentialResponse credential_response;
AuthResponse auth_response;
} KE2;
</pre><a href="#section-6.1-8" class="pilcrow"></a>
</div>
<span class="break"></span><dl class="dlParallel" id="section-6.1-9">
<dt id="section-6.1-9.1">credential_response:</dt>
<dd style="margin-left: 1.5em" id="section-6.1-9.2">A <code>CredentialResponse</code> structure.<a href="#section-6.1-9.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6.1-9.3">auth_response:</dt>
<dd style="margin-left: 1.5em" id="section-6.1-9.4">An <code>AuthResponse</code> structure.<a href="#section-6.1-9.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<div class="sourcecode" id="section-6.1-10">
<pre>
struct {
uint8 client_mac[Nm];
} KE3;
</pre><a href="#section-6.1-10" class="pilcrow"></a>
</div>
<span class="break"></span><dl class="dlParallel" id="section-6.1-11">
<dt id="section-6.1-11.1">client_mac:</dt>
<dd style="margin-left: 1.5em" id="section-6.1-11.2">An authentication tag computed over the
handshake transcript of fixed size <code>Nm</code>, computed using
<code>Km2</code>, defined below.<a href="#section-6.1-11.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
</section>
</div>
<div id="ake-functions">
<section id="section-6.2">
<h3 id="name-ake-functions">
<a href="#section-6.2" class="section-number selfRef">6.2. </a><a href="#name-ake-functions" class="section-name selfRef">AKE Functions</a>
</h3>
<p id="section-6.2-1">In this section, we define the main functions used to produce the AKE messages
in the protocol. Note that this section relies on definitions of subroutines defined
in later sections:<a href="#section-6.2-1" class="pilcrow"></a></p>
<ul class="normal">
<li class="normal" id="section-6.2-2.1">
<p id="section-6.2-2.1.1"><code>CreateCredentialRequest</code>, <code>CreateCredentialResponse</code>, and <code>RecoverCredentials</code> are defined in <a href="#cred-retrieval" class="auto internal xref">Section 6.3</a>.<a href="#section-6.2-2.1.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-6.2-2.2">
<p id="section-6.2-2.2.1"><code>AuthClientStart</code>, <code>AuthServerRespond</code>, <code>AuthClientFinalize</code>, and <code>AuthServerFinalize</code> are
defined in Sections <a href="#ake-client" class="auto internal xref">6.4.3</a> and <a href="#ake-server" class="auto internal xref">6.4.4</a>.<a href="#section-6.2-2.2.1" class="pilcrow"></a></p>
</li>
</ul>
<div id="generateke1">
<section id="section-6.2.1">
<h4 id="name-generateke1">
<a href="#section-6.2.1" class="section-number selfRef">6.2.1. </a><a href="#name-generateke1" class="section-name selfRef">GenerateKE1</a>
</h4>
<p id="section-6.2.1-1">The <code>GenerateKE1</code> function begins the AKE protocol and produces the client's <code>KE1</code>
output for the server.<a href="#section-6.2.1-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.2.1-2">
<pre>
GenerateKE1
State:
- state, a ClientState structure.
Input:
- password, an opaque byte string containing the client's password.
Output:
- ke1, a KE1 message structure.
def GenerateKE1(password):
request, blind = CreateCredentialRequest(password)
state.password = password
state.blind = blind
ke1 = AuthClientStart(request)
return ke1
</pre><a href="#section-6.2.1-2" class="pilcrow"></a>
</div>
</section>
</div>
<div id="generateke2">
<section id="section-6.2.2">
<h4 id="name-generateke2">
<a href="#section-6.2.2" class="section-number selfRef">6.2.2. </a><a href="#name-generateke2" class="section-name selfRef">GenerateKE2</a>
</h4>
<p id="section-6.2.2-1">The <code>GenerateKE2</code> function continues the AKE protocol by processing the client's <code>KE1</code> message
and producing the server's <code>KE2</code> output.<a href="#section-6.2.2-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.2.2-2">
<pre>
GenerateKE2
State:
- state, a ServerState structure.
Input:
- server_identity, the optional encoded server identity, which is
set to server_public_key if not specified.
- server_private_key, the server's private key.
- server_public_key, the server's public key.
- record, the client's RegistrationRecord structure.
- credential_identifier, an identifier that uniquely represents
the credential.
- oprf_seed, the server-side seed of Nh bytes used to generate
an oprf_key.
- ke1, a KE1 message structure.
- client_identity, the optional encoded client identity, which is
set to client_public_key if not specified.
Output:
- ke2, a KE2 structure.
def GenerateKE2(server_identity, server_private_key,
server_public_key, record, credential_identifier,
oprf_seed, ke1, client_identity):
credential_response =
CreateCredentialResponse(ke1.credential_request,
server_public_key, record,
credential_identifier, oprf_seed)
cleartext_credentials =
CreateCleartextCredentials(server_public_key,
record.client_public_key,
server_identity, client_identity)
auth_response =
AuthServerRespond(cleartext_credentials, server_private_key,
record.client_public_key, ke1,
credential_response)
ke2 = KE2 {
credential_response,
auth_response
}
return ke2
</pre><a href="#section-6.2.2-2" class="pilcrow"></a>
</div>
</section>
</div>
<div id="generateke3">
<section id="section-6.2.3">
<h4 id="name-generateke3">
<a href="#section-6.2.3" class="section-number selfRef">6.2.3. </a><a href="#name-generateke3" class="section-name selfRef">GenerateKE3</a>
</h4>
<p id="section-6.2.3-1">The <code>GenerateKE3</code> function completes the AKE protocol for the client and
produces the client's <code>KE3</code> output for the server, as well as the <code>session_key</code>
and <code>export_key</code> outputs from the AKE.<a href="#section-6.2.3-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.2.3-2">
<pre>
GenerateKE3
State:
- state, a ClientState structure.
Input:
- client_identity, the optional encoded client identity, which is
set to client_public_key if not specified.
- server_identity, the optional encoded server identity, which is
set to server_public_key if not specified.
- ke2, a KE2 message structure.
Output:
- ke3, a KE3 message structure.
- session_key, the session's shared secret.
- export_key, an additional client key.
def GenerateKE3(client_identity, server_identity, ke2):
(client_private_key, cleartext_credentials, export_key) =
RecoverCredentials(state.password, state.blind,
ke2.credential_response,
server_identity, client_identity)
(ke3, session_key) =
AuthClientFinalize(cleartext_credentials,
client_private_key, ke2)
return (ke3, session_key, export_key)
</pre><a href="#section-6.2.3-2" class="pilcrow"></a>
</div>
</section>
</div>
<div id="serverfinish">
<section id="section-6.2.4">
<h4 id="name-serverfinish">
<a href="#section-6.2.4" class="section-number selfRef">6.2.4. </a><a href="#name-serverfinish" class="section-name selfRef">ServerFinish</a>
</h4>
<p id="section-6.2.4-1">The <code>ServerFinish</code> function completes the AKE protocol for the server, yielding the <code>session_key</code>.
Since the OPRF is a two-message protocol, <code>KE3</code> has no element of the OPRF. Therefore, <code>KE3</code>
invokes the AKE's <code>AuthServerFinalize</code> directly. The <code>AuthServerFinalize</code> function
takes <code>KE3</code> as input and <span class="bcp14">MUST</span> verify the client authentication material it contains
before the <code>session_key</code> value can be used. This verification is necessary to ensure
forward secrecy against active attackers.<a href="#section-6.2.4-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.2.4-2">
<pre>
ServerFinish
State:
- state, a ServerState structure.
Input:
- ke3, a KE3 structure.
Output:
- session_key, the shared session secret if and only if ke3 is valid.
def ServerFinish(ke3):
return AuthServerFinalize(ke3)
</pre><a href="#section-6.2.4-2" class="pilcrow"></a>
</div>
<p id="section-6.2.4-3">This function <span class="bcp14">MUST NOT</span> return the <code>session_key</code> value if the client authentication
material is invalid and may instead return an appropriate error message, such as
<code>ClientAuthenticationError</code>, which is invoked from <code>AuthServerFinalize</code>.<a href="#section-6.2.4-3" class="pilcrow"></a></p>
</section>
</div>
</section>
</div>
<div id="cred-retrieval">
<section id="section-6.3">
<h3 id="name-credential-retrieval">
<a href="#section-6.3" class="section-number selfRef">6.3. </a><a href="#name-credential-retrieval" class="section-name selfRef">Credential Retrieval</a>
</h3>
<p id="section-6.3-1">This section describes the sub-protocol run during authentication to retrieve and
recover the client credentials.<a href="#section-6.3-1" class="pilcrow"></a></p>
<div id="credential-retrieval-messages">
<section id="section-6.3.1">
<h4 id="name-credential-retrieval-messag">
<a href="#section-6.3.1" class="section-number selfRef">6.3.1. </a><a href="#name-credential-retrieval-messag" class="section-name selfRef">Credential Retrieval Messages</a>
</h4>
<p id="section-6.3.1-1">This section describes the <code>CredentialRequest</code> and <code>CredentialResponse</code> messages exchanged
between client and server to perform credential retrieval.<a href="#section-6.3.1-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.3.1-2">
<pre>
struct {
uint8 blinded_message[Noe];
} CredentialRequest;
</pre><a href="#section-6.3.1-2" class="pilcrow"></a>
</div>
<span class="break"></span><dl class="dlParallel" id="section-6.3.1-3">
<dt id="section-6.3.1-3.1">blinded_message:</dt>
<dd style="margin-left: 1.5em" id="section-6.3.1-3.2">A serialized OPRF group element.<a href="#section-6.3.1-3.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<div class="sourcecode" id="section-6.3.1-4">
<pre>
struct {
uint8 evaluated_message[Noe];
uint8 masking_nonce[Nn];
uint8 masked_response[Npk + Nn + Nm];
} CredentialResponse;
</pre><a href="#section-6.3.1-4" class="pilcrow"></a>
</div>
<span class="break"></span><dl class="dlParallel" id="section-6.3.1-5">
<dt id="section-6.3.1-5.1">evaluated_message:</dt>
<dd style="margin-left: 1.5em" id="section-6.3.1-5.2">A serialized OPRF group element.<a href="#section-6.3.1-5.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6.3.1-5.3">masking_nonce:</dt>
<dd style="margin-left: 1.5em" id="section-6.3.1-5.4">A nonce used for the confidentiality of
the <code>masked_response</code> field.<a href="#section-6.3.1-5.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6.3.1-5.5">
<code>masked_response</code>:</dt>
<dd style="margin-left: 1.5em" id="section-6.3.1-5.6">An encrypted form of the server's
public key and the client's <code>Envelope</code> structure.<a href="#section-6.3.1-5.6" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
</section>
</div>
<div id="credential-retrieval-functions">
<section id="section-6.3.2">
<h4 id="name-credential-retrieval-functi">
<a href="#section-6.3.2" class="section-number selfRef">6.3.2. </a><a href="#name-credential-retrieval-functi" class="section-name selfRef">Credential Retrieval Functions</a>
</h4>
<p id="section-6.3.2-1">This section describes the <code>CreateCredentialRequest</code>, <code>CreateCredentialResponse</code>,
and <code>RecoverCredentials</code> functions used for credential retrieval.<a href="#section-6.3.2-1" class="pilcrow"></a></p>
<div id="create-credential-request">
<section id="section-6.3.2.1">
<h5 id="name-createcredentialrequest">
<a href="#section-6.3.2.1" class="section-number selfRef">6.3.2.1. </a><a href="#name-createcredentialrequest" class="section-name selfRef">CreateCredentialRequest</a>
</h5>
<p id="section-6.3.2.1-1">The <code>CreateCredentialRequest</code> is used by the client to initiate the credential
retrieval process, and it produces a <code>CredentialRequest</code> message and OPRF state.
Like <code>CreateRegistrationRequest</code>, this function can fail with an <code>InvalidInputError</code>
error with negligible probability. However, this should not occur since
registration (via <code>CreateRegistrationRequest</code>) will fail when provided the same
password input.<a href="#section-6.3.2.1-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.3.2.1-2">
<pre>
CreateCredentialRequest
Input:
- password, an opaque byte string containing the client's password.
Output:
- request, a CredentialRequest structure.
- blind, an OPRF scalar value.
Exceptions:
- InvalidInputError, when Blind fails
def CreateCredentialRequest(password):
(blind, blinded_element) = Blind(password)
blinded_message = SerializeElement(blinded_element)
request = CredentialRequest {
blinded_message
}
return (request, blind)
</pre><a href="#section-6.3.2.1-2" class="pilcrow"></a>
</div>
</section>
</div>
<div id="create-credential-response">
<section id="section-6.3.2.2">
<h5 id="name-createcredentialresponse">
<a href="#section-6.3.2.2" class="section-number selfRef">6.3.2.2. </a><a href="#name-createcredentialresponse" class="section-name selfRef">CreateCredentialResponse</a>
</h5>
<p id="section-6.3.2.2-1">The <code>CreateCredentialResponse</code> function is used by the server to process the client's
<code>CredentialRequest</code> message and complete the credential retrieval process, producing
a <code>CredentialResponse</code>.<a href="#section-6.3.2.2-1" class="pilcrow"></a></p>
<p id="section-6.3.2.2-2">There are two scenarios to handle for the construction of a <code>CredentialResponse</code>
object: either the <code>record</code> for the client exists (corresponding to a properly
registered client) or it was never created (corresponding to an unregistered
client identity, possibly the result of an enumeration attack attempt).<a href="#section-6.3.2.2-2" class="pilcrow"></a></p>
<p id="section-6.3.2.2-3">In the case of an existing <code>record</code> with the corresponding identifier
<code>credential_identifier</code>, the server invokes the following function to
produce a <code>CredentialResponse</code>:<a href="#section-6.3.2.2-3" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.3.2.2-4">
<pre>
CreateCredentialResponse
Input:
- request, a CredentialRequest structure.
- server_public_key, the public key of the server.
- record, an instance of RegistrationRecord which is the server's
output from registration.
- credential_identifier, an identifier that uniquely represents
the credential.
- oprf_seed, the server-side seed of Nh bytes used to generate
an oprf_key.
Output:
- response, a CredentialResponse structure.
Exceptions:
- DeserializeError, when OPRF element deserialization fails.
def CreateCredentialResponse(request, server_public_key, record,
credential_identifier, oprf_seed):
seed =
Expand(oprf_seed, concat(credential_identifier, "OprfKey"), Nok)
(oprf_key, _) = DeriveKeyPair(seed, "OPAQUE-DeriveKeyPair")
blinded_element = DeserializeElement(request.blinded_message)
evaluated_element = BlindEvaluate(oprf_key, blinded_element)
evaluated_message = SerializeElement(evaluated_element)
masking_nonce = random(Nn)
credential_response_pad = Expand(record.masking_key,
concat(masking_nonce,
"CredentialResponsePad"),
Npk + Nn + Nm)
masked_response = xor(credential_response_pad,
concat(server_public_key, record.envelope))
response = CredentialResponse {
evaluated_message,
masking_nonce,
masked_response
}
return response
</pre><a href="#section-6.3.2.2-4" class="pilcrow"></a>
</div>
<p id="section-6.3.2.2-5">In the case of a <code>record</code> that does not exist and if client enumeration prevention is desired,
the server <span class="bcp14">MUST</span> respond to the credential request to fake the existence of the <code>record</code>.
The server <span class="bcp14">SHOULD</span> invoke the <code>CreateCredentialResponse</code> function with a fake client <code>record</code>
argument that is configured so that:<a href="#section-6.3.2.2-5" class="pilcrow"></a></p>
<ul class="normal">
<li class="normal" id="section-6.3.2.2-6.1">
<p id="section-6.3.2.2-6.1.1"><code>record.client_public_key</code> is set to a randomly generated public key of length <code>Npk</code><a href="#section-6.3.2.2-6.1.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-6.3.2.2-6.2">
<p id="section-6.3.2.2-6.2.1"><code>record.masking_key</code> is set to a random byte string of length <code>Nh</code><a href="#section-6.3.2.2-6.2.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-6.3.2.2-6.3">
<p id="section-6.3.2.2-6.3.1"><code>record.envelope</code> is set to the byte string consisting only of zeros of length <code>Nn + Nm</code><a href="#section-6.3.2.2-6.3.1" class="pilcrow"></a></p>
</li>
</ul>
<p id="section-6.3.2.2-7">It is <span class="bcp14">RECOMMENDED</span> that a fake client <code>record</code> is created once (e.g., as the first user <code>record</code>
of the application) and then stored alongside legitimate client <code>records</code> to serve
subsequent client requests. This allows servers to retrieve the <code>record</code> in a time comparable
to that of a legitimate client <code>record</code>.<a href="#section-6.3.2.2-7" class="pilcrow"></a></p>
<p id="section-6.3.2.2-8">Note that the responses output by either scenario are indistinguishable to an adversary
that is unable to guess the registered password for the client corresponding to <code>credential_identifier</code>.<a href="#section-6.3.2.2-8" class="pilcrow"></a></p>
</section>
</div>
<div id="recover-credentials">
<section id="section-6.3.2.3">
<h5 id="name-recovercredentials">
<a href="#section-6.3.2.3" class="section-number selfRef">6.3.2.3. </a><a href="#name-recovercredentials" class="section-name selfRef">RecoverCredentials</a>
</h5>
<p id="section-6.3.2.3-1">The <code>RecoverCredentials</code> function is used by the client to process the server's
<code>CredentialResponse</code> message and produce the client's private key, server public
key, and the <code>export_key</code>.<a href="#section-6.3.2.3-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.3.2.3-2">
<pre>
RecoverCredentials
Input:
- password, an opaque byte string containing the client's password.
- blind, an OPRF scalar value.
- response, a CredentialResponse structure.
- server_identity, The optional encoded server identity.
- client_identity, The encoded client identity.
Output:
- client_private_key, the encoded client private key for
the AKE protocol.
- cleartext_credentials, a CleartextCredentials structure.
- export_key, an additional client key.
Exceptions:
- DeserializeError, when OPRF element deserialization fails.
def RecoverCredentials(password, blind, response,
server_identity, client_identity):
evaluated_element = DeserializeElement(response.evaluated_message)
oprf_output = Finalize(password, blind, evaluated_element)
stretched_oprf_output = Stretch(oprf_output)
randomized_password =
Extract("", concat(oprf_output, stretched_oprf_output))
masking_key = Expand(randomized_password, "MaskingKey", Nh)
credential_response_pad =
Expand(masking_key,
concat(response.masking_nonce, "CredentialResponsePad"),
Npk + Nn + Nm)
concat(server_public_key, envelope) =
xor(credential_response_pad, response.masked_response)
(client_private_key, cleartext_credentials, export_key) =
Recover(randomized_password, server_public_key, envelope,
server_identity, client_identity)
return (client_private_key, cleartext_credentials, export_key)
</pre><a href="#section-6.3.2.3-2" class="pilcrow"></a>
</div>
</section>
</div>
</section>
</div>
</section>
</div>
<div id="protocol-3dh">
<section id="section-6.4">
<h3 id="name-3dh-protocol">
<a href="#section-6.4" class="section-number selfRef">6.4. </a><a href="#name-3dh-protocol" class="section-name selfRef">3DH Protocol</a>
</h3>
<p id="section-6.4-1">This section describes the authenticated key exchange protocol for OPAQUE using
3DH, a 3-message AKE that satisfies the forward secrecy and KCI properties
discussed in <a href="#security-considerations" class="auto internal xref">Section 10</a>.<a href="#section-6.4-1" class="pilcrow"></a></p>
<p id="section-6.4-2">The client AKE state <code>ClientAkeState</code> mentioned in <a href="#online-phase" class="auto internal xref">Section 6</a> has the
following fields:<a href="#section-6.4-2" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-6.4-3">
<dt id="section-6.4-3.1">client_secret:</dt>
<dd style="margin-left: 1.5em" id="section-6.4-3.2">An opaque byte string of length <code>Nsk</code>.<a href="#section-6.4-3.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6.4-3.3">ke1:</dt>
<dd style="margin-left: 1.5em" id="section-6.4-3.4">A value of type <code>KE1</code>.<a href="#section-6.4-3.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<p id="section-6.4-4">The server AKE state <code>ServerAkeState</code> mentioned in <a href="#online-phase" class="auto internal xref">Section 6</a> has the
following fields:<a href="#section-6.4-4" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-6.4-5">
<dt id="section-6.4-5.1">expected_client_mac:</dt>
<dd style="margin-left: 1.5em" id="section-6.4-5.2">An opaque byte string of length <code>Nm</code>.<a href="#section-6.4-5.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6.4-5.3">
<code>session_key</code>:</dt>
<dd style="margin-left: 1.5em" id="section-6.4-5.4">An opaque byte string of length <code>Nx</code>.<a href="#section-6.4-5.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<p id="section-6.4-6">Sections <a href="#ake-client" class="auto internal xref">6.4.3</a> and <a href="#ake-server" class="auto internal xref">6.4.4</a> specify the inner workings of client and
server functions, respectively.<a href="#section-6.4-6" class="pilcrow"></a></p>
<div id="key-creation">
<section id="section-6.4.1">
<h4 id="name-3dh-key-exchange-functions">
<a href="#section-6.4.1" class="section-number selfRef">6.4.1. </a><a href="#name-3dh-key-exchange-functions" class="section-name selfRef">3DH Key Exchange Functions</a>
</h4>
<p id="section-6.4.1-1">We assume the following functions exist for all Diffie-Hellman key exchange
variants:<a href="#section-6.4.1-1" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-6.4.1-2">
<dt id="section-6.4.1-2.1">DeriveDiffieHellmanKeyPair(seed):</dt>
<dd style="margin-left: 1.5em" id="section-6.4.1-2.2">Derive a private and
public Diffie-Hellman key pair deterministically from the input
<code>seed</code>. The type of the private key depends on the
implementation, whereas the type of the public key is a byte
string of <code>Npk</code> bytes.<a href="#section-6.4.1-2.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6.4.1-2.3">DiffieHellman(k, B):</dt>
<dd style="margin-left: 1.5em" id="section-6.4.1-2.4">A function that performs the
Diffie-Hellman operation between the private input <code>k</code> and
public input <code>B</code>. The output of this function is a unique,
fixed-length byte string.<a href="#section-6.4.1-2.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
<p id="section-6.4.1-3">It is <span class="bcp14">RECOMMENDED</span> to use Elliptic Curve Diffie-Hellman for this key exchange protocol.
Implementations for recommended groups in <a href="#configurations" class="auto internal xref">Section 7</a>, as well as groups
covered by test vectors in <a href="#test-vectors" class="auto internal xref">Appendix C</a>, are described in the following sections.<a href="#section-6.4.1-3" class="pilcrow"></a></p>
<div id="dh-ristretto255">
<section id="section-6.4.1.1">
<h5 id="name-3dh-ristretto255">
<a href="#section-6.4.1.1" class="section-number selfRef">6.4.1.1. </a><a href="#name-3dh-ristretto255" class="section-name selfRef">3DH ristretto255</a>
</h5>
<p id="section-6.4.1.1-1">This section describes the implementation of the Diffie-Hellman key exchange functions based on ristretto255
as defined in <span>[<a href="#RFC9496" class="cite xref">RFC9496</a>]</span>.<a href="#section-6.4.1.1-1" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-6.4.1.1-2">
<dt id="section-6.4.1.1-2.1">DeriveDiffieHellmanKeyPair(seed):</dt>
<dd style="margin-left: 1.5em" id="section-6.4.1.1-2.2">This function is
implemented as DeriveKeyPair(seed,
"OPAQUE-DeriveDiffieHellmanKeyPair"), where DeriveKeyPair is as
specified in <span><a href="https://rfc-editor.org/rfc/rfc9497#section-3.2" class="relref">Section 3.2</a> of [<a href="#RFC9497" class="cite xref">RFC9497</a>]</span>. The public
value from DeriveKeyPair is encoded using SerializeElement from
<span><a href="https://rfc-editor.org/rfc/rfc9497#section-2.1" class="relref">Section 2.1</a> of [<a href="#RFC9497" class="cite xref">RFC9497</a>]</span>.<a href="#section-6.4.1.1-2.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6.4.1.1-2.3">DiffieHellman(k, B):</dt>
<dd style="margin-left: 1.5em" id="section-6.4.1.1-2.4">Implemented as scalar
multiplication as described in <span>[<a href="#RFC9496" class="cite xref">RFC9496</a>]</span> after decoding
<code>B</code> from its encoded input using the Decode function in
<span><a href="https://rfc-editor.org/rfc/rfc9496#section-4.3.1" class="relref">Section 4.3.1</a> of [<a href="#RFC9496" class="cite xref">RFC9496</a>]</span>. The output is
then encoded using the SerializeElement function of the OPRF
group described in <span><a href="https://rfc-editor.org/rfc/rfc9497#section-2.1" class="relref">Section 2.1</a> of [<a href="#RFC9497" class="cite xref">RFC9497</a>]</span>.<a href="#section-6.4.1.1-2.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
</section>
</div>
<div id="dh-p-256">
<section id="section-6.4.1.2">
<h5 id="name-3dh-p-256">
<a href="#section-6.4.1.2" class="section-number selfRef">6.4.1.2. </a><a href="#name-3dh-p-256" class="section-name selfRef">3DH P-256</a>
</h5>
<p id="section-6.4.1.2-1">This section describes the implementation of the Diffie-Hellman key exchange functions based on NIST P-256
as defined in <span>[<a href="#NISTCurves" class="cite xref">NISTCurves</a>]</span>.<a href="#section-6.4.1.2-1" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-6.4.1.2-2">
<dt id="section-6.4.1.2-2.1">DeriveDiffieHellmanKeyPair(seed):</dt>
<dd style="margin-left: 1.5em" id="section-6.4.1.2-2.2">As defined in
<a href="#dh-ristretto255" class="auto internal xref">Section 6.4.1.1</a>.<a href="#section-6.4.1.2-2.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6.4.1.2-2.3">DiffieHellman(k, B):</dt>
<dd style="margin-left: 1.5em" id="section-6.4.1.2-2.4">Implemented as
scalar multiplication as described in <span>[<a href="#NISTCurves" class="cite xref">NISTCurves</a>]</span> after decoding <code>B</code>
from its encoded input using the compressed
Octet-String-to-Elliptic-Curve-Point method
according to <span>[<a href="#NISTCurves" class="cite xref">NISTCurves</a>]</span>. The
output is then encoded using the SerializeElement
function of the OPRF group described in <span><a href="https://rfc-editor.org/rfc/rfc9497#section-2.1" class="relref">Section 2.1</a> of [<a href="#RFC9497" class="cite xref">RFC9497</a>]</span>.<a href="#section-6.4.1.2-2.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
</section>
</div>
<div id="dh-curve25519">
<section id="section-6.4.1.3">
<h5 id="name-3dh-curve25519">
<a href="#section-6.4.1.3" class="section-number selfRef">6.4.1.3. </a><a href="#name-3dh-curve25519" class="section-name selfRef">3DH Curve25519</a>
</h5>
<p id="section-6.4.1.3-1">This section describes the implementation of the Diffie-Hellman key exchange functions based on Curve25519
as defined in <span>[<a href="#RFC7748" class="cite xref">RFC7748</a>]</span>.<a href="#section-6.4.1.3-1" class="pilcrow"></a></p>
<span class="break"></span><dl class="dlParallel" id="section-6.4.1.3-2">
<dt id="section-6.4.1.3-2.1">DeriveDiffieHellmanKeyPair(seed):</dt>
<dd style="margin-left: 1.5em" id="section-6.4.1.3-2.2">This function is
implemented by returning the private key <code>k</code> based on
<code>seed</code> (of length <code>Nseed = 32</code> bytes) as described in
<span><a href="https://rfc-editor.org/rfc/rfc7748#section-5" class="relref">Section 5</a> of [<a href="#RFC7748" class="cite xref">RFC7748</a>]</span>, as well as the result of
DiffieHellman(k, B), where B is the base point of
Curve25519.<a href="#section-6.4.1.3-2.2" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
<dt id="section-6.4.1.3-2.3">DiffieHellman(k, B):</dt>
<dd style="margin-left: 1.5em" id="section-6.4.1.3-2.4">Implemented using the X25519
function in <span><a href="https://rfc-editor.org/rfc/rfc7748#section-5" class="relref">Section 5</a> of [<a href="#RFC7748" class="cite xref">RFC7748</a>]</span>. The output
is then used raw with no processing.<a href="#section-6.4.1.3-2.4" class="pilcrow"></a>
</dd>
<dd class="break"></dd>
</dl>
</section>
</div>
</section>
</div>
<div id="key-schedule-functions">
<section id="section-6.4.2">
<h4 id="name-key-schedule-functions">
<a href="#section-6.4.2" class="section-number selfRef">6.4.2. </a><a href="#name-key-schedule-functions" class="section-name selfRef">Key Schedule Functions</a>
</h4>
<p id="section-6.4.2-1">This section contains functions used for the AKE key schedule.<a href="#section-6.4.2-1" class="pilcrow"></a></p>
<div id="transcript-functions">
<section id="section-6.4.2.1">
<h5 id="name-transcript-functions">
<a href="#section-6.4.2.1" class="section-number selfRef">6.4.2.1. </a><a href="#name-transcript-functions" class="section-name selfRef">Transcript Functions</a>
</h5>
<p id="section-6.4.2.1-1">The OPAQUE-3DH key derivation procedures make use of the functions below that are repurposed from TLS 1.3 <span>[<a href="#RFC8446" class="cite xref">RFC8446</a>]</span>.<a href="#section-6.4.2.1-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.4.2.1-2">
<pre>
Expand-Label(Secret, Label, Context, Length) =
Expand(Secret, CustomLabel, Length)
</pre><a href="#section-6.4.2.1-2" class="pilcrow"></a>
</div>
<p id="section-6.4.2.1-3">Where CustomLabel is specified and encoded (following <span><a href="https://rfc-editor.org/rfc/rfc8446#section-3.4" class="relref">Section 3.4</a> of [<a href="#RFC8446" class="cite xref">RFC8446</a>]</span>) as:<a href="#section-6.4.2.1-3" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.4.2.1-4">
<pre>
struct {
uint16 length = Length;
opaque label&lt;8..255&gt; = "OPAQUE-" + Label;
uint8 context&lt;0..255&gt; = Context;
} CustomLabel;
Derive-Secret(Secret, Label, Transcript-Hash) =
Expand-Label(Secret, Label, Transcript-Hash, Nx)
</pre><a href="#section-6.4.2.1-4" class="pilcrow"></a>
</div>
<p id="section-6.4.2.1-5">Note that the <code>Label</code> parameter is not a NULL-terminated string.<a href="#section-6.4.2.1-5" class="pilcrow"></a></p>
<p id="section-6.4.2.1-6">OPAQUE-3DH can optionally include application-specific, shared <code>context</code> information in the
transcript, such as configuration parameters or application-specific information, e.g.,
"appXYZ-v1.2.3".<a href="#section-6.4.2.1-6" class="pilcrow"></a></p>
<p id="section-6.4.2.1-7">The OPAQUE-3DH key schedule requires a <code>preamble</code>, which is computed as follows.<a href="#section-6.4.2.1-7" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.4.2.1-8">
<pre>
Preamble
Parameters:
- context, optional shared context information.
Input:
- client_identity, the optional encoded client identity, which is set
to client_public_key if not specified.
- ke1, a KE1 message structure.
- server_identity, the optional encoded server identity, which is set
to server_public_key if not specified.
- credential_response, the corresponding field on the KE2 structure.
- server_nonce, the corresponding field on the AuthResponse
structure.
- server_public_keyshare, the corresponding field on the AuthResponse
structure.
Output:
- preamble, the protocol transcript with identities and messages.
def Preamble(client_identity, ke1, server_identity,
credential_response, server_nonce,
server_public_keyshare):
preamble = concat("OPAQUEv1-",
I2OSP(len(context), 2), context,
I2OSP(len(client_identity), 2), client_identity,
ke1,
I2OSP(len(server_identity), 2), server_identity,
credential_response,
server_nonce,
server_public_keyshare)
return preamble
</pre><a href="#section-6.4.2.1-8" class="pilcrow"></a>
</div>
</section>
</div>
<div id="shared-secret-derivation">
<section id="section-6.4.2.2">
<h5 id="name-shared-secret-derivation">
<a href="#section-6.4.2.2" class="section-number selfRef">6.4.2.2. </a><a href="#name-shared-secret-derivation" class="section-name selfRef">Shared Secret Derivation</a>
</h5>
<p id="section-6.4.2.2-1">The OPAQUE-3DH shared secret derived during the key exchange protocol is
computed using the following helper function.<a href="#section-6.4.2.2-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.4.2.2-2">
<pre>
DeriveKeys
Input:
- ikm, input key material.
- preamble, the protocol transcript with identities and messages.
Output:
- Km2, a MAC authentication key.
- Km3, a MAC authentication key.
- session_key, the shared session secret.
def DeriveKeys(ikm, preamble):
prk = Extract("", ikm)
handshake_secret =
Derive-Secret(prk, "HandshakeSecret",Hash(preamble))
session_key =
Derive-Secret(prk, "SessionKey", Hash(preamble))
Km2 = Derive-Secret(handshake_secret, "ServerMAC", "")
Km3 = Derive-Secret(handshake_secret, "ClientMAC", "")
return (Km2, Km3, session_key)
</pre><a href="#section-6.4.2.2-2" class="pilcrow"></a>
</div>
</section>
</div>
</section>
</div>
<div id="ake-client">
<section id="section-6.4.3">
<h4 id="name-3dh-client-functions">
<a href="#section-6.4.3" class="section-number selfRef">6.4.3. </a><a href="#name-3dh-client-functions" class="section-name selfRef">3DH Client Functions</a>
</h4>
<p id="section-6.4.3-1">The <code>AuthClientStart</code> function is used by the client to create a
<code>KE1</code> structure.<a href="#section-6.4.3-1" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.4.3-2">
<pre>
AuthClientStart
Parameters:
- Nn, the nonce length.
State:
- state, a ClientAkeState structure.
Input:
- credential_request, a CredentialRequest structure.
Output:
- ke1, a KE1 structure.
def AuthClientStart(credential_request):
client_nonce = random(Nn)
client_keyshare_seed = random(Nseed)
(client_secret, client_public_keyshare) =
DeriveDiffieHellmanKeyPair(client_keyshare_seed)
auth_request = AuthRequest {
client_nonce,
client_public_keyshare
}
ke1 = KE1 {
credential_request,
auth_request
}
state.client_secret = client_secret
state.ke1 = ke1
return ke1
</pre><a href="#section-6.4.3-2" class="pilcrow"></a>
</div>
<p id="section-6.4.3-3">The <code>AuthClientFinalize</code> function is used by the client to create a <code>KE3</code>
message and output <code>session_key</code> using the server's <code>KE2</code> message and
recovered credential information.<a href="#section-6.4.3-3" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.4.3-4">
<pre>
AuthClientFinalize
State:
- state, a ClientAkeState structure.
Input:
- cleartext_credentials, a CleartextCredentials structure.
- client_private_key, the client's private key.
- ke2, a KE2 message structure.
Output:
- ke3, a KE3 structure.
- session_key, the shared session secret.
Exceptions:
- ServerAuthenticationError, the handshake fails.
def AuthClientFinalize(cleartext_credentials,
client_private_key, ke2):
dh1 = DiffieHellman(state.client_secret,
ke2.auth_response.server_public_keyshare)
dh2 = DiffieHellman(state.client_secret,
cleartext_credentials.server_public_key)
dh3 = DiffieHellman(client_private_key,
ke2.auth_response.server_public_keyshare)
ikm = concat(dh1, dh2, dh3)
preamble = Preamble(cleartext_credentials.client_identity,
state.ke1,
cleartext_credentials.server_identity,
ke2.credential_response,
ke2.auth_response.server_nonce,
ke2.auth_response.server_public_keyshare)
Km2, Km3, session_key = DeriveKeys(ikm, preamble)
expected_server_mac = MAC(Km2, Hash(preamble))
if !ct_equal(ke2.auth_response.server_mac, expected_server_mac),
raise ServerAuthenticationError
client_mac = MAC(Km3, Hash(concat(preamble, expected_server_mac)))
ke3 = KE3 {
client_mac
}
return (ke3, session_key)
</pre><a href="#section-6.4.3-4" class="pilcrow"></a>
</div>
</section>
</div>
<div id="ake-server">
<section id="section-6.4.4">
<h4 id="name-3dh-server-functions">
<a href="#section-6.4.4" class="section-number selfRef">6.4.4. </a><a href="#name-3dh-server-functions" class="section-name selfRef">3DH Server Functions</a>
</h4>
<p id="section-6.4.4-1">The <code>AuthServerRespond</code> function is used by the server to process the client's
<code>KE1</code> message and public credential information to create a <code>KE2</code> message.<a href="#section-6.4.4-1" class="pilcrow"></a></p>
<div class="breakable sourcecode" id="section-6.4.4-2">
<pre>
AuthServerRespond
Parameters:
- Nn, the nonce length.
State:
- state, a ServerAkeState structure.
Input:
- cleartext_credentials, a CleartextCredentials structure.
- server_private_key, the server's private key.
- client_public_key, the client's public key.
- ke1, a KE1 message structure.
Output:
- auth_response, an AuthResponse structure.
def AuthServerRespond(cleartext_credentials, server_private_key,
client_public_key, ke1, credential_response):
server_nonce = random(Nn)
server_keyshare_seed = random(Nseed)
(server_private_keyshare, server_public_keyshare) =
DeriveDiffieHellmanKeyPair(server_keyshare_seed)
preamble = Preamble(cleartext_credentials.client_identity,
ke1,
cleartext_credentials.server_identity,
credential_response,
server_nonce,
server_public_keyshare)
dh1 = DiffieHellman(server_private_keyshare,
ke1.auth_request.client_public_keyshare)
dh2 = DiffieHellman(server_private_key,
ke1.auth_request.client_public_keyshare)
dh3 = DiffieHellman(server_private_keyshare,
client_public_key)
ikm = concat(dh1, dh2, dh3)
Km2, Km3, session_key = DeriveKeys(ikm, preamble)
server_mac = MAC(Km2, Hash(preamble))
state.expected_client_mac =
MAC(Km3, Hash(concat(preamble, server_mac)))
state.session_key = session_key
auth_response = AuthResponse {
server_nonce,
server_public_keyshare,
server_mac
}
return auth_response
</pre><a href="#section-6.4.4-2" class="pilcrow"></a>
</div>
<p id="section-6.4.4-3">The <code>AuthServerFinalize</code> function is used by the server to process the client's
<code>KE3</code> message and output the final <code>session_key</code>.<a href="#section-6.4.4-3" class="pilcrow"></a></p>
<div class="sourcecode" id="section-6.4.4-4">
<pre>
AuthServerFinalize
State:
- state, a ServerAkeState structure.
Input:
- ke3, a KE3 structure.
Output:
- session_key, the shared session secret if and only if ke3 is valid.
Exceptions:
- ClientAuthenticationError, the handshake fails.
def AuthServerFinalize(ke3):
if !ct_equal(ke3.client_mac, state.expected_client_mac):
raise ClientAuthenticationError
return state.session_key
</pre><a href="#section-6.4.4-4" class="pilcrow"></a>
</div>
</section>
</div>
</section>
</div>
</section>
</div>
<div id="configurations">
<section id="section-7">
<h2 id="name-configurations">
<a href="#section-7" class="section-number selfRef">7. </a><a href="#name-configurations" class="section-name selfRef">Configurations</a>
</h2>
<p id="section-7-1">An OPAQUE-3DH configuration is a tuple (OPRF, KDF, MAC, Hash, KSF, Group, Context)
such that the following conditions are met:<a href="#section-7-1" class="pilcrow"></a></p>
<ul class="normal">
<li class="normal" id="section-7-2.1">
<p id="section-7-2.1.1">The OPRF protocol uses the <code>modeOPRF</code> configuration in <span><a href="https://rfc-editor.org/rfc/rfc9497#section-3.1" class="relref">Section 3.1</a> of [<a href="#RFC9497" class="cite xref">RFC9497</a>]</span> and
implements the interface in <a href="#dependencies" class="auto internal xref">Section 2</a>. Examples include ristretto255-SHA512
and P256-SHA256.<a href="#section-7-2.1.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-7-2.2">
<p id="section-7-2.2.1">The KDF, MAC, and Hash functions implement the interfaces in <a href="#dependencies" class="auto internal xref">Section 2</a>.
Examples include HKDF <span>[<a href="#RFC5869" class="cite xref">RFC5869</a>]</span> for the KDF, HMAC <span>[<a href="#RFC2104" class="cite xref">RFC2104</a>]</span> for the MAC,
and SHA-256 and SHA-512 for the Hash functions. If an extensible output function
such as SHAKE128 <span>[<a href="#FIPS202" class="cite xref">FIPS202</a>]</span> is used, then the output length <code>Nh</code> <span class="bcp14">MUST</span> be chosen
to align with the target security level of the OPAQUE configuration. For example,
if the target security parameter for the configuration is 128 bits, then <code>Nh</code> <span class="bcp14">SHOULD</span>
be at least 32 bytes.<a href="#section-7-2.2.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-7-2.3">
<p id="section-7-2.3.1">The KSF is determined by the application and implements the interface in
<a href="#dependencies" class="auto internal xref">Section 2</a>. As noted, collision resistance is required. Examples for KSF
include Argon2id <span>[<a href="#RFC9106" class="cite xref">RFC9106</a>]</span>, scrypt <span>[<a href="#RFC7914" class="cite xref">RFC7914</a>]</span>, and PBKDF2
<span>[<a href="#RFC8018" class="cite xref">RFC8018</a>]</span> with fixed parameter choices. See <a href="#app-considerations" class="auto internal xref">Section 8</a>
for more information about this choice of function.<a href="#section-7-2.3.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-7-2.4">
<p id="section-7-2.4.1">The Group mode identifies the group used in the OPAQUE-3DH AKE. This <span class="bcp14">SHOULD</span>
match that of the OPRF. For example, if the OPRF is ristretto255-SHA512,
then Group <span class="bcp14">SHOULD</span> be ristretto255.<a href="#section-7-2.4.1" class="pilcrow"></a></p>
</li>
</ul>
<p id="section-7-3">Context is the shared parameter used to construct the <code>preamble</code> in <a href="#transcript-functions" class="auto internal xref">Section 6.4.2.1</a>.
This parameter <span class="bcp14">SHOULD</span> include any application-specific configuration information or
parameters that are needed to prevent cross-protocol or downgrade attacks.<a href="#section-7-3" class="pilcrow"></a></p>
<p id="section-7-4">Absent an application-specific profile, the following configurations are <span class="bcp14">RECOMMENDED</span>:<a href="#section-7-4" class="pilcrow"></a></p>
<ul class="normal">
<li class="normal" id="section-7-5.1">
<p id="section-7-5.1.1">ristretto255-SHA512, HKDF-SHA-512, HMAC-SHA-512, SHA-512,
Argon2id(S = zeroes(16), p = 4, T = <code>Nh</code>, m = 2^21, t = 1, v = 0x13, K = nil, X = nil, y = 2), ristretto255<a href="#section-7-5.1.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-7-5.2">
<p id="section-7-5.2.1">P256-SHA256, HKDF-SHA-256, HMAC-SHA-256, SHA-256,
Argon2id(S = zeroes(16), p = 4, T = <code>Nh</code>, m = 2^21, t = 1, v = 0x13, K = nil, X = nil, y = 2), P-256<a href="#section-7-5.2.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-7-5.3">
<p id="section-7-5.3.1">P256-SHA256, HKDF-SHA-256, HMAC-SHA-256, SHA-256,
scrypt(S = zeroes(16), N = 32768, r = 8, p = 1, dkLen = 32), P-256<a href="#section-7-5.3.1" class="pilcrow"></a></p>
</li>
</ul>
<p id="section-7-6">The above recommended configurations target 128-bit security.<a href="#section-7-6" class="pilcrow"></a></p>
<p id="section-7-7">Future configurations may specify different combinations of dependent algorithms
with the following considerations:<a href="#section-7-7" class="pilcrow"></a></p>
<ol start="1" type="1" class="normal type-1" id="section-7-8">
<li id="section-7-8.1">
<p id="section-7-8.1.1">The size of AKE public and private keys -- <code>Npk</code> and <code>Nsk</code>, respectively -- must adhere
to the output length limitations of the KDF Expand function. If HKDF is used, this means
<code>Npk</code>, <code>Nsk</code> &lt;= 255 * <code>Nx</code>, where <code>Nx</code> is the output size of the underlying hash function.
See <span>[<a href="#RFC5869" class="cite xref">RFC5869</a>]</span> for details.<a href="#section-7-8.1.1" class="pilcrow"></a></p>
</li>
<li id="section-7-8.2">
<p id="section-7-8.2.1">The output size of the Hash function <span class="bcp14">SHOULD</span> be long enough to produce a key for
MAC of suitable length. For example, if MAC is HMAC-SHA256, then <code>Nh</code> could be
32 bytes.<a href="#section-7-8.2.1" class="pilcrow"></a></p>
</li>
</ol>
</section>
</div>
<div id="app-considerations">
<section id="section-8">
<h2 id="name-application-considerations">
<a href="#section-8" class="section-number selfRef">8. </a><a href="#name-application-considerations" class="section-name selfRef">Application Considerations</a>
</h2>
<p id="section-8-1">Beyond choosing an appropriate configuration, there are several parameters that applications can use to control OPAQUE:<a href="#section-8-1" class="pilcrow"></a></p>
<ul class="normal">
<li class="normal" id="section-8-2.1">
<p id="section-8-2.1.1">Credential identifier: As described in <a href="#registration-phase" class="auto internal xref">Section 5</a>, this is a unique
handle to the client's credential being stored. In applications where there are alternate
client identities that accompany an account, such as a username or email address, this
identifier can be set to those alternate values. For simplicity, applications may choose
to set <code>credential_identifier</code> to be equal to <code>client_identity</code>. Applications
<span class="bcp14">MUST NOT</span> use the same credential identifier for multiple clients.<a href="#section-8-2.1.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-8-2.2">
<p id="section-8-2.2.1">Context information: As described in <a href="#configurations" class="auto internal xref">Section 7</a>, applications may include
a shared <code>context</code> string that is authenticated as part of the handshake. This parameter
<span class="bcp14">SHOULD</span> include any configuration information or parameters that are needed to prevent
cross-protocol or downgrade attacks. This <code>context</code> information is not sent over the
wire in any key exchange messages. However, applications may choose to send it alongside
key exchange messages if needed for their use case.<a href="#section-8-2.2.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-8-2.3">
<p id="section-8-2.3.1">Client and server identities: As described in <a href="#client-material" class="auto internal xref">Section 4</a>, clients
and servers are identified with their public keys by default. However, applications
may choose alternate identities that are pinned to these public keys. For example,
servers may use a domain name instead of a public key as their identifier.
Absent
alternate notions of identity, applications <span class="bcp14">SHOULD</span> set these identities to nil
and rely solely on public key information.<a href="#section-8-2.3.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-8-2.4">
<p id="section-8-2.4.1">Configuration and envelope updates: Applications may wish to update or change their
configuration or other parameters that affect the client's <code>RegistrationRecord</code> over
time. Some reasons for changing these are to use different cryptographic algorithms,
e.g., a different KSF with improved parameters, or to update key material that is
cryptographically bound to the <code>RegistrationRecord</code>, such as the server's public key
(<code>server_public_key</code>). Any such change will require users to reregister to create a
new <code>RegistrationRecord</code>. Supporting these types of updates can be helpful for applications
that anticipate such changes in their deployment setting.<a href="#section-8-2.4.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-8-2.5">
<p id="section-8-2.5.1">Password hardening parameters: Key stretching is done to help prevent password disclosure
in the event of server compromise; see <a href="#key-stretch" class="auto internal xref">Section 10.8</a>. There is no ideal or default
set of parameters, though relevant specifications for KSFs give some reasonable
defaults.<a href="#section-8-2.5.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-8-2.6">
<p id="section-8-2.6.1">Enumeration prevention: If servers
receive a credential request for a non-existent client, they <span class="bcp14">SHOULD</span> respond with a
"fake" response to prevent active client enumeration attacks as described in <a href="#create-credential-response" class="auto internal xref">Section 6.3.2.2</a>. Servers that
implement this mitigation <span class="bcp14">SHOULD</span> use the same configuration information (such as
the <code>oprf_seed</code>) for all clients; see <a href="#preventing-client-enumeration" class="auto internal xref">Section 10.9</a>. In settings
where this attack is not a concern, servers may choose to not support this functionality.<a href="#section-8-2.6.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-8-2.7">
<p id="section-8-2.7.1">Handling password changes: In the event of a password change, the client and
server can run the registration phase using the new password as a
fresh instance (ensuring to resample all random values). The resulting
registration <code>record</code> can then replace the previous <code>record</code> corresponding to
the client's old password registration.<a href="#section-8-2.7.1" class="pilcrow"></a></p>
</li>
</ul>
</section>
</div>
<div id="implementation-considerations">
<section id="section-9">
<h2 id="name-implementation-consideratio">
<a href="#section-9" class="section-number selfRef">9. </a><a href="#name-implementation-consideratio" class="section-name selfRef">Implementation Considerations</a>
</h2>
<p id="section-9-1">This section documents considerations for OPAQUE implementations. This includes
implementation safeguards and error handling considerations.<a href="#section-9-1" class="pilcrow"></a></p>
<div id="implementation-safeguards">
<section id="section-9.1">
<h3 id="name-implementation-safeguards">
<a href="#section-9.1" class="section-number selfRef">9.1. </a><a href="#name-implementation-safeguards" class="section-name selfRef">Implementation Safeguards</a>
</h3>
<p id="section-9.1-1">Certain information created, exchanged, and processed in OPAQUE is sensitive.
Specifically, all private key material and intermediate values, along with the
outputs of the key exchange phase, are all secret. Implementations should not
retain these values in memory when no longer needed. Moreover, all operations,
particularly the cryptographic and group arithmetic operations, should be
constant-time and independent of the bits of any secrets. This includes any
conditional branching during the creation of the credential response as needed
to mitigate client enumeration attacks.<a href="#section-9.1-1" class="pilcrow"></a></p>
<p id="section-9.1-2">As specified in <a href="#registration-phase" class="auto internal xref">Section 5</a> and <a href="#online-phase" class="auto internal xref">Section 6</a>, OPAQUE only requires
the client password as input to the OPRF for registration and authentication.
However, if <code>client_identity</code> can be bound to the client's registration <code>record</code>
(i.e., the identity will not change during the lifetime of the <code>record</code>),
then an implementation <span class="bcp14">SHOULD</span> incorporate <code>client_identity</code> alongside the
password as input to the OPRF. Furthermore, it is <span class="bcp14">RECOMMENDED</span> to incorporate
<code>server_identity</code> alongside the password as input to the OPRF. These
additions provide domain separation for clients and servers; see
<a href="#security-analysis" class="auto internal xref">Section 10.2</a>.<a href="#section-9.1-2" class="pilcrow"></a></p>
</section>
</div>
<div id="handling-online-guessing-attacks">
<section id="section-9.2">
<h3 id="name-handling-online-guessing-at">
<a href="#section-9.2" class="section-number selfRef">9.2. </a><a href="#name-handling-online-guessing-at" class="section-name selfRef">Handling Online Guessing Attacks</a>
</h3>
<p id="section-9.2-1">Online guessing attacks (against any aPAKE) can be done from
both the client side and the server side. In particular, a malicious server can
attempt to simulate honest responses to learn the client's password.
While this constitutes an exhaustive online attack (as expensive as a guessing
attack from the client side), it can be mitigated when the channel between
client and server is authenticated, e.g., using server-authenticated TLS. In
such cases, these online attacks are limited to clients and the authenticated
server itself. Moreover, such a channel provides privacy of user information,
including identity and envelope values.<a href="#section-9.2-1" class="pilcrow"></a></p>
<p id="section-9.2-2">Additionally, note that a client participating in the online login stage
will learn whether or not authentication is successful after receiving the
<code>KE2</code> message. This means that the server should treat any client which fails to
send a subsequent <code>KE3</code> message as an authentication failure. This can be handled
in applications that wish to track authentication failures by, for example,
assuming by default that any client authentication attempt is a failure unless a <code>KE3</code>
message is received by the server and passes <code>ServerFinish</code> without error.<a href="#section-9.2-2" class="pilcrow"></a></p>
</section>
</div>
<div id="error-considerations">
<section id="section-9.3">
<h3 id="name-error-considerations">
<a href="#section-9.3" class="section-number selfRef">9.3. </a><a href="#name-error-considerations" class="section-name selfRef">Error Considerations</a>
</h3>
<p id="section-9.3-1">Some functions included in this specification are fallible. For example, the
authenticated key exchange protocol may fail because the client's password was
incorrect or the authentication check failed, yielding an error. The explicit
errors generated throughout this specification, along with conditions that lead
to each error, are as follows:<a href="#section-9.3-1" class="pilcrow"></a></p>
<ul class="normal">
<li class="normal" id="section-9.3-2.1">
<p id="section-9.3-2.1.1"><code>EnvelopeRecoveryError</code>: The <code>Envelope</code> <code>Recover</code> function failed to produce any
authentication key material; <a href="#envelope-recovery" class="auto internal xref">Section 4.1.3</a>.<a href="#section-9.3-2.1.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-9.3-2.2">
<p id="section-9.3-2.2.1">ServerAuthenticationError: The client failed to complete the authenticated
key exchange protocol with the server; <a href="#ake-client" class="auto internal xref">Section 6.4.3</a>.<a href="#section-9.3-2.2.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-9.3-2.3">
<p id="section-9.3-2.3.1"><code>ClientAuthenticationError</code>: The server failed to complete the authenticated
key exchange protocol with the client; <a href="#ake-server" class="auto internal xref">Section 6.4.4</a>.<a href="#section-9.3-2.3.1" class="pilcrow"></a></p>
</li>
</ul>
<p id="section-9.3-3">Beyond these explicit errors, OPAQUE implementations can produce implicit errors.
For example, if protocol messages sent between client and server do not match
their expected size, an implementation should produce an error. More generally,
if any protocol message received from the peer is invalid, perhaps because the
message contains an invalid public key (indicated by the AKE DeserializeElement
function failing) or an invalid OPRF element (indicated by the OPRF DeserializeElement),
then an implementation should produce an error.<a href="#section-9.3-3" class="pilcrow"></a></p>
<p id="section-9.3-4">The errors in this document are meant as a guide for implementors. They are not an
exhaustive list of all the errors an implementation might emit. For example, an
implementation might run out of memory.<a href="#section-9.3-4" class="pilcrow"></a></p>
</section>
</div>
</section>
</div>
<div id="security-considerations">
<section id="section-10">
<h2 id="name-security-considerations">
<a href="#section-10" class="section-number selfRef">10. </a><a href="#name-security-considerations" class="section-name selfRef">Security Considerations</a>
</h2>
<p id="section-10-1">OPAQUE is defined as the composition of two functionalities: an OPRF and
an AKE protocol. It can be seen as a "compiler" for transforming any AKE
protocol (with Key Compromise Impersonation (KCI) security and forward secrecy; see <a href="#security-analysis" class="auto internal xref">Section 10.2</a>)
into a secure aPAKE protocol. In OPAQUE, the client derives a private key
during password registration and retrieves this key each time
it needs to authenticate to the server. The OPRF security properties
ensure that only the correct password can unlock the private key
while at the same time avoiding potential offline guessing attacks.
This general composability property provides great flexibility and
enables a variety of OPAQUE instantiations, from optimized
performance to integration with existing authenticated key exchange
protocols such as TLS.<a href="#section-10-1" class="pilcrow"></a></p>
<div id="notable-design-differences">
<section id="section-10.1">
<h3 id="name-notable-design-differences">
<a href="#section-10.1" class="section-number selfRef">10.1. </a><a href="#name-notable-design-differences" class="section-name selfRef">Notable Design Differences</a>
</h3>
<p id="section-10.1-1">The specification as written here differs from the original cryptographic design in <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span>
and the corresponding CFRG document <span>[<a href="#I-D.krawczyk-cfrg-opaque" class="cite xref">Krawczyk20</a>]</span>, both of which were used
as input to the CFRG PAKE competition. This section describes these differences, including
their motivation and explanation as to why they preserve the provable security of OPAQUE based
on <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span>.<a href="#section-10.1-1" class="pilcrow"></a></p>
<p id="section-10.1-2">The following list enumerates important functional differences that were made
as part of the protocol specification process to address application or
implementation considerations.<a href="#section-10.1-2" class="pilcrow"></a></p>
<ul class="normal">
<li class="normal" id="section-10.1-3.1">
<p id="section-10.1-3.1.1">Clients construct envelope contents without revealing the password to the
server, as described in <a href="#registration-phase" class="auto internal xref">Section 5</a>, whereas the servers construct
envelopes in <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span>. This change adds to the security of the protocol.
<span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span> considered the case where the envelope was constructed by the
server for reasons of compatibility with previous Universal Composability (UC) security modeling. <span>[<a href="#HJKW23" class="cite xref">HJKW23</a>]</span>
analyzes the registration phase as specified in this document. This
change was made to support registration flows where the client chooses the
password and wishes to keep it secret from the server, and it is compatible
with the variant in <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span> that was originally analyzed.<a href="#section-10.1-3.1.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-10.1-3.2">
<p id="section-10.1-3.2.1">Envelopes do not contain encrypted credentials. Instead, envelopes contain
information used to derive client private key material for the AKE.
This change improves the assumption behind the protocol by getting rid of
equivocality and random key robustness for the encryption function.
The random-key robustness property defined in <a href="#deps-symmetric" class="auto internal xref">Section 2.2</a> is only
needed for the MAC function. This change was made for two reasons. First, it
reduces the number of bytes stored in envelopes, which is a helpful
improvement for large applications of OPAQUE with many registered users.
Second, it removes the need for client applications to generate private
keys during registration. Instead, this responsibility is handled by OPAQUE,
thereby simplifying the client interface to the protocol.<a href="#section-10.1-3.2.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-10.1-3.3">
<p id="section-10.1-3.3.1">Envelopes are masked with a per-user masking key as a way of preventing
client enumeration attacks. See <a href="#preventing-client-enumeration" class="auto internal xref">Section 10.9</a> for more
details. This extension is not needed for the security of OPAQUE as an aPAKE protocol,
but is only used to provide a defense against enumeration attacks. In the
analysis, the masking key can be simulated as a (pseudo) random key. This
change was made to support real-world use cases where client or user
enumeration is a security (or privacy) risk.<a href="#section-10.1-3.3.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-10.1-3.4">
<p id="section-10.1-3.4.1">Per-user OPRF keys are derived from a client identity and cross-user PRF <code>seed</code>
as a mitigation against client enumeration attacks. See
<a href="#preventing-client-enumeration" class="auto internal xref">Section 10.9</a> for more details. The analysis of OPAQUE
assumes OPRF keys of different users are independently random or
pseudorandom. Deriving these keys via a single PRF (i.e., with a single
cross-user key) applied to users' identities satisfies this assumption.
This change was made to support real-world use cases where client or user
enumeration is a security (or privacy) risk. Note that the derivation of the
OPRF key via a PRF keyed by <code>oprf_seed</code> and applied to the unique
<code>credential_identifier</code> ensures the critical requirement of the per-user OPRF keys
being unique per client.<a href="#section-10.1-3.4.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-10.1-3.5">
<p id="section-10.1-3.5.1">The protocol outputs an export key for the client in addition to a shared
session key that can be used for application-specific purposes. This key
is a pseudorandom value derived from the client password (among other values) and
has no influence on the security analysis (it can be simulated with a
random output). This change was made to support more application use cases
for OPAQUE, such as the use of OPAQUE for end-to-end encrypted backups;
see <span>[<a href="#WhatsAppE2E" class="cite xref">WhatsAppE2E</a>]</span>.<a href="#section-10.1-3.5.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-10.1-3.6">
<p id="section-10.1-3.6.1">The AKE protocol describes a 3-message protocol where the third message includes client
authentication material that the server is required to verify. This change
(from the original 2-message protocol) was made to provide explicit client
authentication and full forward security. The 3-message protocol is analyzed
in <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span>.<a href="#section-10.1-3.6.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-10.1-3.7">
<p id="section-10.1-3.7.1">The protocol admits optional application-layer client and server identities.
In the absence of these identities, the client and server are authenticated
against their public keys. Binding authentication to identities is part
of the AKE part of OPAQUE. The type of identities and their semantics
are application-dependent and independent of the protocol analysis. This
change was made to simplify client and server interfaces to the protocol
by removing the need to specify additional identities alongside their
corresponding public authentication keys when not needed.<a href="#section-10.1-3.7.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-10.1-3.8">
<p id="section-10.1-3.8.1">The protocol admits application-specific <code>context</code> information configured
out-of-band in the AKE transcript. This allows domain separation between
different application uses of OPAQUE. This is a mechanism for the AKE
component and is best practice for domain separation between different
applications of the protocol. This change was made to allow different
applications to use OPAQUE without the risk of cross-protocol attacks.<a href="#section-10.1-3.8.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-10.1-3.9">
<p id="section-10.1-3.9.1">Servers use a separate identifier for computing OPRF evaluations and
indexing into the registration <code>record</code> storage called the <code>credential_identifier</code>.
This allows clients to change their application-layer identity
(<code>client_identity</code>) without inducing server-side changes, e.g., by changing
an email address associated with a given account. This mechanism is part
of the derivation of OPRF keys via a single PRF. As long as the derivation
of different OPRF keys from a single PRF has different PRF inputs, the
protocol is secure. The choice of such inputs is up to the application.<a href="#section-10.1-3.9.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-10.1-3.10">
<p id="section-10.1-3.10.1"><span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span> comments on a defense against offline
dictionary attacks upon server compromise or honest-but-curious servers.
The authors suggest implementing the OPRF phase as a threshold OPRF <span>[<a href="#TOPPSS" class="cite xref">TOPPSS</a>]</span>, effectively forcing an attacker to act online or
control at least t key shares (of the total n), where t is the threshold
number of shares necessary to recombine the secret OPRF key. Only then
would an attacker be able to run an offline dictionary attack. This
implementation only affects the server and changes nothing for the client.
Furthermore, if the threshold OPRF servers holding these keys are separate
from the authentication server, then recovering all n shares would still
not suffice to run an offline dictionary attack without access to the
client <code>record</code> database. However, this mechanism is out of scope for this
document.<a href="#section-10.1-3.10.1" class="pilcrow"></a></p>
</li>
</ul>
<p id="section-10.1-4">The following list enumerates notable differences and refinements from the original
cryptographic design in <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span> and the corresponding CFRG document
<span>[<a href="#I-D.krawczyk-cfrg-opaque" class="cite xref">Krawczyk20</a>]</span> that were made to make this specification
suitable for interoperable implementations.<a href="#section-10.1-4" class="pilcrow"></a></p>
<ul class="normal">
<li class="normal" id="section-10.1-5.1">
<p id="section-10.1-5.1.1"><span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span> used a generic prime-order group for the DH-OPRF and HMQV operations,
and includes necessary prime-order subgroup checks when receiving attacker-controlled
values over the wire. This specification instantiates the prime-order group used for
3DH using prime-order groups based on elliptic curves as described in
<span><a href="https://rfc-editor.org/rfc/rfc9497#section-2.1" class="relref">Section 2.1</a> of [<a href="#RFC9497" class="cite xref">RFC9497</a>]</span>. This specification also delegates OPRF group
choice and operations to <span><a href="https://rfc-editor.org/rfc/rfc9497#section-4" class="relref">Section 4</a> of [<a href="#RFC9497" class="cite xref">RFC9497</a>]</span>. As such, the prime-order group as used
in the OPRF and 3DH as specified in this document both adhere to the requirements in
<span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span>.<a href="#section-10.1-5.1.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-10.1-5.2">
<p id="section-10.1-5.2.1">Appendix B of <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span> specified DH-OPRF to instantiate
the OPRF functionality in the protocol. A critical part of DH-OPRF is the
hash-to-group operation, which was not instantiated in the original analysis.
However, the requirements for this operation were included. This specification
instantiates the OPRF functionality based on <span><a href="https://rfc-editor.org/rfc/rfc9497#section-3.3.1" class="relref">Section 3.3.1</a> of [<a href="#RFC9497" class="cite xref">RFC9497</a>]</span>, which
is identical to the DH-OPRF functionality in <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span> and, concretely, uses
the hash-to-curve functions in <span>[<a href="#RFC9380" class="cite xref">RFC9380</a>]</span>. All hash-to-curve
methods in <span>[<a href="#RFC9380" class="cite xref">RFC9380</a>]</span> are compliant with the requirement
in <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span>, namely, that the output be a member of the prime-order group.<a href="#section-10.1-5.2.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-10.1-5.3">
<p id="section-10.1-5.3.1"><span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span> and <span>[<a href="#I-D.krawczyk-cfrg-opaque" class="cite xref">Krawczyk20</a>]</span> both used HMQV as the AKE
for the protocol. However, this document fully specifies 3DH instead of HMQV
(though a sketch for how to instantiate OPAQUE using HMQV is included in <a href="#hmqv-sketch" class="auto internal xref">Appendix B.1</a>).
Since 3DH satisfies the essential requirements for the AKE protocol as described in <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span>
and <span>[<a href="#I-D.krawczyk-cfrg-opaque" class="cite xref">Krawczyk20</a>]</span>, as recalled in <a href="#security-analysis" class="auto internal xref">Section 10.2</a>, this change
preserves the overall security of the protocol. 3DH was chosen for its
simplicity and ease of implementation.<a href="#section-10.1-5.3.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-10.1-5.4">
<p id="section-10.1-5.4.1">The DH-OPRF and HMQV instantiation of OPAQUE as shown in Figure 12 <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span> uses
a different transcript than that which is described in this specification. In particular,
the key exchange transcript specified in <a href="#protocol-3dh" class="auto internal xref">Section 6.4</a> is a superset of the transcript
as defined in <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span>. This was done to align with best practices, like what is done for key exchange protocols like TLS 1.3 <span>[<a href="#RFC8446" class="cite xref">RFC8446</a>]</span>.<a href="#section-10.1-5.4.1" class="pilcrow"></a></p>
</li>
<li class="normal" id="section-10.1-5.5">
<p id="section-10.1-5.5.1">Neither <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span> nor <span>[<a href="#I-D.krawczyk-cfrg-opaque" class="cite xref">Krawczyk20</a>]</span> included wire format details for the
protocol, which is essential for interoperability. This specification fills this
gap by including such wire format details and corresponding test vectors; see <a href="#test-vectors" class="auto internal xref">Appendix C</a>.<a href="#section-10.1-5.5.1" class="pilcrow"></a></p>
</li>
</ul>
</section>
</div>
<div id="security-analysis">
<section id="section-10.2">
<h3 id="name-security-analysis">
<a href="#section-10.2" class="section-number selfRef">10.2. </a><a href="#name-security-analysis" class="section-name selfRef">Security Analysis</a>
</h3>
<p id="section-10.2-1">Jarecki et al. <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span> proved the security of OPAQUE (modulo the
design differences outlined in <a href="#notable-design-differences" class="auto internal xref">Section 10.1</a>)
in a strong aPAKE model that ensures security against precomputation attacks
and is formulated in the UC framework <span>[<a href="#Canetti01" class="cite xref">Canetti01</a>]</span>
under the random oracle model. This assumes security of the OPRF
function and the underlying key exchange protocol.<a href="#section-10.2-1" class="pilcrow"></a></p>
<p id="section-10.2-2">OPAQUE's design builds on a line of work initiated in the seminal
paper of Ford and Kaliski <span>[<a href="#FK00" class="cite xref">FK00</a>]</span> and is based on the HPAKE protocol
of Xavier Boyen <span>[<a href="#Boyen09" class="cite xref">Boyen09</a>]</span> and the (1,1)-PPSS protocol from Jarecki
et al. <span>[<a href="#JKKX16" class="cite xref">JKKX16</a>]</span>. None of these papers considered security against
precomputation attacks or presented a proof of aPAKE security
(not even in a weak model).<a href="#section-10.2-2" class="pilcrow"></a></p>
<p id="section-10.2-3">The KCI property required from AKE protocols for use with OPAQUE
states that knowledge of a party's private key does not allow an attacker
to impersonate others to that party. This is an important security
property achieved by most public-key-based AKE protocols, including
protocols that use signatures or public key encryption for
authentication. It is also a property of many implicitly
authenticated protocols, e.g., HMQV, but not all of them. We also note that
key exchange protocols based on shared keys do not satisfy the KCI
requirement, hence they are not considered in the OPAQUE setting.
We note that KCI is needed to ensure a crucial property of OPAQUE. Even upon
compromise of the server, the attacker cannot impersonate the client to the
server without first running an exhaustive dictionary attack.
Another essential requirement from AKE protocols for use in OPAQUE is to
provide forward secrecy (against active attackers).<a href="#section-10.2-3" class="pilcrow"></a></p>
<p id="section-10.2-4">In <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span>, security is proven for one instance (i.e., one
key) of the OPAQUE protocol, and without batching. There is currently no
security analysis available for the OPAQUE protocol described in this
document in a setting with multiple server keys or batching.<a href="#section-10.2-4" class="pilcrow"></a></p>
<p id="section-10.2-5">As stated in <a href="#implementation-safeguards" class="auto internal xref">Section 9.1</a>, incorporating <code>client_identity</code>
adds domain separation, particularly against servers that choose the same
OPRF key for multiple clients. The <code>client_identity</code> as input to the OPRF
also acts as a key identifier that would be required for a proof of the
protocol in the multi-key setting; the OPAQUE analysis in <span>[<a href="#JKX18" class="cite xref">JKX18</a>]</span> assumes
single server-key instances. Adding <code>server_identity</code> to the OPRF input
provides domain separation for clients that reuse the same <code>client_identity</code>
across different server instantiations.<a href="#section-10.2-5" class="pilcrow"></a></p>
</section>
</div>
<div id="identities">
<section id="section-10.3">
<h3 id="name-identities">
<a href="#section-10.3" class="section-number selfRef">10.3. </a><a href="#name-identities" class="section-name selfRef">Identities</a>
</h3>
<p id="section-10.3-1">AKE protocols generate keys that need to be uniquely and verifiably bound to a pair
of identities. In the case of OPAQUE, those identities correspond to <code>client_identity</code> and <code>server_identity</code>.
Thus, it is essential for the parties to agree on such identities, including an
agreed bit representation of these identities as needed.<a href="#section-10.3-1" class="pilcrow"></a></p>
<p id="section-10.3-2">Note that the method of transmission of <code>client_identity</code> from client to server is outside
the scope of this protocol and it is up to an application to choose how this identity
should be delivered (for instance, alongside the first OPAQUE message or agreed upon before
the OPAQUE protocol begins).<a href="#section-10.3-2" class="pilcrow"></a></p>
<p id="section-10.3-3">Applications may have different policies about how and when identities are
determined. A natural approach is to tie <code>client_identity</code> to the identity the server uses
to fetch the envelope (determined during password registration) and tie <code>server_identity</code>
to the server identity used by the client to initiate an offline password
registration or online authenticated key exchange session. <code>server_identity</code> and <code>client_identity</code> can also
be part of the envelope or tied to the parties' public keys. In principle, identities
may change across different sessions as long as there is a policy that
can establish if the identity is acceptable or not to the peer. However, we note
that the public keys of both the server and the client must always be those defined
at the time of password registration.<a href="#section-10.3-3" class="pilcrow"></a></p>
<p id="section-10.3-4">The client identity (<code>client_identity</code>) and server identity (<code>server_identity</code>) are
optional parameters that are left to the application to designate as aliases for
the client and server. If the application layer does not supply values for these
parameters, then they will be omitted from the creation of the envelope
during the registration stage. Furthermore, they will be substituted with
<code>client_identity</code> = <code>client_public_key</code> and <code>server_identity</code> = <code>server_public_key</code> during
the authenticated key exchange stage.<a href="#section-10.3-4" class="pilcrow"></a></p>
<p id="section-10.3-5">The advantage of supplying a custom <code>client_identity</code> and <code>server_identity</code> (instead of simply relying
on a fallback to <code>client_public_key</code> and <code>server_public_key</code>) is that the client can then ensure that any
mappings between <code>client_identity</code> and <code>client_public_key</code> (and <code>server_identity</code> and <code>server_public_key</code>)
are protected by the authentication from the envelope. Then, the client can verify that the
<code>client_identity</code> and <code>server_identity</code> contained in its envelope match the <code>client_identity</code>
and <code>server_identity</code> supplied by the server.<a href="#section-10.3-5" class="pilcrow"></a></p>
<p id="section-10.3-6">However, if this extra layer of verification is unnecessary for the application, then simply
leaving <code>client_identity</code> and <code>server_identity</code> unspecified (and using <code>client_public_key</code> and
<code>server_public_key</code> instead) is acceptable.<a href="#section-10.3-6" class="pilcrow"></a></p>
</section>
</div>
<div id="export-key-usage">
<section id="section-10.4">
<h3 id="name-export-key-usage">
<a href="#section-10.4" class="section-number selfRef">10.4. </a><a href="#name-export-key-usage" class="section-name selfRef">Export Key Usage</a>
</h3>
<p id="section-10.4-1">The export key can be used (separately from the OPAQUE protocol) to provide
confidentiality and integrity to other data that only the client should be
able to process. For instance, if the client wishes to store secrets with a
third party, then this export key can be used by the client to encrypt these
secrets so that they remain hidden from a passive adversary that does not have
access to the server's secret keys or the client's password.<a href="#section-10.4-1" class="pilcrow"></a></p>
</section>
</div>
<div id="static-diffie-hellman-oracles">
<section id="section-10.5">
<h3 id="name-static-diffie-hellman-oracl">
<a href="#section-10.5" class="section-number selfRef">10.5. </a><a href="#name-static-diffie-hellman-oracl" class="section-name selfRef">Static Diffie-Hellman Oracles</a>
</h3>
<p id="section-10.5-1">While one can expect the practical security of the OPRF function (namely,
the hardness of computing the function without knowing the key) to be in the
order of computing discrete logarithms or solving Diffie-Hellman, Brown and
Gallant <span>[<a href="#BG04" class="cite xref">BG04</a>]</span> and Cheon <span>[<a href="#Cheon06" class="cite xref">Cheon06</a>]</span> show an attack that slightly improves
on generic attacks. For typical curves, the attack requires an infeasible
number of calls to the OPRF or results in insignificant security loss;
see <span><a href="https://rfc-editor.org/rfc/rfc9497#section-7.2.3" class="relref">Section 7.2.3</a> of [<a href="#RFC9497" class="cite xref">RFC9497</a>]</span> for more information. For OPAQUE, these attacks
are particularly impractical as they translate into an infeasible number of
failed authentication attempts directed at individual users.<a href="#section-10.5-1" class="pilcrow"></a></p>
</section>
</div>
<div id="rkr-mac">
<section id="section-10.6">
<h3 id="name-random-key-robust-macs">
<a href="#section-10.6" class="section-number selfRef">10.6. </a><a href="#name-random-key-robust-macs" class="section-name selfRef">Random-Key Robust MACs</a>
</h3>
<p id="section-10.6-1">The random-key robustness property for a MAC states
that, given two random keys k1 and k2, it is infeasible to find a message m
such that MAC(k1, m) = MAC(k2, m). Note that in general, not every MAC function
is key-robust. In particular, GMAC (which underlies GCM) does not satisfy
key-robustness, whereas HMAC with a collision-resistant hash function does
satisfy key-robustness.<a href="#section-10.6-1" class="pilcrow"></a></p>
<p id="section-10.6-2">An application can choose to use a non-key-robust MAC within the AKE portion of
the protocol described in <a href="#protocol-3dh" class="auto internal xref">Section 6.4</a>, but it <span class="bcp14">MUST</span> use a key-robust MAC
for the creation of the <code>auth_tag</code> parameter in <a href="#envelope-creation" class="auto internal xref">Section 4.1.2</a>.<a href="#section-10.6-2" class="pilcrow"></a></p>
</section>
</div>
<div id="validation">
<section id="section-10.7">
<h3 id="name-input-validation">
<a href="#section-10.7" class="section-number selfRef">10.7. </a><a href="#name-input-validation" class="section-name selfRef">Input Validation</a>
</h3>
<p id="section-10.7-1">Both client and server <span class="bcp14">MUST</span> validate the other party's public key(s) used
for the execution of OPAQUE. This includes the keys shared during the
registration phase, as well as any keys shared during the online
key agreement phase. The validation procedure varies depending on the
type of key. For example, for OPAQUE instantiations
using 3DH with P-256, P-384, or P-521 as the underlying group, validation
is as specified in Section 5.6.2.3.4 of <span>[<a href="#keyagreement" class="cite xref">keyagreement</a>]</span>. This includes
checking that the coordinates are in the correct range, that the point
is on the curve, and that the point is not the point at infinity.
Additionally, validation <span class="bcp14">MUST</span> ensure the Diffie-Hellman shared secret is
not the point at infinity.<a href="#section-10.7-1" class="pilcrow"></a></p>
</section>
</div>
<div id="key-stretch">
<section id="section-10.8">
<h3 id="name-oprf-key-stretching">
<a href="#section-10.8" class="section-number selfRef">10.8. </a><a href="#name-oprf-key-stretching" class="section-name selfRef">OPRF Key Stretching</a>
</h3>
<p id="section-10.8-1">Applying a key stretching function to the output of the OPRF greatly increases the cost of an offline
attack upon the compromise of the credential file on the server. Applications
<span class="bcp14">SHOULD</span> select parameters for the KSF that balance cost and complexity across
different client implementations and deployments. Note that in OPAQUE, the
key stretching function is executed by the client as opposed to the server in
common password hashing scenarios. This means that applications must consider
a tradeoff between the performance of the protocol on clients (specifically low-end
devices) and protection against offline attacks after a server compromise.<a href="#section-10.8-1" class="pilcrow"></a></p>
</section>
</div>
<div id="preventing-client-enumeration">
<section id="section-10.9">
<h3 id="name-client-enumeration">
<a href="#section-10.9" class="section-number selfRef">10.9. </a><a href="#name-client-enumeration" class="section-name selfRef">Client Enumeration</a>
</h3>
<p id="section-10.9-1">Client enumeration refers to attacks where the attacker tries to learn whether
a given user identity is registered with a server or whether a reregistration
or change of password was performed for that user. OPAQUE counters these
attacks by requiring servers to act with unregistered client identities in a
way that is indistinguishable from their behavior with existing registered clients.
Servers do this by simulating a fake <code>CredentialResponse</code> as specified in
<a href="#create-credential-response" class="auto internal xref">Section 6.3.2.2</a> for unregistered users and encrypting
<code>CredentialResponse</code> using a masking key. In this way, real and fake <code>CredentialResponse</code>
messages are indistinguishable from one another.
Implementations must also take care to avoid side-channel leakage (e.g., timing
attacks) from helping differentiate these operations from a regular server
response. Note that this may introduce possible abuse vectors since the
server's cost of generating a <code>CredentialResponse</code> is less than that of the
client's cost of generating a <code>CredentialRequest</code>. Server implementations
may choose to forego the construction of a simulated credential response
message for an unregistered client if these client enumeration attacks can
be mitigated through other application-specific means or are otherwise not
applicable for their threat model.<a href="#section-10.9-1" class="pilcrow"></a></p>
<p id="section-10.9-2">OPAQUE does not prevent this type of attack during the registration flow.
Servers necessarily react differently during the registration flow between
registered and unregistered clients. This allows an attacker to use the server's
response during registration as an oracle for whether a given client identity is
registered. Applications should mitigate against this type of attack by rate
limiting or otherwise restricting the registration flow.<a href="#section-10.9-2" class="pilcrow"></a></p>
<p id="section-10.9-3">Finally, applications that do not require protection against
client enumeration attacks can choose to derive independent OPRF keys for different
clients. The advantage to using independently-derived OPRF keys is that the server
avoids keeping the <code>oprf_seed</code> value across different clients, which, if leaked, would
compromise the security for all clients reliant on <code>oprf_seed</code> as noted in <span>[<a href="#DL24" class="cite xref">DL24</a>]</span>.<a href="#section-10.9-3" class="pilcrow"></a></p>
</section>
</div>
<div id="protecting-the-registration-masking-key">
<section id="section-10.10">
<h3 id="name-protecting-the-registration">
<a href="#section-10.10" class="section-number selfRef">10.10. </a><a href="#name-protecting-the-registration" class="section-name selfRef">Protecting the Registration Masking Key</a>
</h3>
<p id="section-10.10-1">The user enumeration prevention method described in this document uses a
symmetric encryption key, <code>masking_key</code>, generated and sent to the server
by the client during registration. This requires a confidential channel
between client and server during registration, e.g., using TLS <span>[<a href="#RFC8446" class="cite xref">RFC8446</a>]</span>.
If the channel is only authenticated (this is a requirement for correct
identification of the parties), a confidential channel can be established
using public-key encryption, e.g., with HPKE <span>[<a href="#RFC9180" class="cite xref">RFC9180</a>]</span>. However, the details
of this mechanism are out of scope for this document.<a href="#section-10.10-1" class="pilcrow"></a></p>
</section>
</div>
<div id="password-salt-and-storage-implications">
<section id="section-10.11">
<h3 id="name-password-salt-and-storage-i">
<a href="#section-10.11" class="section-number selfRef">10.11. </a><a href="#name-password-salt-and-storage-i" class="section-name selfRef">Password Salt and Storage Implications</a>
</h3>
<p id="section-10.11-1">In OPAQUE, the OPRF key acts as the secret <code>salt</code> value that ensures the infeasibility
of precomputation attacks. No extra <code>salt</code> value is needed. Also, clients never
disclose their passwords to the server, even during registration. Note that a corrupted
server can run an exhaustive offline dictionary attack to validate guesses for the client's
password; this is inevitable in any (single-server) aPAKE protocol. It can be avoided in
the case of OPAQUE by resorting to a multi-server threshold OPRF implementation,
e.g., <span>[<a href="#TOPPSS" class="cite xref">TOPPSS</a>]</span>. Furthermore, if the server does not
sample the PRF <code>seed</code> with sufficiently high entropy, or if it is not kept hidden from an
adversary, then any derivatives from the client's password may also be susceptible to an
offline dictionary attack to recover the original password.<a href="#section-10.11-1" class="pilcrow"></a></p>
<p id="section-10.11-2">Some applications may require learning the client's password to enforce password
rules. Doing so invalidates this important security property of OPAQUE and is
<span class="bcp14">NOT RECOMMENDED</span> unless it is not possible for applications to move such checks
to the client. Note that limited checks at the server are possible to implement, e.g.,
detecting repeated passwords upon reregistrations or password change.<a href="#section-10.11-2" class="pilcrow"></a></p>
<p id="section-10.11-3">In general, passwords should be selected with sufficient entropy to avoid being susceptible
to recovery through dictionary attacks, both online and offline.<a href="#section-10.11-3" class="pilcrow"></a></p>
</section>
</div>
<div id="ake-private-key-storage">
<section id="section-10.12">
<h3 id="name-ake-private-key-storage">
<a href="#section-10.12" class="section-number selfRef">10.12. </a><a href="#name-ake-private-key-storage" class="section-name selfRef">AKE Private Key Storage</a>
</h3>
<p id="section-10.12-1">Server implementations of OPAQUE do not need access to the raw AKE private key. They only require
the ability to compute shared secrets as specified in <a href="#key-schedule-functions" class="auto internal xref">Section 6.4.2</a>. Thus, applications
may store the server AKE private key in a Hardware Security Module (HSM) or
similar. Upon compromise of <code>oprf_seed</code> and client envelopes, this would prevent an
attacker from using this data to mount a server spoofing attack. Supporting implementations
need to consider allowing separate AKE and OPRF algorithms in cases where the HSM is
incompatible with the OPRF algorithm.<a href="#section-10.12-1" class="pilcrow"></a></p>
</section>
</div>
<div id="client-authentication-using-credentials">
<section id="section-10.13">
<h3 id="name-client-authentication-using">
<a href="#section-10.13" class="section-number selfRef">10.13. </a><a href="#name-client-authentication-using" class="section-name selfRef">Client Authentication Using Credentials</a>
</h3>
<p id="section-10.13-1">For scenarios in which the client has access to private state that can be persisted across
registration and login, the client can back up the <code>randomized_password</code> variable (as
computed in <a href="#finalize-request" class="auto internal xref">Section 5.2.3</a>) so that upon a future login attempt, the client can
authenticate to the server using <code>randomized_password</code> instead of the original password.
This can be achieved by supplying an arbitrary password as input to
<code>CreateCredentialRequest</code> in the login phase, and then using <code>randomized_password</code> from
the backup in <code>RecoverCredentials</code> (invoked by <code>GenerateKE3</code>) rather than computing it from
the password.<a href="#section-10.13-1" class="pilcrow"></a></p>
<p id="section-10.13-2">This provides an advantage over the regular authentication flow for login
in that if <code>randomized_password</code> is compromised, an adversary cannot use this value to
successfully impersonate the server to the client during login. The drawback is that it is
only applicable to settings where <code>randomized_password</code> can be treated as a credential
that can be stored securely after registration and retrieved upon login.<a href="#section-10.13-2" class="pilcrow"></a></p>
</section>
</div>
</section>
</div>
<div id="iana-considerations">
<section id="section-11">
<h2 id="name-iana-considerations">
<a href="#section-11" class="section-number selfRef">11. </a><a href="#name-iana-considerations" class="section-name selfRef">IANA Considerations</a>
</h2>
<p id="section-11-1">This document has no IANA actions.<a href="#section-11-1" class="pilcrow"></a></p>
</section>
</div>
<div id="sec-combined-references">
<section id="section-12">
<h2 id="name-references">
<a href="#section-12" class="section-number selfRef">12. </a><a href="#name-references" class="section-name selfRef">References</a>
</h2>
<div id="sec-normative-references">
<section id="section-12.1">
<h3 id="name-normative-references">
<a href="#section-12.1" class="section-number selfRef">12.1. </a><a href="#name-normative-references" class="section-name selfRef">Normative References</a>
</h3>
<dl class="references">
<dt id="RFC2104">[RFC2104]</dt>
<dd>
<span class="refAuthor">Krawczyk, H.</span>, <span class="refAuthor">Bellare, M.</span>, and <span class="refAuthor">R. Canetti</span>, <span class="refTitle">"HMAC: Keyed-Hashing for Message Authentication"</span>, <span class="seriesInfo">RFC 2104</span>, <span class="seriesInfo">DOI 10.17487/RFC2104</span>, <time datetime="1997-02" class="refDate">February 1997</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc2104">https://www.rfc-editor.org/info/rfc2104</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="RFC2119">[RFC2119]</dt>
<dd>
<span class="refAuthor">Bradner, S.</span>, <span class="refTitle">"Key words for use in RFCs to Indicate Requirement Levels"</span>, <span class="seriesInfo">BCP 14</span>, <span class="seriesInfo">RFC 2119</span>, <span class="seriesInfo">DOI 10.17487/RFC2119</span>, <time datetime="1997-03" class="refDate">March 1997</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc2119">https://www.rfc-editor.org/info/rfc2119</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="RFC4086">[RFC4086]</dt>
<dd>
<span class="refAuthor">Eastlake 3rd, D.</span>, <span class="refAuthor">Schiller, J.</span>, and <span class="refAuthor">S. Crocker</span>, <span class="refTitle">"Randomness Requirements for Security"</span>, <span class="seriesInfo">BCP 106</span>, <span class="seriesInfo">RFC 4086</span>, <span class="seriesInfo">DOI 10.17487/RFC4086</span>, <time datetime="2005-06" class="refDate">June 2005</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc4086">https://www.rfc-editor.org/info/rfc4086</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="RFC8174">[RFC8174]</dt>
<dd>
<span class="refAuthor">Leiba, B.</span>, <span class="refTitle">"Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words"</span>, <span class="seriesInfo">BCP 14</span>, <span class="seriesInfo">RFC 8174</span>, <span class="seriesInfo">DOI 10.17487/RFC8174</span>, <time datetime="2017-05" class="refDate">May 2017</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc8174">https://www.rfc-editor.org/info/rfc8174</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="RFC9497">[RFC9497]</dt>
<dd>
<span class="refAuthor">Davidson, A.</span>, <span class="refAuthor">Faz-Hernandez, A.</span>, <span class="refAuthor">Sullivan, N.</span>, and <span class="refAuthor">C. A. Wood</span>, <span class="refTitle">"Oblivious Pseudorandom Functions (OPRFs) Using Prime-Order Groups"</span>, <span class="seriesInfo">RFC 9497</span>, <span class="seriesInfo">DOI 10.17487/RFC9497</span>, <time datetime="2023-12" class="refDate">December 2023</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc9497">https://www.rfc-editor.org/info/rfc9497</a>&gt;</span>. </dd>
<dd class="break"></dd>
</dl>
</section>
</div>
<div id="sec-informative-references">
<section id="section-12.2">
<h3 id="name-informative-references">
<a href="#section-12.2" class="section-number selfRef">12.2. </a><a href="#name-informative-references" class="section-name selfRef">Informative References</a>
</h3>
<dl class="references">
<dt id="BG04">[BG04]</dt>
<dd>
<span class="refAuthor">Brown, D.</span> and <span class="refAuthor">R. Galant</span>, <span class="refTitle">"The Static Diffie-Hellman Problem"</span>, <span class="refContent">Cryptology ePrint Archive, Paper 2004/306</span>, <time datetime="2004" class="refDate">2004</time>, <span>&lt;<a href="https://eprint.iacr.org/2004/306">https://eprint.iacr.org/2004/306</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="Boyen09">[Boyen09]</dt>
<dd>
<span class="refAuthor">Boyen, X.</span>, <span class="refTitle">"HPAKE: Password Authentication Secure against Cross-Site User Impersonation"</span>, <span class="refContent">Cryptology and Network Security (CANS 2009), Lecture Notes in Computer Science, vol. 5888, pp. 279-298</span>, <span class="seriesInfo">DOI 10.1007/978-3-642-10433-6_19</span>, <time datetime="2009" class="refDate">2009</time>, <span>&lt;<a href="https://doi.org/10.1007/978-3-642-10433-6_19">https://doi.org/10.1007/978-3-642-10433-6_19</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="Canetti01">[Canetti01]</dt>
<dd>
<span class="refAuthor">Canetti, R.</span>, <span class="refTitle">"Universally composable security: A new paradigm for cryptographic protocols"</span>, <span class="refContent">42nd IEEE Symposium on Foundations of Computer Science, pp. 136-145</span>, <span class="seriesInfo">DOI 10.1109/SFCS.2001.959888</span>, <time datetime="2001" class="refDate">2001</time>, <span>&lt;<a href="https://doi.org/10.1109/SFCS.2001.959888">https://doi.org/10.1109/SFCS.2001.959888</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="Cheon06">[Cheon06]</dt>
<dd>
<span class="refAuthor">Cheon, J. H.</span>, <span class="refTitle">"Security Analysis of the Strong Diffie-Hellman Problem"</span>, <span class="refContent">Advances in Cryptology - EUROCRYPT 2006, Lecture Notes in Computer Science, vol. 4004, pp. 1-11</span>, <span class="seriesInfo">DOI 10.1007/11761679_1</span>, <time datetime="2006" class="refDate">2006</time>, <span>&lt;<a href="https://doi.org/10.1007/11761679_1">https://doi.org/10.1007/11761679_1</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="DL24">[DL24]</dt>
<dd>
<span class="refAuthor">Dayanikli, D.</span> and <span class="refAuthor">A. Lehmann</span>, <span class="refTitle">"(Strong) aPAKE Revisited: Capturing Multi-User Security and Salting"</span>, <span class="refContent">Cryptology ePrint Archive, Paper 2024/756</span>, <time datetime="2024" class="refDate">2024</time>, <span>&lt;<a href="https://eprint.iacr.org/2024/756">https://eprint.iacr.org/2024/756</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="FIPS202">[FIPS202]</dt>
<dd>
<span class="refAuthor">NIST</span>, <span class="refTitle">"SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions"</span>, <span class="seriesInfo">NIST FIPS 202</span>, <span class="seriesInfo">DOI 10.6028/NIST.FIPS.202</span>, <time datetime="2015-08" class="refDate">August 2015</time>, <span>&lt;<a href="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf">https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="FK00">[FK00]</dt>
<dd>
<span class="refAuthor">Ford, W.</span> and <span class="refAuthor">B. S. Kaliski, Jr</span>, <span class="refTitle">"Server-assisted generation of a strong secret from a password"</span>, <span class="refContent">IEEE 9th International Workshops on Enabling Technologies: Infrastructure for Collaborative Enterprises (WET ICE 2000), pp. 176-180</span>, <span class="seriesInfo">DOI 10.1109/ENABL.2000.883724</span>, <time datetime="2000" class="refDate">2000</time>, <span>&lt;<a href="https://doi.org/10.1109/ENABL.2000.883724">https://doi.org/10.1109/ENABL.2000.883724</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="HJKW23">[HJKW23]</dt>
<dd>
<span class="refAuthor">Hesse, J.</span>, <span class="refAuthor">Jarecki, S.</span>, <span class="refAuthor">Krawczyk, H.</span>, and <span class="refAuthor">C. Wood</span>, <span class="refTitle">"Password-Authenticated TLS via OPAQUE and Post-Handshake Authentication"</span>, <span class="refContent">Advances in Cryptology - EUROCRYPT 2023, Lecture Notes in Computer Science, vol. 14008, pp. 98-127</span>, <span class="seriesInfo">DOI 10.1007/978-3-031-30589-4_4</span>, <time datetime="2023" class="refDate">2023</time>, <span>&lt;<a href="https://doi.org/10.1007/978-3-031-30589-4_4">https://doi.org/10.1007/978-3-031-30589-4_4</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="HMQV">[HMQV]</dt>
<dd>
<span class="refAuthor">Krawczyk, H.</span>, <span class="refTitle">"HMQV: A High-Performance Secure Diffie-Hellman Protocol"</span>, <span class="refContent">Cryptology ePrint Archive, Paper 2005/176</span>, <time datetime="2005" class="refDate">2005</time>, <span>&lt;<a href="https://eprint.iacr.org/2005/176">https://eprint.iacr.org/2005/176</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="JKKX16">[JKKX16]</dt>
<dd>
<span class="refAuthor">Jarecki, S.</span>, <span class="refAuthor">Kiayias, A.</span>, <span class="refAuthor">Krawczyk, H.</span>, and <span class="refAuthor">J. Xu</span>, <span class="refTitle">"Highly-Efficient and Composable Password-Protected Secret Sharing (Or: How to Protect Your Bitcoin Wallet Online)"</span>, <span class="refContent">2016 IEEE European Symposium on Security and Privacy (EuroS&amp;P), pp. 276-291</span>, <span class="seriesInfo">DOI 10.1109/EuroSP.2016.30</span>, <time datetime="2016" class="refDate">2016</time>, <span>&lt;<a href="https://doi.org/10.1109/EuroSP.2016.30">https://doi.org/10.1109/EuroSP.2016.30</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="JKX18">[JKX18]</dt>
<dd>
<span class="refAuthor">Jarecki, S.</span>, <span class="refAuthor">Krawczyk, H.</span>, and <span class="refAuthor">J. Xu</span>, <span class="refTitle">"OPAQUE: An Asymmetric PAKE Protocol Secure Against Pre-Computation Attacks"</span>, <span class="refContent">Cryptology ePrint Archive, Paper 2018/163</span>, <time datetime="2018" class="refDate">2018</time>, <span>&lt;<a href="https://eprint.iacr.org/2018/163">https://eprint.iacr.org/2018/163</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="keyagreement">[keyagreement]</dt>
<dd>
<span class="refAuthor">Barker, E.</span>, <span class="refAuthor">Chen, L.</span>, <span class="refAuthor">Roginsky, A.</span>, <span class="refAuthor">Vassilev, A.</span>, and <span class="refAuthor">R. Davis</span>, <span class="refTitle">"Recommendation for Pair-Wise Key-Establishment Schemes Using Discrete Logarithm Cryptography"</span>, <span class="seriesInfo">DOI 10.6028/nist.sp.800-56ar3</span>, <span class="seriesInfo">NIST SP 800-56Ar3</span>, <time datetime="2018-04" class="refDate">April 2018</time>, <span>&lt;<a href="https://doi.org/10.6028/nist.sp.800-56ar3">https://doi.org/10.6028/nist.sp.800-56ar3</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="I-D.krawczyk-cfrg-opaque">[Krawczyk20]</dt>
<dd>
<span class="refAuthor">Krawczyk, H.</span>, <span class="refTitle">"The OPAQUE Asymmetric PAKE Protocol"</span>, <span class="refContent">Work in Progress</span>, <span class="seriesInfo">Internet-Draft, draft-krawczyk-cfrg-opaque-06</span>, <time datetime="2020-06-19" class="refDate">19 June 2020</time>, <span>&lt;<a href="https://datatracker.ietf.org/doc/html/draft-krawczyk-cfrg-opaque-06">https://datatracker.ietf.org/doc/html/draft-krawczyk-cfrg-opaque-06</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="LGR20">[LGR20]</dt>
<dd>
<span class="refAuthor">Len, J.</span>, <span class="refAuthor">Grubbs, P.</span>, and <span class="refAuthor">T. Ristenpart</span>, <span class="refTitle">"Partitioning Oracle Attacks"</span>, <span class="refContent">Cryptology ePrint Archive, Paper 2020/1491</span>, <time datetime="2021" class="refDate">2021</time>, <span>&lt;<a href="https://eprint.iacr.org/2020/1491.pdf">https://eprint.iacr.org/2020/1491.pdf</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="NISTCurves">[NISTCurves]</dt>
<dd>
<span class="refAuthor">NIST</span>, <span class="refTitle">"Digital Signature Standard (DSS)"</span>, <span class="seriesInfo">NIST FIPS 186-5</span>, <span class="seriesInfo">DOI 10.6028/nist.fips.186-5</span>, <time datetime="2013" class="refDate">2013</time>, <span>&lt;<a href="https://doi.org/10.6028/nist.fips.186-5">https://doi.org/10.6028/nist.fips.186-5</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="RFC5869">[RFC5869]</dt>
<dd>
<span class="refAuthor">Krawczyk, H.</span> and <span class="refAuthor">P. Eronen</span>, <span class="refTitle">"HMAC-based Extract-and-Expand Key Derivation Function (HKDF)"</span>, <span class="seriesInfo">RFC 5869</span>, <span class="seriesInfo">DOI 10.17487/RFC5869</span>, <time datetime="2010-05" class="refDate">May 2010</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc5869">https://www.rfc-editor.org/info/rfc5869</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="RFC7748">[RFC7748]</dt>
<dd>
<span class="refAuthor">Langley, A.</span>, <span class="refAuthor">Hamburg, M.</span>, and <span class="refAuthor">S. Turner</span>, <span class="refTitle">"Elliptic Curves for Security"</span>, <span class="seriesInfo">RFC 7748</span>, <span class="seriesInfo">DOI 10.17487/RFC7748</span>, <time datetime="2016-01" class="refDate">January 2016</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc7748">https://www.rfc-editor.org/info/rfc7748</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="RFC7914">[RFC7914]</dt>
<dd>
<span class="refAuthor">Percival, C.</span> and <span class="refAuthor">S. Josefsson</span>, <span class="refTitle">"The scrypt Password-Based Key Derivation Function"</span>, <span class="seriesInfo">RFC 7914</span>, <span class="seriesInfo">DOI 10.17487/RFC7914</span>, <time datetime="2016-08" class="refDate">August 2016</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc7914">https://www.rfc-editor.org/info/rfc7914</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="RFC8017">[RFC8017]</dt>
<dd>
<span class="refAuthor">Moriarty, K., Ed.</span>, <span class="refAuthor">Kaliski, B.</span>, <span class="refAuthor">Jonsson, J.</span>, and <span class="refAuthor">A. Rusch</span>, <span class="refTitle">"PKCS #1: RSA Cryptography Specifications Version 2.2"</span>, <span class="seriesInfo">RFC 8017</span>, <span class="seriesInfo">DOI 10.17487/RFC8017</span>, <time datetime="2016-11" class="refDate">November 2016</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc8017">https://www.rfc-editor.org/info/rfc8017</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="RFC8018">[RFC8018]</dt>
<dd>
<span class="refAuthor">Moriarty, K., Ed.</span>, <span class="refAuthor">Kaliski, B.</span>, and <span class="refAuthor">A. Rusch</span>, <span class="refTitle">"PKCS #5: Password-Based Cryptography Specification Version 2.1"</span>, <span class="seriesInfo">RFC 8018</span>, <span class="seriesInfo">DOI 10.17487/RFC8018</span>, <time datetime="2017-01" class="refDate">January 2017</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc8018">https://www.rfc-editor.org/info/rfc8018</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="RFC8125">[RFC8125]</dt>
<dd>
<span class="refAuthor">Schmidt, J.</span>, <span class="refTitle">"Requirements for Password-Authenticated Key Agreement (PAKE) Schemes"</span>, <span class="seriesInfo">RFC 8125</span>, <span class="seriesInfo">DOI 10.17487/RFC8125</span>, <time datetime="2017-04" class="refDate">April 2017</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc8125">https://www.rfc-editor.org/info/rfc8125</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="RFC8446">[RFC8446]</dt>
<dd>
<span class="refAuthor">Rescorla, E.</span>, <span class="refTitle">"The Transport Layer Security (TLS) Protocol Version 1.3"</span>, <span class="seriesInfo">RFC 8446</span>, <span class="seriesInfo">DOI 10.17487/RFC8446</span>, <time datetime="2018-08" class="refDate">August 2018</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc8446">https://www.rfc-editor.org/info/rfc8446</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="RFC9106">[RFC9106]</dt>
<dd>
<span class="refAuthor">Biryukov, A.</span>, <span class="refAuthor">Dinu, D.</span>, <span class="refAuthor">Khovratovich, D.</span>, and <span class="refAuthor">S. Josefsson</span>, <span class="refTitle">"Argon2 Memory-Hard Function for Password Hashing and Proof-of-Work Applications"</span>, <span class="seriesInfo">RFC 9106</span>, <span class="seriesInfo">DOI 10.17487/RFC9106</span>, <time datetime="2021-09" class="refDate">September 2021</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc9106">https://www.rfc-editor.org/info/rfc9106</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="RFC9180">[RFC9180]</dt>
<dd>
<span class="refAuthor">Barnes, R.</span>, <span class="refAuthor">Bhargavan, K.</span>, <span class="refAuthor">Lipp, B.</span>, and <span class="refAuthor">C. Wood</span>, <span class="refTitle">"Hybrid Public Key Encryption"</span>, <span class="seriesInfo">RFC 9180</span>, <span class="seriesInfo">DOI 10.17487/RFC9180</span>, <time datetime="2022-02" class="refDate">February 2022</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc9180">https://www.rfc-editor.org/info/rfc9180</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="RFC9380">[RFC9380]</dt>
<dd>
<span class="refAuthor">Faz-Hernandez, A.</span>, <span class="refAuthor">Scott, S.</span>, <span class="refAuthor">Sullivan, N.</span>, <span class="refAuthor">Wahby, R. S.</span>, and <span class="refAuthor">C. A. Wood</span>, <span class="refTitle">"Hashing to Elliptic Curves"</span>, <span class="seriesInfo">RFC 9380</span>, <span class="seriesInfo">DOI 10.17487/RFC9380</span>, <time datetime="2023-08" class="refDate">August 2023</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc9380">https://www.rfc-editor.org/info/rfc9380</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="RFC9496">[RFC9496]</dt>
<dd>
<span class="refAuthor">de Valence, H.</span>, <span class="refAuthor">Grigg, J.</span>, <span class="refAuthor">Hamburg, M.</span>, <span class="refAuthor">Lovecruft, I.</span>, <span class="refAuthor">Tankersley, G.</span>, and <span class="refAuthor">F. Valsorda</span>, <span class="refTitle">"The ristretto255 and decaf448 Groups"</span>, <span class="seriesInfo">RFC 9496</span>, <span class="seriesInfo">DOI 10.17487/RFC9496</span>, <time datetime="2023-12" class="refDate">December 2023</time>, <span>&lt;<a href="https://www.rfc-editor.org/info/rfc9496">https://www.rfc-editor.org/info/rfc9496</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="SIGMA-I">[SIGMA-I]</dt>
<dd>
<span class="refAuthor">Krawczyk, H.</span>, <span class="refTitle">"SIGMA: The 'SIGn-and-MAc' Approach to Authenticated Diffie-Hellman and its Use in the IKE Protocols"</span>, <time datetime="2003" class="refDate">2003</time>, <span>&lt;<a href="https://www.iacr.org/cryptodb/archive/2003/CRYPTO/1495/1495.pdf">https://www.iacr.org/cryptodb/archive/2003/CRYPTO/1495/1495.pdf</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="TOPPSS">[TOPPSS]</dt>
<dd>
<span class="refAuthor">Jarecki, S.</span>, <span class="refAuthor">Kiayias, A.</span>, <span class="refAuthor">Krawczyk, H.</span>, and <span class="refAuthor">J. Xu</span>, <span class="refTitle">"TOPPSS: Cost-Minimal Password-Protected Secret Sharing based on Threshold OPRF"</span>, <span class="refContent">Applied Cryptology and Network Security - ACNS 2017, Lecture Notes in Computer Science, vol. 10355, pp. 39-58</span>, <span class="seriesInfo">DOI 10.1007/978-3-319-61204-1_3</span>, <time datetime="2017" class="refDate">2017</time>, <span>&lt;<a href="https://doi.org/10.1007/978-3-319-61204-1_3">https://doi.org/10.1007/978-3-319-61204-1_3</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="TripleDH">[TripleDH]</dt>
<dd>
<span class="refAuthor">Marlinspike, M.</span>, <span class="refTitle">"Simplifying OTR deniability"</span>, <span class="refContent">Signal Blog</span>, <time datetime="2013-07-27" class="refDate">27 July 2013</time>, <span>&lt;<a href="https://signal.org/blog/simplifying-otr-deniability">https://signal.org/blog/simplifying-otr-deniability</a>&gt;</span>. </dd>
<dd class="break"></dd>
<dt id="WhatsAppE2E">[WhatsAppE2E]</dt>
<dd>
<span class="refAuthor">WhatsApp</span>, <span class="refTitle">"Security of End-to-End Encrypted Backups"</span>, <span class="refContent">WhatsApp Security Whitepaper</span>, <time datetime="2021-09-10" class="refDate">10 September 2021</time>, <span>&lt;<a href="https://www.whatsapp.com/security/WhatsApp_Security_Encrypted_Backups_Whitepaper.pdf">https://www.whatsapp.com/security/WhatsApp_Security_Encrypted_Backups_Whitepaper.pdf</a>&gt;</span>. </dd>
<dd class="break"></dd>
</dl>
</section>
</div>
</section>
</div>
<div id="alternate-key-recovery">
<section id="appendix-A">
<h2 id="name-alternate-key-recovery-mech">
<a href="#appendix-A" class="section-number selfRef">Appendix A. </a><a href="#name-alternate-key-recovery-mech" class="section-name selfRef">Alternate Key Recovery Mechanisms</a>
</h2>
<p id="appendix-A-1">Client authentication material can be stored and retrieved using different key
recovery mechanisms. Any key recovery mechanism that encrypts data
in the envelope <span class="bcp14">MUST</span> use an authenticated encryption scheme with random
key-robustness (or key-committing). Deviating from the key-robustness
requirement may open the protocol to attacks, e.g., <span>[<a href="#LGR20" class="cite xref">LGR20</a>]</span>.
This specification enforces this property by using a MAC over the envelope
contents.<a href="#appendix-A-1" class="pilcrow"></a></p>
<p id="appendix-A-2">We remark that <code>export_key</code> for authentication or encryption requires
no special properties from the authentication or encryption schemes
as long as <code>export_key</code> is used only after authentication material is successfully
recovered, i.e., after the MAC in <code>RecoverCredentials</code> passes verification.<a href="#appendix-A-2" class="pilcrow"></a></p>
</section>
</div>
<div id="alternate-akes">
<section id="appendix-B">
<h2 id="name-alternate-ake-instantiation">
<a href="#appendix-B" class="section-number selfRef">Appendix B. </a><a href="#name-alternate-ake-instantiation" class="section-name selfRef">Alternate AKE Instantiations</a>
</h2>
<p id="appendix-B-1">It is possible to instantiate OPAQUE with other AKEs, such as HMQV <span>[<a href="#HMQV" class="cite xref">HMQV</a>]</span> and SIGMA-I <span>[<a href="#SIGMA-I" class="cite xref">SIGMA-I</a>]</span>.
HMQV is similar to 3DH but varies in its key schedule. SIGMA-I uses digital signatures
rather than static DH keys for authentication. Specification of these instantiations is
left to future documents. A sketch of how these instantiations might change is included
in the next subsection for posterity.<a href="#appendix-B-1" class="pilcrow"></a></p>
<p id="appendix-B-2">OPAQUE may also be instantiated with any post-quantum (PQ) AKE protocol that has the message
flow above and security properties (KCI resistance and forward secrecy) outlined
in <a href="#security-considerations" class="auto internal xref">Section 10</a>. Note that such an instantiation is not quantum-safe unless
the OPRF is quantum-safe. However, an OPAQUE instantiation where the AKE protocol is quantum-safe,
but the OPRF is not, would still ensure the confidentiality and integrity of application data encrypted
under <code>session_key</code> (or a key derived from it) with a quantum-safe encryption function.
However, the only effect of a break of the OPRF by a future quantum attacker would be
the ability of this attacker to run at that time an exhaustive dictionary
attack against the old user's password and only for users whose envelopes were
harvested while in use (in the case of OPAQUE run over a TLS channel with the
server, harvesting such envelopes requires targeted active attacks).<a href="#appendix-B-2" class="pilcrow"></a></p>
<div id="hmqv-sketch">
<section id="appendix-B.1">
<h3 id="name-hmqv-instantiation-sketch">
<a href="#appendix-B.1" class="section-number selfRef">B.1. </a><a href="#name-hmqv-instantiation-sketch" class="section-name selfRef">HMQV Instantiation Sketch</a>
</h3>
<p id="appendix-B.1-1">An HMQV instantiation would work similarly to OPAQUE-3DH, differing primarily in the key
schedule <span>[<a href="#HMQV" class="cite xref">HMQV</a>]</span>. First, the key schedule <code>preamble</code> value would use a different constant prefix
-- "HMQV" instead of "3DH" -- as shown below.<a href="#appendix-B.1-1" class="pilcrow"></a></p>
<div class="sourcecode" id="appendix-B.1-2">
<pre>
preamble = concat("HMQV",
I2OSP(len(client_identity), 2), client_identity,
KE1,
I2OSP(len(server_identity), 2), server_identity,
KE2.credential_response,
KE2.auth_response.server_nonce,
KE2.auth_response.server_public_keyshare)
</pre><a href="#appendix-B.1-2" class="pilcrow"></a>
</div>
<p id="appendix-B.1-3">Second, the <code>IKM</code> derivation would change. Assuming HMQV is instantiated with a cyclic
group of prime order p with bit length L, clients would compute <code>IKM</code> as follows:<a href="#appendix-B.1-3" class="pilcrow"></a></p>
<div class="sourcecode" id="appendix-B.1-4">
<pre>
u' = (eskU + u \* skU) mod p
IKM = (epkS \* pkS^s)^u'
</pre><a href="#appendix-B.1-4" class="pilcrow"></a>
</div>
<p id="appendix-B.1-5">Likewise, servers would compute <code>IKM</code> as follows:<a href="#appendix-B.1-5" class="pilcrow"></a></p>
<div class="sourcecode" id="appendix-B.1-6">
<pre>
s' = (eskS + s \* skS) mod p
IKM = (epkU \* pkU^u)^s'
</pre><a href="#appendix-B.1-6" class="pilcrow"></a>
</div>
<p id="appendix-B.1-7">In both cases, <code>u</code> would be computed as follows:<a href="#appendix-B.1-7" class="pilcrow"></a></p>
<div class="sourcecode" id="appendix-B.1-8">
<pre>
hashInput = concat(I2OSP(len(epkU), 2), epkU,
I2OSP(len(info), 2), info,
I2OSP(len("client"), 2), "client")
u = Hash(hashInput) mod L
</pre><a href="#appendix-B.1-8" class="pilcrow"></a>
</div>
<p id="appendix-B.1-9">Likewise, <code>s</code> would be computed as follows:<a href="#appendix-B.1-9" class="pilcrow"></a></p>
<div class="sourcecode" id="appendix-B.1-10">
<pre>
hashInput = concat(I2OSP(len(epkS), 2), epkS,
I2OSP(len(info), 2), info,
I2OSP(len("server"), 2), "server")
s = Hash(hashInput) mod L
</pre><a href="#appendix-B.1-10" class="pilcrow"></a>
</div>
<p id="appendix-B.1-11">Hash is the same hash function used in the main OPAQUE protocol for key derivation.
Its output length (in bits) must be at least L.<a href="#appendix-B.1-11" class="pilcrow"></a></p>
<p id="appendix-B.1-12">Both parties should perform validation (as in <a href="#validation" class="auto internal xref">Section 10.7</a>) on each other's
public keys before computing the above parameters.<a href="#appendix-B.1-12" class="pilcrow"></a></p>
</section>
</div>
<div id="sigma-i-instantiation-sketch">
<section id="appendix-B.2">
<h3 id="name-sigma-i-instantiation-sketc">
<a href="#appendix-B.2" class="section-number selfRef">B.2. </a><a href="#name-sigma-i-instantiation-sketc" class="section-name selfRef">SIGMA-I Instantiation Sketch</a>
</h3>
<p id="appendix-B.2-1">A SIGMA-I <span>[<a href="#SIGMA-I" class="cite xref">SIGMA-I</a>]</span> instantiation differs more drastically from OPAQUE-3DH since authentication
uses digital signatures instead of Diffie-Hellman. In particular, both <code>KE2</code> and <code>KE3</code>
would carry a digital signature, computed using the server and client private keys
established during registration, respectively, as well as a MAC, where the MAC is
computed as in OPAQUE-3DH but it also covers the identity of the sender.<a href="#appendix-B.2-1" class="pilcrow"></a></p>
<p id="appendix-B.2-2">The key schedule would also change. Specifically, the key schedule <code>preamble</code> value would
use a different constant prefix -- "SIGMA-I" instead of "3DH" -- and the <code>IKM</code> computation
would use only the ephemeral public keys exchanged between client and server.<a href="#appendix-B.2-2" class="pilcrow"></a></p>
</section>
</div>
</section>
</div>
<div id="test-vectors">
<section id="appendix-C">
<h2 id="name-test-vectors">
<a href="#appendix-C" class="section-number selfRef">Appendix C. </a><a href="#name-test-vectors" class="section-name selfRef">Test Vectors</a>
</h2>
<p id="appendix-C-1">This section contains real and fake test vectors for the OPAQUE-3DH specification.
Each real test vector in <a href="#real-vectors" class="auto internal xref">Appendix C.1</a> specifies the configuration information,
protocol inputs, intermediate values computed during registration and authentication,
and protocol outputs.<a href="#appendix-C-1" class="pilcrow"></a></p>
<p id="appendix-C-2">Similarly, each fake test vector in <a href="#fake-vectors" class="auto internal xref">Appendix C.2</a> specifies
the configuration information, protocol inputs, and protocol
outputs computed during the authentication of an unknown or unregistered user. Note that <code>masking_key</code>,
<code>client_private_key</code>, and <code>client_public_key</code> are used as additional inputs as described in
<a href="#create-credential-response" class="auto internal xref">Section 6.3.2.2</a>. <code>client_public_key</code> is used as the fake <code>record</code>'s public key, and
<code>masking_key</code> is used for the fake <code>record</code>'s masking key parameter.<a href="#appendix-C-2" class="pilcrow"></a></p>
<p id="appendix-C-3">All values are encoded in hexadecimal strings. The configuration information
includes the (OPRF, Hash, KSF, KDF, MAC, Group, Context) tuple, where the Group
matches that which is used in the OPRF. The KSF used for each test vector is the
identity function (denoted Identity), which returns as output the input message
supplied to the function without any modification, i.e., <code>msg</code> = Stretch(msg).<a href="#appendix-C-3" class="pilcrow"></a></p>
<div id="real-vectors">
<section id="appendix-C.1">
<h3 id="name-real-test-vectors">
<a href="#appendix-C.1" class="section-number selfRef">C.1. </a><a href="#name-real-test-vectors" class="section-name selfRef">Real Test Vectors</a>
</h3>
<div id="opaque-3dh-real-test-vector-1">
<section id="appendix-C.1.1">
<h4 id="name-opaque-3dh-real-test-vector">
<a href="#appendix-C.1.1" class="section-number selfRef">C.1.1. </a><a href="#name-opaque-3dh-real-test-vector" class="section-name selfRef">OPAQUE-3DH Real Test Vector 1</a>
</h4>
<div id="configuration">
<section id="appendix-C.1.1.1">
<h5 id="name-configuration">
<a href="#appendix-C.1.1.1" class="section-number selfRef">C.1.1.1. </a><a href="#name-configuration" class="section-name selfRef">Configuration</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.1.1-1">
<pre>
OPRF: ristretto255-SHA512
Hash: SHA512
KSF: Identity
KDF: HKDF-SHA512
MAC: HMAC-SHA512
Group: ristretto255
Context: 4f50415155452d504f43
Nh: 64
Npk: 32
Nsk: 32
Nm: 64
Nx: 64
Nok: 32
</pre><a href="#appendix-C.1.1.1-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="input-values">
<section id="appendix-C.1.1.2">
<h5 id="name-input-values">
<a href="#appendix-C.1.1.2" class="section-number selfRef">C.1.1.2. </a><a href="#name-input-values" class="section-name selfRef">Input Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.1.2-1">
<pre>
oprf_seed: f433d0227b0b9dd54f7c4422b600e764e47fb503f1f9a0f0a47c6606b0
54a7fdc65347f1a08f277e22358bbabe26f823fca82c7848e9a75661f4ec5d5c1989e
f
credential_identifier: 31323334
password: 436f7272656374486f72736542617474657279537461706c65
envelope_nonce: ac13171b2f17bc2c74997f0fce1e1f35bec6b91fe2e12dbd323d2
3ba7a38dfec
masking_nonce: 38fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80
f612fdfc6d
server_private_key: 47451a85372f8b3537e249d7b54188091fb18edde78094b43
e2ba42b5eb89f0d
server_public_key: b2fe7af9f48cc502d016729d2fe25cdd433f2c4bc904660b2a
382c9b79df1a78
server_nonce: 71cd9960ecef2fe0d0f7494986fa3d8b2bb01963537e60efb13981e
138e3d4a1
client_nonce: da7e07376d6d6f034cfa9bb537d11b8c6b4238c334333d1f0aebb38
0cae6a6cc
client_keyshare_seed: 82850a697b42a505f5b68fcdafce8c31f0af2b581f063cf
1091933541936304b
server_keyshare_seed: 05a4f54206eef1ba2f615bc0aa285cb22f26d1153b5b40a
1e85ff80da12f982f
blind_registration: 76cfbfe758db884bebb33582331ba9f159720ca8784a2a070
a265d9c2d6abe01
blind_login: 6ecc102d2e7a7cf49617aad7bbe188556792d4acd60a1a8a8d2b65d4
b0790308
</pre><a href="#appendix-C.1.1.2-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="intermediate-values">
<section id="appendix-C.1.1.3">
<h5 id="name-intermediate-values">
<a href="#appendix-C.1.1.3" class="section-number selfRef">C.1.1.3. </a><a href="#name-intermediate-values" class="section-name selfRef">Intermediate Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.1.3-1">
<pre>
client_public_key: 76a845464c68a5d2f7e442436bb1424953b17d3e2e289ccbac
cafb57ac5c3675
auth_key: 6cd32316f18d72a9a927a83199fa030663a38ce0c11fbaef82aa9003773
0494fc555c4d49506284516edd1628c27965b7555a4ebfed2223199f6c67966dde822
randomized_password: aac48c25ab036e30750839d31d6e73007344cb1155289fb7
d329beb932e9adeea73d5d5c22a0ce1952f8aba6d66007615cd1698d4ac85ef1fcf15
0031d1435d9
envelope: ac13171b2f17bc2c74997f0fce1e1f35bec6b91fe2e12dbd323d23ba7a3
8dfec634b0f5b96109c198a8027da51854c35bee90d1e1c781806d07d49b76de6a28b
8d9e9b6c93b9f8b64d16dddd9c5bfb5fea48ee8fd2f75012a8b308605cdd8ba5
handshake_secret: 81263cb85a0cfa12450f0f388de4e92291ec4c7c7a0878b6245
50ff528726332f1298fc6cc822a432c89504347c7a2ccd70316ae3da6a15e0399e6db
3f7c1b12
server_mac_key: 0d36b26cfe38f51f804f0a9361818f32ee1ce2a4e5578653b5271
84af058d3b2d8075c296fd84d24677913d1baa109290cd81a13ed383f9091a3804e65
298dfc
client_mac_key: 91750adbac54a5e8e53b4c233cc8d369fe83b0de1b6a3cd85575e
eb0bb01a6a90a086a2cf5fe75fff2a9379c30ba9049510a33b5b0b1444a88800fc3ee
e2260d
oprf_key: 5d4c6a8b7c7138182afb4345d1fae6a9f18a1744afbcc3854f8f5a2b4b4
c6d05
</pre><a href="#appendix-C.1.1.3-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="output-values">
<section id="appendix-C.1.1.4">
<h5 id="name-output-values">
<a href="#appendix-C.1.1.4" class="section-number selfRef">C.1.1.4. </a><a href="#name-output-values" class="section-name selfRef">Output Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.1.4-1">
<pre>
registration_request: 5059ff249eb1551b7ce4991f3336205bde44a105a032e74
7d21bf382e75f7a71
registration_response: 7408a268083e03abc7097fc05b587834539065e86fb0c7
b6342fcf5e01e5b019b2fe7af9f48cc502d016729d2fe25cdd433f2c4bc904660b2a3
82c9b79df1a78
registration_upload: 76a845464c68a5d2f7e442436bb1424953b17d3e2e289ccb
accafb57ac5c36751ac5844383c7708077dea41cbefe2fa15724f449e535dd7dd562e
66f5ecfb95864eadddec9db5874959905117dad40a4524111849799281fefe3c51fa8
2785c5ac13171b2f17bc2c74997f0fce1e1f35bec6b91fe2e12dbd323d23ba7a38dfe
c634b0f5b96109c198a8027da51854c35bee90d1e1c781806d07d49b76de6a28b8d9e
9b6c93b9f8b64d16dddd9c5bfb5fea48ee8fd2f75012a8b308605cdd8ba5
KE1: c4dedb0ba6ed5d965d6f250fbe554cd45cba5dfcce3ce836e4aee778aa3cd44d
da7e07376d6d6f034cfa9bb537d11b8c6b4238c334333d1f0aebb380cae6a6cc6e29b
ee50701498605b2c085d7b241ca15ba5c32027dd21ba420b94ce60da326
KE2: 7e308140890bcde30cbcea28b01ea1ecfbd077cff62c4def8efa075aabcbb471
38fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80f612fdfc6dd6ec6
0bcdb26dc455ddf3e718f1020490c192d70dfc7e403981179d8073d1146a4f9aa1ced
4e4cd984c657eb3b54ced3848326f70331953d91b02535af44d9fedc80188ca46743c
52786e0382f95ad85c08f6afcd1ccfbff95e2bdeb015b166c6b20b92f832cc6df01e0
b86a7efd92c1c804ff865781fa93f2f20b446c8371b671cd9960ecef2fe0d0f749498
6fa3d8b2bb01963537e60efb13981e138e3d4a1c4f62198a9d6fa9170c42c3c71f197
1b29eb1d5d0bd733e40816c91f7912cc4a660c48dae03e57aaa38f3d0cffcfc21852e
bc8b405d15bd6744945ba1a93438a162b6111699d98a16bb55b7bdddfe0fc5608b23d
a246e7bd73b47369169c5c90
KE3: 4455df4f810ac31a6748835888564b536e6da5d9944dfea9e34defb9575fe5e2
661ef61d2ae3929bcf57e53d464113d364365eb7d1a57b629707ca48da18e442
export_key: 1ef15b4fa99e8a852412450ab78713aad30d21fa6966c9b8c9fb3262a
970dc62950d4dd4ed62598229b1b72794fc0335199d9f7fcc6eaedde92cc04870e63f
16
session_key: 42afde6f5aca0cfa5c163763fbad55e73a41db6b41bc87b8e7b62214
a8eedc6731fa3cb857d657ab9b3764b89a84e91ebcb4785166fbb02cedfcbdfda215b
96f
</pre><a href="#appendix-C.1.1.4-1" class="pilcrow"></a>
</div>
</section>
</div>
</section>
</div>
<div id="opaque-3dh-real-test-vector-2">
<section id="appendix-C.1.2">
<h4 id="name-opaque-3dh-real-test-vector-">
<a href="#appendix-C.1.2" class="section-number selfRef">C.1.2. </a><a href="#name-opaque-3dh-real-test-vector-" class="section-name selfRef">OPAQUE-3DH Real Test Vector 2</a>
</h4>
<div id="configuration-1">
<section id="appendix-C.1.2.1">
<h5 id="name-configuration-2">
<a href="#appendix-C.1.2.1" class="section-number selfRef">C.1.2.1. </a><a href="#name-configuration-2" class="section-name selfRef">Configuration</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.2.1-1">
<pre>
OPRF: ristretto255-SHA512
Hash: SHA512
KSF: Identity
KDF: HKDF-SHA512
MAC: HMAC-SHA512
Group: ristretto255
Context: 4f50415155452d504f43
Nh: 64
Npk: 32
Nsk: 32
Nm: 64
Nx: 64
Nok: 32
</pre><a href="#appendix-C.1.2.1-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="input-values-1">
<section id="appendix-C.1.2.2">
<h5 id="name-input-values-2">
<a href="#appendix-C.1.2.2" class="section-number selfRef">C.1.2.2. </a><a href="#name-input-values-2" class="section-name selfRef">Input Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.2.2-1">
<pre>
client_identity: 616c696365
server_identity: 626f62
oprf_seed: f433d0227b0b9dd54f7c4422b600e764e47fb503f1f9a0f0a47c6606b0
54a7fdc65347f1a08f277e22358bbabe26f823fca82c7848e9a75661f4ec5d5c1989e
f
credential_identifier: 31323334
password: 436f7272656374486f72736542617474657279537461706c65
envelope_nonce: ac13171b2f17bc2c74997f0fce1e1f35bec6b91fe2e12dbd323d2
3ba7a38dfec
masking_nonce: 38fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80
f612fdfc6d
server_private_key: 47451a85372f8b3537e249d7b54188091fb18edde78094b43
e2ba42b5eb89f0d
server_public_key: b2fe7af9f48cc502d016729d2fe25cdd433f2c4bc904660b2a
382c9b79df1a78
server_nonce: 71cd9960ecef2fe0d0f7494986fa3d8b2bb01963537e60efb13981e
138e3d4a1
client_nonce: da7e07376d6d6f034cfa9bb537d11b8c6b4238c334333d1f0aebb38
0cae6a6cc
client_keyshare_seed: 82850a697b42a505f5b68fcdafce8c31f0af2b581f063cf
1091933541936304b
server_keyshare_seed: 05a4f54206eef1ba2f615bc0aa285cb22f26d1153b5b40a
1e85ff80da12f982f
blind_registration: 76cfbfe758db884bebb33582331ba9f159720ca8784a2a070
a265d9c2d6abe01
blind_login: 6ecc102d2e7a7cf49617aad7bbe188556792d4acd60a1a8a8d2b65d4
b0790308
</pre><a href="#appendix-C.1.2.2-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="intermediate-values-1">
<section id="appendix-C.1.2.3">
<h5 id="name-intermediate-values-2">
<a href="#appendix-C.1.2.3" class="section-number selfRef">C.1.2.3. </a><a href="#name-intermediate-values-2" class="section-name selfRef">Intermediate Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.2.3-1">
<pre>
client_public_key: 76a845464c68a5d2f7e442436bb1424953b17d3e2e289ccbac
cafb57ac5c3675
auth_key: 6cd32316f18d72a9a927a83199fa030663a38ce0c11fbaef82aa9003773
0494fc555c4d49506284516edd1628c27965b7555a4ebfed2223199f6c67966dde822
randomized_password: aac48c25ab036e30750839d31d6e73007344cb1155289fb7
d329beb932e9adeea73d5d5c22a0ce1952f8aba6d66007615cd1698d4ac85ef1fcf15
0031d1435d9
envelope: ac13171b2f17bc2c74997f0fce1e1f35bec6b91fe2e12dbd323d23ba7a3
8dfec1ac902dc5589e9a5f0de56ad685ea8486210ef41449cd4d8712828913c5d2b68
0b2b3af4a26c765cff329bfb66d38ecf1d6cfa9e7a73c222c6efe0d9520f7d7c
handshake_secret: 5e723bed1e5276de2503419eba9da61ead573109c4012268323
98c7e08155b885bfe7bc93451f9d887a0c1d0c19233e40a8e47b347a9ac3907f94032
a4cff64f
server_mac_key: dad66bb9251073d17a13f8e5500f36e5998e3cde520ca0738e708
5af62fd97812eb79a745c94d0bf8a6ac17f980cf435504cf64041eeb6bb237796d2c7
f81e9a
client_mac_key: f816fe2914f7c5b29852385615d7c7f31ac122adf202d7ccd4976
06d7aabd48930323d1d02b1cc9ecd456c4de6f46c7950becb18bffd921dd5876381b5
486ffe
oprf_key: 5d4c6a8b7c7138182afb4345d1fae6a9f18a1744afbcc3854f8f5a2b4b4
c6d05
</pre><a href="#appendix-C.1.2.3-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="output-values-1">
<section id="appendix-C.1.2.4">
<h5 id="name-output-values-2">
<a href="#appendix-C.1.2.4" class="section-number selfRef">C.1.2.4. </a><a href="#name-output-values-2" class="section-name selfRef">Output Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.2.4-1">
<pre>
registration_request: 5059ff249eb1551b7ce4991f3336205bde44a105a032e74
7d21bf382e75f7a71
registration_response: 7408a268083e03abc7097fc05b587834539065e86fb0c7
b6342fcf5e01e5b019b2fe7af9f48cc502d016729d2fe25cdd433f2c4bc904660b2a3
82c9b79df1a78
registration_upload: 76a845464c68a5d2f7e442436bb1424953b17d3e2e289ccb
accafb57ac5c36751ac5844383c7708077dea41cbefe2fa15724f449e535dd7dd562e
66f5ecfb95864eadddec9db5874959905117dad40a4524111849799281fefe3c51fa8
2785c5ac13171b2f17bc2c74997f0fce1e1f35bec6b91fe2e12dbd323d23ba7a38dfe
c1ac902dc5589e9a5f0de56ad685ea8486210ef41449cd4d8712828913c5d2b680b2b
3af4a26c765cff329bfb66d38ecf1d6cfa9e7a73c222c6efe0d9520f7d7c
KE1: c4dedb0ba6ed5d965d6f250fbe554cd45cba5dfcce3ce836e4aee778aa3cd44d
da7e07376d6d6f034cfa9bb537d11b8c6b4238c334333d1f0aebb380cae6a6cc6e29b
ee50701498605b2c085d7b241ca15ba5c32027dd21ba420b94ce60da326
KE2: 7e308140890bcde30cbcea28b01ea1ecfbd077cff62c4def8efa075aabcbb471
38fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80f612fdfc6dd6ec6
0bcdb26dc455ddf3e718f1020490c192d70dfc7e403981179d8073d1146a4f9aa1ced
4e4cd984c657eb3b54ced3848326f70331953d91b02535af44d9fea502150b67fe367
95dd8914f164e49f81c7688a38928372134b7dccd50e09f8fed9518b7b2f94835b3c4
fe4c8475e7513f20eb97ff0568a39caee3fd6251876f71cd9960ecef2fe0d0f749498
6fa3d8b2bb01963537e60efb13981e138e3d4a1c4f62198a9d6fa9170c42c3c71f197
1b29eb1d5d0bd733e40816c91f7912cc4a292371e7809a9031743e943fb3b56f51de9
03552fc91fba4e7419029951c3970b2e2f0a9dea218d22e9e4e0000855bb6421aa361
0d6fc0f4033a6517030d4341
KE3: 7a026de1d6126905736c3f6d92463a08d209833eb793e46d0f7f15b3e0f62c76
43763c02bbc6b8d3d15b63250cae98171e9260f1ffa789750f534ac11a0176d5
export_key: 1ef15b4fa99e8a852412450ab78713aad30d21fa6966c9b8c9fb3262a
970dc62950d4dd4ed62598229b1b72794fc0335199d9f7fcc6eaedde92cc04870e63f
16
session_key: ae7951123ab5befc27e62e63f52cf472d6236cb386c968cc47b7e34f
866aa4bc7638356a73cfce92becf39d6a7d32a1861f12130e824241fe6cab34fbd471
a57
</pre><a href="#appendix-C.1.2.4-1" class="pilcrow"></a>
</div>
</section>
</div>
</section>
</div>
<div id="opaque-3dh-real-test-vector-3">
<section id="appendix-C.1.3">
<h4 id="name-opaque-3dh-real-test-vector-3">
<a href="#appendix-C.1.3" class="section-number selfRef">C.1.3. </a><a href="#name-opaque-3dh-real-test-vector-3" class="section-name selfRef">OPAQUE-3DH Real Test Vector 3</a>
</h4>
<div id="configuration-2">
<section id="appendix-C.1.3.1">
<h5 id="name-configuration-3">
<a href="#appendix-C.1.3.1" class="section-number selfRef">C.1.3.1. </a><a href="#name-configuration-3" class="section-name selfRef">Configuration</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.3.1-1">
<pre>
OPRF: ristretto255-SHA512
Hash: SHA512
KSF: Identity
KDF: HKDF-SHA512
MAC: HMAC-SHA512
Group: curve25519
Context: 4f50415155452d504f43
Nh: 64
Npk: 32
Nsk: 32
Nm: 64
Nx: 64
Nok: 32
</pre><a href="#appendix-C.1.3.1-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="input-values-2">
<section id="appendix-C.1.3.2">
<h5 id="name-input-values-3">
<a href="#appendix-C.1.3.2" class="section-number selfRef">C.1.3.2. </a><a href="#name-input-values-3" class="section-name selfRef">Input Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.3.2-1">
<pre>
oprf_seed: a78342ab84d3d30f08d5a9630c79bf311c31ed7f85d9d4959bf492ec67
a0eec8a67dfbf4497248eebd49e878aab173e5e4ff76354288fdd53e949a5f7c9f7f1
b
credential_identifier: 31323334
password: 436f7272656374486f72736542617474657279537461706c65
envelope_nonce: 40d6b67fdd7da7c49894750754514dbd2070a407166bd2a5237cc
a9bf44d6e0b
masking_nonce: 38fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80
f612fdfc6d
server_private_key: c06139381df63bfc91c850db0b9cfbec7a62e86d80040a41a
a7725bf0e79d564
server_public_key: a41e28269b4e97a66468cc00c5a57753e192e1527669897706
88aa90486ef031
server_nonce: 71cd9960ecef2fe0d0f7494986fa3d8b2bb01963537e60efb13981e
138e3d4a1
client_nonce: da7e07376d6d6f034cfa9bb537d11b8c6b4238c334333d1f0aebb38
0cae6a6cc
client_keyshare_seed: 82850a697b42a505f5b68fcdafce8c31f0af2b581f063cf
1091933541936304b
server_keyshare_seed: 05a4f54206eef1ba2f615bc0aa285cb22f26d1153b5b40a
1e85ff80da12f982f
blind_registration: c575731ffe1cb0ca5ba63b42c4699767b8b9ab78ba39316ee
04baddb2034a70a
blind_login: 6ecc102d2e7a7cf49617aad7bbe188556792d4acd60a1a8a8d2b65d4
b0790308
</pre><a href="#appendix-C.1.3.2-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="intermediate-values-2">
<section id="appendix-C.1.3.3">
<h5 id="name-intermediate-values-3">
<a href="#appendix-C.1.3.3" class="section-number selfRef">C.1.3.3. </a><a href="#name-intermediate-values-3" class="section-name selfRef">Intermediate Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.3.3-1">
<pre>
client_public_key: 0936ea94ab030ec332e29050d266c520e916731a052d05ced7
e0cfe751142b48
auth_key: 7e880ab484f750e80e6f839d975aff476070ce65066d85ea62523d1d576
4739d91307fac47186a4ab935e6a5c7f70cb47faa9473311947502c022cc67ae9440c
randomized_password: 3a602c295a9c323d9362fe286f104567ed6862b25dbe30fa
da844f19e41cf40047424b7118e15dc2c1a815a70fea5c8de6c30aa61440cd4b4b5e8
f3963fbb2e1
envelope: 40d6b67fdd7da7c49894750754514dbd2070a407166bd2a5237cca9bf44
d6e0b20c1e81fef28e92e897ca8287d49a55075b47c3988ff0fff367d79a3e350ccac
150b4a3ff48b4770c8e84e437b3d4e68d2b95833f7788f7eb93fa6a8afb85ecb
handshake_secret: 178c8c15e025252380c3edb1c6ad8ac52573b38d536099e2f86
5786f5e31c642608550c0c6f281c37ce259667dd72768af31630e0eb36f1096a2e642
1c2aa163
server_mac_key: f3c6a8e069c54bb0d8905139f723c9e22f5c662dc08848243a665
4c8223800019b9823523d84da2ef67ca1c14277630aace464c113be8a0a658c39e181
a8bb71
client_mac_key: b1ee7ce52dbd0ab72872924ff11596cb196bbabfc319e74aca78a
de54a0f74dd15dcf5621f6d2e79161b0c9b701381d494836dedbb86e584a65b34267a
370e01
oprf_key: 62ef7f7d9506a14600c34f642aaf6ef8019cc82a6755db4fded5248ea14
6030a
</pre><a href="#appendix-C.1.3.3-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="output-values-2">
<section id="appendix-C.1.3.4">
<h5 id="name-output-values-3">
<a href="#appendix-C.1.3.4" class="section-number selfRef">C.1.3.4. </a><a href="#name-output-values-3" class="section-name selfRef">Output Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.3.4-1">
<pre>
registration_request: 26f3dbfd76b8e5f85b4da604f42889a7d4b1bc919f65538
1a67de02c59fd5436
registration_response: 506e8f1b89c098fb89b5b6210a05f7898cafdaea221761
e8d5272fc39e0f9f08a41e28269b4e97a66468cc00c5a57753e192e15276698977068
8aa90486ef031
registration_upload: 0936ea94ab030ec332e29050d266c520e916731a052d05ce
d7e0cfe751142b486d23c6ed818882f9bdfdcf91389fcbc0b7a3faf92bd0bd6be4a1e
7730277b694fc7c6ba327fbe786af18487688e0f7c148bbd54dc2fc80c28e7a976d9e
f53c3540d6b67fdd7da7c49894750754514dbd2070a407166bd2a5237cca9bf44d6e0
b20c1e81fef28e92e897ca8287d49a55075b47c3988ff0fff367d79a3e350ccac150b
4a3ff48b4770c8e84e437b3d4e68d2b95833f7788f7eb93fa6a8afb85ecb
KE1: c4dedb0ba6ed5d965d6f250fbe554cd45cba5dfcce3ce836e4aee778aa3cd44d
da7e07376d6d6f034cfa9bb537d11b8c6b4238c334333d1f0aebb380cae6a6cc10a83
b9117d3798cb2957fbdb0268a0d63dbf9d66bde5c00c78affd80026c911
KE2: 9a0e5a1514f62e005ea098b0d8cf6750e358c4389e6add1c52aed9500fa19d00
38fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80f612fdfc6d22cc3
1127d6f0096755be3c3d2dd6287795c317aeea10c9485bf4f419a786642c19a8f151c
eb5e8767d175248c62c017de94057398d28bf0ed00d1b50ee4f812fd9afddf98af8cd
58067ca43b0633b6cadd0e9d987f89623fed4d3583bdf6910c425600e90dab3c6b351
3188a465461a67f6bbc47aeba808f7f7e2c6d66f5c3271cd9960ecef2fe0d0f749498
6fa3d8b2bb01963537e60efb13981e138e3d4a141f55f0bef355cfb34ccd468fdacad
75865ee7efef95f4cb6c25d477f720502676f06a3b806da262139bf3fa76a1090b94d
ac78bc3bc6f8747d5b35acf94eff3ec2ebe7d49b8cf16be64120b279fe92664e47be5
da7e60f08f12e91192652f79
KE3: 550e923829a544496d8316c490da2b979b78c730dd75be3a17f237a26432c19f
bba54b6a0467b1c22ecbd6794bc5fa5b04215ba1ef974c6b090baa42c5bb984f
export_key: 9dec51d6d0f6ce7e4345f10961053713b07310cc2e45872f57bbd2fe5
070fdf0fb5b77c7ddaa2f3dc5c35132df7417ad7fefe0f690ad266e5a54a21d045c9c
38
session_key: fd2fdd07c1bcc88e81c1b1d1de5ad62dfdef1c0b8209ff9d671e1fac
55ce9c34d381c1fb2703ff53a797f77daccbe33047ccc167b8105171e10ec962eea20
3aa
</pre><a href="#appendix-C.1.3.4-1" class="pilcrow"></a>
</div>
</section>
</div>
</section>
</div>
<div id="opaque-3dh-real-test-vector-4">
<section id="appendix-C.1.4">
<h4 id="name-opaque-3dh-real-test-vector-4">
<a href="#appendix-C.1.4" class="section-number selfRef">C.1.4. </a><a href="#name-opaque-3dh-real-test-vector-4" class="section-name selfRef">OPAQUE-3DH Real Test Vector 4</a>
</h4>
<div id="configuration-3">
<section id="appendix-C.1.4.1">
<h5 id="name-configuration-4">
<a href="#appendix-C.1.4.1" class="section-number selfRef">C.1.4.1. </a><a href="#name-configuration-4" class="section-name selfRef">Configuration</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.4.1-1">
<pre>
OPRF: ristretto255-SHA512
Hash: SHA512
KSF: Identity
KDF: HKDF-SHA512
MAC: HMAC-SHA512
Group: curve25519
Context: 4f50415155452d504f43
Nh: 64
Npk: 32
Nsk: 32
Nm: 64
Nx: 64
Nok: 32
</pre><a href="#appendix-C.1.4.1-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="input-values-3">
<section id="appendix-C.1.4.2">
<h5 id="name-input-values-4">
<a href="#appendix-C.1.4.2" class="section-number selfRef">C.1.4.2. </a><a href="#name-input-values-4" class="section-name selfRef">Input Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.4.2-1">
<pre>
client_identity: 616c696365
server_identity: 626f62
oprf_seed: a78342ab84d3d30f08d5a9630c79bf311c31ed7f85d9d4959bf492ec67
a0eec8a67dfbf4497248eebd49e878aab173e5e4ff76354288fdd53e949a5f7c9f7f1
b
credential_identifier: 31323334
password: 436f7272656374486f72736542617474657279537461706c65
envelope_nonce: 40d6b67fdd7da7c49894750754514dbd2070a407166bd2a5237cc
a9bf44d6e0b
masking_nonce: 38fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80
f612fdfc6d
server_private_key: c06139381df63bfc91c850db0b9cfbec7a62e86d80040a41a
a7725bf0e79d564
server_public_key: a41e28269b4e97a66468cc00c5a57753e192e1527669897706
88aa90486ef031
server_nonce: 71cd9960ecef2fe0d0f7494986fa3d8b2bb01963537e60efb13981e
138e3d4a1
client_nonce: da7e07376d6d6f034cfa9bb537d11b8c6b4238c334333d1f0aebb38
0cae6a6cc
client_keyshare_seed: 82850a697b42a505f5b68fcdafce8c31f0af2b581f063cf
1091933541936304b
server_keyshare_seed: 05a4f54206eef1ba2f615bc0aa285cb22f26d1153b5b40a
1e85ff80da12f982f
blind_registration: c575731ffe1cb0ca5ba63b42c4699767b8b9ab78ba39316ee
04baddb2034a70a
blind_login: 6ecc102d2e7a7cf49617aad7bbe188556792d4acd60a1a8a8d2b65d4
b0790308
</pre><a href="#appendix-C.1.4.2-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="intermediate-values-3">
<section id="appendix-C.1.4.3">
<h5 id="name-intermediate-values-4">
<a href="#appendix-C.1.4.3" class="section-number selfRef">C.1.4.3. </a><a href="#name-intermediate-values-4" class="section-name selfRef">Intermediate Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.4.3-1">
<pre>
client_public_key: 0936ea94ab030ec332e29050d266c520e916731a052d05ced7
e0cfe751142b48
auth_key: 7e880ab484f750e80e6f839d975aff476070ce65066d85ea62523d1d576
4739d91307fac47186a4ab935e6a5c7f70cb47faa9473311947502c022cc67ae9440c
randomized_password: 3a602c295a9c323d9362fe286f104567ed6862b25dbe30fa
da844f19e41cf40047424b7118e15dc2c1a815a70fea5c8de6c30aa61440cd4b4b5e8
f3963fbb2e1
envelope: 40d6b67fdd7da7c49894750754514dbd2070a407166bd2a5237cca9bf44
d6e0bb4c0eab6143959a650c5f6b32acf162b1fbe95bb36c5c4f99df53865c4d3537d
69061d80522d772cd0efdbe91f817f6bf7259a56e20b4eb9cbe9443702f4b759
handshake_secret: 13e7dc6afa5334b9dfffe26bee3caf744ef4add176caee464cd
eb3d37303b90de35a8bf095df84471ac77d705f12fe232f1571de1d6a001d3e808998
73a142dc
server_mac_key: a58135acfb2bde92d506cf59119729a6404ad94eba294e4b52a63
baf58cfe03f21bcf735222c7f2c27a60bd958be7f6aed50dc03a78f64e7ae4ac1ff07
1b95aa
client_mac_key: 1e1a8ba156aadc4a302f707d2193c9dab477b355f430d450dd407
ce40dc75613f76ec33dec494f8a6bfdcf951eb060dac33e6572c693954fe92e33730c
9ab0a2
oprf_key: 62ef7f7d9506a14600c34f642aaf6ef8019cc82a6755db4fded5248ea14
6030a
</pre><a href="#appendix-C.1.4.3-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="output-values-3">
<section id="appendix-C.1.4.4">
<h5 id="name-output-values-4">
<a href="#appendix-C.1.4.4" class="section-number selfRef">C.1.4.4. </a><a href="#name-output-values-4" class="section-name selfRef">Output Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.4.4-1">
<pre>
registration_request: 26f3dbfd76b8e5f85b4da604f42889a7d4b1bc919f65538
1a67de02c59fd5436
registration_response: 506e8f1b89c098fb89b5b6210a05f7898cafdaea221761
e8d5272fc39e0f9f08a41e28269b4e97a66468cc00c5a57753e192e15276698977068
8aa90486ef031
registration_upload: 0936ea94ab030ec332e29050d266c520e916731a052d05ce
d7e0cfe751142b486d23c6ed818882f9bdfdcf91389fcbc0b7a3faf92bd0bd6be4a1e
7730277b694fc7c6ba327fbe786af18487688e0f7c148bbd54dc2fc80c28e7a976d9e
f53c3540d6b67fdd7da7c49894750754514dbd2070a407166bd2a5237cca9bf44d6e0
bb4c0eab6143959a650c5f6b32acf162b1fbe95bb36c5c4f99df53865c4d3537d6906
1d80522d772cd0efdbe91f817f6bf7259a56e20b4eb9cbe9443702f4b759
KE1: c4dedb0ba6ed5d965d6f250fbe554cd45cba5dfcce3ce836e4aee778aa3cd44d
da7e07376d6d6f034cfa9bb537d11b8c6b4238c334333d1f0aebb380cae6a6cc10a83
b9117d3798cb2957fbdb0268a0d63dbf9d66bde5c00c78affd80026c911
KE2: 9a0e5a1514f62e005ea098b0d8cf6750e358c4389e6add1c52aed9500fa19d00
38fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80f612fdfc6d22cc3
1127d6f0096755be3c3d2dd6287795c317aeea10c9485bf4f419a786642c19a8f151c
eb5e8767d175248c62c017de94057398d28bf0ed00d1b50ee4f812699bff7663be3c5
d59de94d8e7e58817c7da005b39c25d25555c929e1c5cf6c1b82837b1367c839aab56
a422c0d97719426a79a16f9869cf852100597b23b5a071cd9960ecef2fe0d0f749498
6fa3d8b2bb01963537e60efb13981e138e3d4a141f55f0bef355cfb34ccd468fdacad
75865ee7efef95f4cb6c25d477f72050267cc22c87edbf3ecaca64cb33bc60dc3bfc5
51e365f0d46a7fed0e09d96f9afbb48868f5bb3c3e05a86ed8c9476fc22c58306c5a2
91be34388e09548ba9d70f39
KE3: d16344e791c3f18594d22ba068984fa18ec1e9bead662b75f66826ffd627932f
cd1ec40cd01dcf5f63f4055ebe45c7717a57a833aad360256cf1e1c20c0eae1c
export_key: 9dec51d6d0f6ce7e4345f10961053713b07310cc2e45872f57bbd2fe5
070fdf0fb5b77c7ddaa2f3dc5c35132df7417ad7fefe0f690ad266e5a54a21d045c9c
38
session_key: f6116d3aa0e4089a179713bad4d98ed5cb57e5443cae8d36ef78996f
a60f3dc6e9fcdd63c001596b06dbc1285d80211035cc0e485506b3f7a650cbf78c5bf
fc9
</pre><a href="#appendix-C.1.4.4-1" class="pilcrow"></a>
</div>
</section>
</div>
</section>
</div>
<div id="opaque-3dh-real-test-vector-5">
<section id="appendix-C.1.5">
<h4 id="name-opaque-3dh-real-test-vector-5">
<a href="#appendix-C.1.5" class="section-number selfRef">C.1.5. </a><a href="#name-opaque-3dh-real-test-vector-5" class="section-name selfRef">OPAQUE-3DH Real Test Vector 5</a>
</h4>
<div id="configuration-4">
<section id="appendix-C.1.5.1">
<h5 id="name-configuration-5">
<a href="#appendix-C.1.5.1" class="section-number selfRef">C.1.5.1. </a><a href="#name-configuration-5" class="section-name selfRef">Configuration</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.5.1-1">
<pre>
OPRF: P256-SHA256
Hash: SHA256
KSF: Identity
KDF: HKDF-SHA256
MAC: HMAC-SHA256
Group: P256_XMD:SHA-256_SSWU_RO_
Context: 4f50415155452d504f43
Nh: 32
Npk: 33
Nsk: 32
Nm: 32
Nx: 32
Nok: 32
</pre><a href="#appendix-C.1.5.1-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="input-values-4">
<section id="appendix-C.1.5.2">
<h5 id="name-input-values-5">
<a href="#appendix-C.1.5.2" class="section-number selfRef">C.1.5.2. </a><a href="#name-input-values-5" class="section-name selfRef">Input Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.5.2-1">
<pre>
oprf_seed: 62f60b286d20ce4fd1d64809b0021dad6ed5d52a2c8cf27ae6582543a0
a8dce2
credential_identifier: 31323334
password: 436f7272656374486f72736542617474657279537461706c65
envelope_nonce: a921f2a014513bd8a90e477a629794e89fec12d12206dde662ebd
cf65670e51f
masking_nonce: 38fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80
f612fdfc6d
server_private_key: c36139381df63bfc91c850db0b9cfbec7a62e86d80040a41a
a7725bf0e79d5e5
server_public_key: 035f40ff9cf88aa1f5cd4fe5fd3da9ea65a4923a5594f84fd9
f2092d6067784874
server_nonce: 71cd9960ecef2fe0d0f7494986fa3d8b2bb01963537e60efb13981e
138e3d4a1
client_nonce: ab3d33bde0e93eda72392346a7a73051110674bbf6b1b7ffab8be4f
91fdaeeb1
client_keyshare_seed: 633b875d74d1556d2a2789309972b06db21dfcc4f5ad51d
7e74d783b7cfab8dc
server_keyshare_seed: 05a4f54206eef1ba2f615bc0aa285cb22f26d1153b5b40a
1e85ff80da12f982f
blind_registration: 411bf1a62d119afe30df682b91a0a33d777972d4f2daa4b34
ca527d597078153
blind_login: c497fddf6056d241e6cf9fb7ac37c384f49b357a221eb0a802c989b9
942256c1
</pre><a href="#appendix-C.1.5.2-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="intermediate-values-4">
<section id="appendix-C.1.5.3">
<h5 id="name-intermediate-values-5">
<a href="#appendix-C.1.5.3" class="section-number selfRef">C.1.5.3. </a><a href="#name-intermediate-values-5" class="section-name selfRef">Intermediate Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.5.3-1">
<pre>
client_public_key: 03b218507d978c3db570ca994aaf36695a731ddb2db272c817
f79746fc37ae5214
auth_key: 5bd4be1602516092dc5078f8d699f5721dc1720a49fb80d8e5c16377abd
0987b
randomized_password: 06be0a1a51d56557a3adad57ba29c5510565dcd8b5078fa3
19151b9382258fb0
envelope: a921f2a014513bd8a90e477a629794e89fec12d12206dde662ebdcf6567
0e51fad30bbcfc1f8eda0211553ab9aaf26345ad59a128e80188f035fe4924fad67b8
handshake_secret: 83a932431a8f25bad042f008efa2b07c6cd0faa8285f335b636
3546a9f9b235f
server_mac_key: 13e928581febfad28855e3e7f03306d61bd69489686f621535d44
a1365b73b0d
client_mac_key: afdc53910c25183b08b930e6953c35b3466276736d9de2e9c5efa
f150f4082c5
oprf_key: 2dfb5cb9aa1476093be74ca0d43e5b02862a05f5d6972614d7433acdc66
f7f31
</pre><a href="#appendix-C.1.5.3-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="output-values-4">
<section id="appendix-C.1.5.4">
<h5 id="name-output-values-5">
<a href="#appendix-C.1.5.4" class="section-number selfRef">C.1.5.4. </a><a href="#name-output-values-5" class="section-name selfRef">Output Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.5.4-1">
<pre>
registration_request: 029e949a29cfa0bf7c1287333d2fb3dc586c41aa652f507
0d26a5315a1b50229f8
registration_response: 0350d3694c00978f00a5ce7cd08a00547e4ab5fb5fc2b2
f6717cdaa6c89136efef035f40ff9cf88aa1f5cd4fe5fd3da9ea65a4923a5594f84fd
9f2092d6067784874
registration_upload: 03b218507d978c3db570ca994aaf36695a731ddb2db272c8
17f79746fc37ae52147f0ed53532d3ae8e505ecc70d42d2b814b6b0e48156def71ea0
29148b2803aafa921f2a014513bd8a90e477a629794e89fec12d12206dde662ebdcf6
5670e51fad30bbcfc1f8eda0211553ab9aaf26345ad59a128e80188f035fe4924fad6
7b8
KE1: 037342f0bcb3ecea754c1e67576c86aa90c1de3875f390ad599a26686cdfee6e
07ab3d33bde0e93eda72392346a7a73051110674bbf6b1b7ffab8be4f91fdaeeb1022
ed3f32f318f81bab80da321fecab3cd9b6eea11a95666dfa6beeaab321280b6
KE2: 0246da9fe4d41d5ba69faa6c509a1d5bafd49a48615a47a8dd4b0823cc147648
1138fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80f612fdfc6d2f0
c547f70deaeca54d878c14c1aa5e1ab405dec833777132eea905c2fbb12504a67dcbe
0e66740c76b62c13b04a38a77926e19072953319ec65e41f9bfd2ae26837b6ce688bf
9af2542f04eec9ab96a1b9328812dc2f5c89182ed47fead61f09f71cd9960ecef2fe0
d0f7494986fa3d8b2bb01963537e60efb13981e138e3d4a103c1701353219b53acf33
7bf6456a83cefed8f563f1040b65afbf3b65d3bc9a19b50a73b145bc87a157e8c58c0
342e2047ee22ae37b63db17e0a82a30fcc4ecf7b
KE3: e97cab4433aa39d598e76f13e768bba61c682947bdcf9936035e8a3a3ebfb66e
export_key: c3c9a1b0e33ac84dd83d0b7e8af6794e17e7a3caadff289fbd9dc769a
853c64b
session_key: 484ad345715ccce138ca49e4ea362c6183f0949aaaa1125dc3bc3f80
876e7cd1
</pre><a href="#appendix-C.1.5.4-1" class="pilcrow"></a>
</div>
</section>
</div>
</section>
</div>
<div id="opaque-3dh-real-test-vector-6">
<section id="appendix-C.1.6">
<h4 id="name-opaque-3dh-real-test-vector-6">
<a href="#appendix-C.1.6" class="section-number selfRef">C.1.6. </a><a href="#name-opaque-3dh-real-test-vector-6" class="section-name selfRef">OPAQUE-3DH Real Test Vector 6</a>
</h4>
<div id="configuration-5">
<section id="appendix-C.1.6.1">
<h5 id="name-configuration-6">
<a href="#appendix-C.1.6.1" class="section-number selfRef">C.1.6.1. </a><a href="#name-configuration-6" class="section-name selfRef">Configuration</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.6.1-1">
<pre>
OPRF: P256-SHA256
Hash: SHA256
KSF: Identity
KDF: HKDF-SHA256
MAC: HMAC-SHA256
Group: P256_XMD:SHA-256_SSWU_RO_
Context: 4f50415155452d504f43
Nh: 32
Npk: 33
Nsk: 32
Nm: 32
Nx: 32
Nok: 32
</pre><a href="#appendix-C.1.6.1-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="input-values-5">
<section id="appendix-C.1.6.2">
<h5 id="name-input-values-6">
<a href="#appendix-C.1.6.2" class="section-number selfRef">C.1.6.2. </a><a href="#name-input-values-6" class="section-name selfRef">Input Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.6.2-1">
<pre>
client_identity: 616c696365
server_identity: 626f62
oprf_seed: 62f60b286d20ce4fd1d64809b0021dad6ed5d52a2c8cf27ae6582543a0
a8dce2
credential_identifier: 31323334
password: 436f7272656374486f72736542617474657279537461706c65
envelope_nonce: a921f2a014513bd8a90e477a629794e89fec12d12206dde662ebd
cf65670e51f
masking_nonce: 38fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80
f612fdfc6d
server_private_key: c36139381df63bfc91c850db0b9cfbec7a62e86d80040a41a
a7725bf0e79d5e5
server_public_key: 035f40ff9cf88aa1f5cd4fe5fd3da9ea65a4923a5594f84fd9
f2092d6067784874
server_nonce: 71cd9960ecef2fe0d0f7494986fa3d8b2bb01963537e60efb13981e
138e3d4a1
client_nonce: ab3d33bde0e93eda72392346a7a73051110674bbf6b1b7ffab8be4f
91fdaeeb1
client_keyshare_seed: 633b875d74d1556d2a2789309972b06db21dfcc4f5ad51d
7e74d783b7cfab8dc
server_keyshare_seed: 05a4f54206eef1ba2f615bc0aa285cb22f26d1153b5b40a
1e85ff80da12f982f
blind_registration: 411bf1a62d119afe30df682b91a0a33d777972d4f2daa4b34
ca527d597078153
blind_login: c497fddf6056d241e6cf9fb7ac37c384f49b357a221eb0a802c989b9
942256c1
</pre><a href="#appendix-C.1.6.2-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="intermediate-values-5">
<section id="appendix-C.1.6.3">
<h5 id="name-intermediate-values-6">
<a href="#appendix-C.1.6.3" class="section-number selfRef">C.1.6.3. </a><a href="#name-intermediate-values-6" class="section-name selfRef">Intermediate Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.6.3-1">
<pre>
client_public_key: 03b218507d978c3db570ca994aaf36695a731ddb2db272c817
f79746fc37ae5214
auth_key: 5bd4be1602516092dc5078f8d699f5721dc1720a49fb80d8e5c16377abd
0987b
randomized_password: 06be0a1a51d56557a3adad57ba29c5510565dcd8b5078fa3
19151b9382258fb0
envelope: a921f2a014513bd8a90e477a629794e89fec12d12206dde662ebdcf6567
0e51f4d7773a36a208a866301dbb2858e40dc5638017527cf91aef32d3848eebe0971
handshake_secret: 80bdcc498f22de492e90ee8101fcc7c101e158dd49c77f7c283
816ae329ed62f
server_mac_key: 0f82432fbdb5b90daf27a91a3acc42299a9590dba1b77932c2207
b4cb3d4a157
client_mac_key: 7f629eb0b1b69979b07ca1f564b3e92ed22f07569fd1d11725d93
e46731fbe71
oprf_key: 2dfb5cb9aa1476093be74ca0d43e5b02862a05f5d6972614d7433acdc66
f7f31
</pre><a href="#appendix-C.1.6.3-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="output-values-5">
<section id="appendix-C.1.6.4">
<h5 id="name-output-values-6">
<a href="#appendix-C.1.6.4" class="section-number selfRef">C.1.6.4. </a><a href="#name-output-values-6" class="section-name selfRef">Output Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.1.6.4-1">
<pre>
registration_request: 029e949a29cfa0bf7c1287333d2fb3dc586c41aa652f507
0d26a5315a1b50229f8
registration_response: 0350d3694c00978f00a5ce7cd08a00547e4ab5fb5fc2b2
f6717cdaa6c89136efef035f40ff9cf88aa1f5cd4fe5fd3da9ea65a4923a5594f84fd
9f2092d6067784874
registration_upload: 03b218507d978c3db570ca994aaf36695a731ddb2db272c8
17f79746fc37ae52147f0ed53532d3ae8e505ecc70d42d2b814b6b0e48156def71ea0
29148b2803aafa921f2a014513bd8a90e477a629794e89fec12d12206dde662ebdcf6
5670e51f4d7773a36a208a866301dbb2858e40dc5638017527cf91aef32d3848eebe0
971
KE1: 037342f0bcb3ecea754c1e67576c86aa90c1de3875f390ad599a26686cdfee6e
07ab3d33bde0e93eda72392346a7a73051110674bbf6b1b7ffab8be4f91fdaeeb1022
ed3f32f318f81bab80da321fecab3cd9b6eea11a95666dfa6beeaab321280b6
KE2: 0246da9fe4d41d5ba69faa6c509a1d5bafd49a48615a47a8dd4b0823cc147648
1138fe59af0df2c79f57b8780278f5ae47355fe1f817119041951c80f612fdfc6d2f0
c547f70deaeca54d878c14c1aa5e1ab405dec833777132eea905c2fbb12504a67dcbe
0e66740c76b62c13b04a38a77926e19072953319ec65e41f9bfd2ae268d7f10604202
1c80300e4c6f585980cf39fc51a4a6bba41b0729f9b240c729e5671cd9960ecef2fe0
d0f7494986fa3d8b2bb01963537e60efb13981e138e3d4a103c1701353219b53acf33
7bf6456a83cefed8f563f1040b65afbf3b65d3bc9a19b84922c7e5d074838a8f27859
2c53f61fb59f031e85ad480c0c71086b871e1b24
KE3: 46833578cee137775f6be3f01b80748daac5a694101ad0e9e7025480552da56a
export_key: c3c9a1b0e33ac84dd83d0b7e8af6794e17e7a3caadff289fbd9dc769a
853c64b
session_key: 27766fabd8dd88ff37fbd0ef1a491e601d10d9f016c2b28c4bd1b0fb
7511a3c3
</pre><a href="#appendix-C.1.6.4-1" class="pilcrow"></a>
</div>
</section>
</div>
</section>
</div>
</section>
</div>
<div id="fake-vectors">
<section id="appendix-C.2">
<h3 id="name-fake-test-vectors">
<a href="#appendix-C.2" class="section-number selfRef">C.2. </a><a href="#name-fake-test-vectors" class="section-name selfRef">Fake Test Vectors</a>
</h3>
<div id="opaque-3dh-fake-test-vector-1">
<section id="appendix-C.2.1">
<h4 id="name-opaque-3dh-fake-test-vector">
<a href="#appendix-C.2.1" class="section-number selfRef">C.2.1. </a><a href="#name-opaque-3dh-fake-test-vector" class="section-name selfRef">OPAQUE-3DH Fake Test Vector 1</a>
</h4>
<div id="configuration-6">
<section id="appendix-C.2.1.1">
<h5 id="name-configuration-7">
<a href="#appendix-C.2.1.1" class="section-number selfRef">C.2.1.1. </a><a href="#name-configuration-7" class="section-name selfRef">Configuration</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.2.1.1-1">
<pre>
OPRF: ristretto255-SHA512
Hash: SHA512
KSF: Identity
KDF: HKDF-SHA512
MAC: HMAC-SHA512
Group: ristretto255
Context: 4f50415155452d504f43
Nh: 64
Npk: 32
Nsk: 32
Nm: 64
Nx: 64
Nok: 32
</pre><a href="#appendix-C.2.1.1-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="input-values-6">
<section id="appendix-C.2.1.2">
<h5 id="name-input-values-7">
<a href="#appendix-C.2.1.2" class="section-number selfRef">C.2.1.2. </a><a href="#name-input-values-7" class="section-name selfRef">Input Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.2.1.2-1">
<pre>
client_identity: 616c696365
server_identity: 626f62
oprf_seed: 743fc168d1f826ad43738933e5adb23da6fb95f95a1b069f0daa0522d0
a78b617f701fc6aa46d3e7981e70de7765dfcd6b1e13e3369a582eb8dc456b10aa53b
0
credential_identifier: 31323334
masking_nonce: 9c035896a043e70f897d87180c543e7a063b83c1bb728fbd189c61
9e27b6e5a6
client_private_key: 2b98980aa95ab53a0f39f0291903d2fdf04b00c167f081416
9922df873002409
client_public_key: 84f43f9492e19c22d8bdaa4447cc3d4db1cdb5427a9f852c47
07921212c36251
server_private_key: c788585ae8b5ba2942b693b849be0c0426384e41977c18d2e
81fbe30fd7c9f06
server_public_key: 825f832667480f08b0c9069da5083ac4d0e9ee31b49c4e0310
031fea04d52966
server_nonce: 1e10f6eeab2a7a420bf09da9b27a4639645622c46358de9cf7ae813
055ae2d12
client_keyshare_seed: a270dc715dc2b4612bc7864312a05c3e9788ee1bad1f276
d1e15bdeb4c355e94
server_keyshare_seed: 360b0937f47d45f6123a4d8f0d0c0814b6120d840ebb8bc
5b4f6b62df07f78c2
masking_key: 39ebd51f0e39a07a1c2d2431995b0399bca9996c5d10014d6ebab445
3dc10ce5cef38ed3df6e56bfff40c2d8dd4671c2b4cf63c3d54860f31fe40220d690b
b71
KE1: b0a26dcaca2230b8f5e4b1bcab9c84b586140221bb8b2848486874b0be448905
42d4e61ed3f8d64cdd3b9d153343eca15b9b0d5e388232793c6376bd2d9cfd0ab641d
7f20a245a09f1d4dbb6e301661af7f352beb0791d055e48d3645232f77f
</pre><a href="#appendix-C.2.1.2-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="output-values-6">
<section id="appendix-C.2.1.3">
<h5 id="name-output-values-7">
<a href="#appendix-C.2.1.3" class="section-number selfRef">C.2.1.3. </a><a href="#name-output-values-7" class="section-name selfRef">Output Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.2.1.3-1">
<pre>
KE2: 928f79ad8df21963e91411b9f55165ba833dea918f441db967cdc09521d22925
9c035896a043e70f897d87180c543e7a063b83c1bb728fbd189c619e27b6e5a632b5a
b1bff96636144faa4f9f9afaac75dd88ea99cf5175902ae3f3b2195693f165f11929b
a510a5978e64dcdabecbd7ee1e4380ce270e58fea58e6462d92964a1aaef72698bca1
c673baeb04cc2bf7de5f3c2f5553464552d3a0f7698a9ca7f9c5e70c6cb1f706b2f17
5ab9d04bbd13926e816b6811a50b4aafa9799d5ed7971e10f6eeab2a7a420bf09da9b
27a4639645622c46358de9cf7ae813055ae2d1298251c5ba55f6b0b2d58d9ff0c88fe
4176484be62a96db6e2a8c4d431bd1bf27fe6c1d0537603835217d42ebf7b25819827
32e74892fd28211b31ed33863f0beaf75ba6f59474c0aaf9d78a60a9b2f4cd24d7ab5
4131b3c8efa192df6b72db4c
</pre><a href="#appendix-C.2.1.3-1" class="pilcrow"></a>
</div>
</section>
</div>
</section>
</div>
<div id="opaque-3dh-fake-test-vector-2">
<section id="appendix-C.2.2">
<h4 id="name-opaque-3dh-fake-test-vector-">
<a href="#appendix-C.2.2" class="section-number selfRef">C.2.2. </a><a href="#name-opaque-3dh-fake-test-vector-" class="section-name selfRef">OPAQUE-3DH Fake Test Vector 2</a>
</h4>
<div id="configuration-7">
<section id="appendix-C.2.2.1">
<h5 id="name-configuration-8">
<a href="#appendix-C.2.2.1" class="section-number selfRef">C.2.2.1. </a><a href="#name-configuration-8" class="section-name selfRef">Configuration</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.2.2.1-1">
<pre>
OPRF: ristretto255-SHA512
Hash: SHA512
KSF: Identity
KDF: HKDF-SHA512
MAC: HMAC-SHA512
Group: curve25519
Context: 4f50415155452d504f43
Nh: 64
Npk: 32
Nsk: 32
Nm: 64
Nx: 64
Nok: 32
</pre><a href="#appendix-C.2.2.1-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="input-values-7">
<section id="appendix-C.2.2.2">
<h5 id="name-input-values-8">
<a href="#appendix-C.2.2.2" class="section-number selfRef">C.2.2.2. </a><a href="#name-input-values-8" class="section-name selfRef">Input Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.2.2.2-1">
<pre>
client_identity: 616c696365
server_identity: 626f62
oprf_seed: 66e650652a8266b2205f31fdd68adeb739a05b5e650b19e7edc75e734a
1296d6088188ca46c31ae8ccbd42a52ed338c06e53645387a7efbc94b6a0449526155
e
credential_identifier: 31323334
masking_nonce: 9c035896a043e70f897d87180c543e7a063b83c1bb728fbd189c61
9e27b6e5a6
client_private_key: 288bf63470199221847bb035d99f96531adf8badd14cb1571
b48f7a506649660
client_public_key: 3c64a3153854cc9f0c23aab3c1a19106ec8bab4730736d1d00
3880a1d5a59005
server_private_key: 30fbe7e830be1fe8d2187c97414e3826040cbe49b893b6422
9bab5e85a588846
server_public_key: 78b3040047ff26572a7619617601a61b9c81899bee92f00cfc
aa5eed96863555
server_nonce: 1e10f6eeab2a7a420bf09da9b27a4639645622c46358de9cf7ae813
055ae2d12
client_keyshare_seed: a270dc715dc2b4612bc7864312a05c3e9788ee1bad1f276
d1e15bdeb4c355e94
server_keyshare_seed: 360b0937f47d45f6123a4d8f0d0c0814b6120d840ebb8bc
5b4f6b62df07f78c2
masking_key: 79ad2621b0757a447dff7108a8ae20a068ce67872095620f415ea611
c9dcc04972fa359538cd2fd6528775ca775487b2b56db642049b8a90526b975a38484
c6a
KE1: b0a26dcaca2230b8f5e4b1bcab9c84b586140221bb8b2848486874b0be448905
42d4e61ed3f8d64cdd3b9d153343eca15b9b0d5e388232793c6376bd2d9cfd0ac059b
7ba2aec863933ae48816360c7a9022e83d822704f3b0b86c0502a66e574
</pre><a href="#appendix-C.2.2.2-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="output-values-7">
<section id="appendix-C.2.2.3">
<h5 id="name-output-values-8">
<a href="#appendix-C.2.2.3" class="section-number selfRef">C.2.2.3. </a><a href="#name-output-values-8" class="section-name selfRef">Output Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.2.2.3-1">
<pre>
KE2: 6606b6fedbb33f19a81a1feb5149c600fe77252f58acd3080d7504d3dad4922f
9c035896a043e70f897d87180c543e7a063b83c1bb728fbd189c619e27b6e5a67db39
8c0f65d8c298eac430abdae4c80e82b552fb940c00f0cbcea853c0f96c1c15099f3d4
b0e83ecc249613116d605b8d77bb68bdf76994c2bc507e2dcae4176f00afed68ad25c
f3040a0e991acece31ca532117f5c12816997372ff031ad04ebcdce06c501da24e7b4
db95343456e2ed260895ec362694230a1fa20e24a9c71e10f6eeab2a7a420bf09da9b
27a4639645622c46358de9cf7ae813055ae2d122d9055eb8f83e1b497370adad5cc2a
417bf9be436a792def0c7b7ccb92b9e275d7c663104ea4655bd70570d975c05351655
d55fbfb392286edb55600a23b55ce18f8c60e0d1960c960412dd08eabc81ba7ca8ae2
b04aad65462321f51c298010
</pre><a href="#appendix-C.2.2.3-1" class="pilcrow"></a>
</div>
</section>
</div>
</section>
</div>
<div id="opaque-3dh-fake-test-vector-3">
<section id="appendix-C.2.3">
<h4 id="name-opaque-3dh-fake-test-vector-3">
<a href="#appendix-C.2.3" class="section-number selfRef">C.2.3. </a><a href="#name-opaque-3dh-fake-test-vector-3" class="section-name selfRef">OPAQUE-3DH Fake Test Vector 3</a>
</h4>
<div id="configuration-8">
<section id="appendix-C.2.3.1">
<h5 id="name-configuration-9">
<a href="#appendix-C.2.3.1" class="section-number selfRef">C.2.3.1. </a><a href="#name-configuration-9" class="section-name selfRef">Configuration</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.2.3.1-1">
<pre>
OPRF: P256-SHA256
Hash: SHA256
KSF: Identity
KDF: HKDF-SHA256
MAC: HMAC-SHA256
Group: P256_XMD:SHA-256_SSWU_RO_
Context: 4f50415155452d504f43
Nh: 32
Npk: 33
Nsk: 32
Nm: 32
Nx: 32
Nok: 32
</pre><a href="#appendix-C.2.3.1-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="input-values-8">
<section id="appendix-C.2.3.2">
<h5 id="name-input-values-9">
<a href="#appendix-C.2.3.2" class="section-number selfRef">C.2.3.2. </a><a href="#name-input-values-9" class="section-name selfRef">Input Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.2.3.2-1">
<pre>
client_identity: 616c696365
server_identity: 626f62
oprf_seed: bb1cd59e16ac09bc0cb6d528541695d7eba2239b1613a3db3ade77b362
80f725
credential_identifier: 31323334
masking_nonce: 9c035896a043e70f897d87180c543e7a063b83c1bb728fbd189c61
9e27b6e5a6
client_private_key: d423b87899fc61d014fc8330a4e26190fcfa470a3afe59243
24294af7dbbc1dd
client_public_key: 03b81708eae026a9370616c22e1e8542fe9dbebd36ce8a2661
b708e9628f4a57fc
server_private_key: 34fbe7e830be1fe8d2187c97414e3826040cbe49b893b6422
9bab5e85a5888c7
server_public_key: 0221e034c0e202fe883dcfc96802a7624166fed4cfcab4ae30
cf5f3290d01c88bf
server_nonce: 1e10f6eeab2a7a420bf09da9b27a4639645622c46358de9cf7ae813
055ae2d12
client_keyshare_seed: a270dc715dc2b4612bc7864312a05c3e9788ee1bad1f276
d1e15bdeb4c355e94
server_keyshare_seed: 360b0937f47d45f6123a4d8f0d0c0814b6120d840ebb8bc
5b4f6b62df07f78c2
masking_key: caecc6ccb4cae27cb54d8f3a1af1bac52a3d53107ce08497cdd362b1
992e4e5e
KE1: 0396875da2b4f7749bba411513aea02dc514a48d169d8a9531bd61d3af3fa9ba
ae42d4e61ed3f8d64cdd3b9d153343eca15b9b0d5e388232793c6376bd2d9cfd0a021
47a6583983cc9973b5082db5f5070890cb373d70f7ac1b41ed2305361009784
</pre><a href="#appendix-C.2.3.2-1" class="pilcrow"></a>
</div>
</section>
</div>
<div id="output-values-8">
<section id="appendix-C.2.3.3">
<h5 id="name-output-values-9">
<a href="#appendix-C.2.3.3" class="section-number selfRef">C.2.3.3. </a><a href="#name-output-values-9" class="section-name selfRef">Output Values</a>
</h5>
<div class="lang-test-vectors sourcecode" id="appendix-C.2.3.3-1">
<pre>
KE2: 0201198dcd13f9792eb75dcfa815f61b049abfe2e3e9456d4bbbceec5f442efd
049c035896a043e70f897d87180c543e7a063b83c1bb728fbd189c619e27b6e5a6fac
da65ce0a97b9085e7af07f61fd3fdd046d257cbf2183ce8766090b8041a8bf28d79dd
4c9031ddc75bb6ddb4c291e639937840e3d39fc0d5a3d6e7723c09f7945df485bcf9a
efe3fe82d149e84049e259bb5b33d6a2ff3b25e4bfb7eff0962821e10f6eeab2a7a42
0bf09da9b27a4639645622c46358de9cf7ae813055ae2d12023f82bbb24e75b8683fd
13b843cd566efae996cd0016cffdcc24ee2bc937d026f80144878749a69565b433c10
40aff67e94f79345de888a877422b9bbe21ec329
</pre><a href="#appendix-C.2.3.3-1" class="pilcrow"></a>
</div>
</section>
</div>
</section>
</div>
</section>
</div>
</section>
</div>
<div id="acknowledgments">
<section id="appendix-D">
<h2 id="name-acknowledgments">
<a href="#name-acknowledgments" class="section-name selfRef">Acknowledgments</a>
</h2>
<p id="appendix-D-1">We are indebted to the OPAQUE reviewers during CFRG's aPAKE selection
process, particularly <span class="contact-name">Julia Hesse</span> and <span class="contact-name">Bjorn Tackmann</span>. This document has benefited from comments by
multiple people. Special thanks to <span class="contact-name">Richard Barnes</span>,
<span class="contact-name">Dan Brown</span>, <span class="contact-name">Matt Campagna</span>,
<span class="contact-name">Eric Crockett</span>, <span class="contact-name">Paul Grubbs</span>,
<span class="contact-name">Fredrik Kuivinen</span>, <span class="contact-name">Stefan Marsiske</span>, <span class="contact-name">Payman Mohassel</span>, <span class="contact-name">Marta Mularczyk</span>, <span class="contact-name">Jason Resch</span>,
<span class="contact-name">Greg Rubin</span>, and <span class="contact-name">Nick Sullivan</span>. <span class="contact-name">Hugo Krawczyk</span> wishes to thank his
OPAQUE co-authors <span class="contact-name">Stas Jarecki</span> and <span class="contact-name">Jiayu Xu</span>, without whom this work would have not been
possible.<a href="#appendix-D-1" class="pilcrow"></a></p>
</section>
</div>
<div id="authors-addresses">
<section id="appendix-E">
<h2 id="name-authors-addresses">
<a href="#name-authors-addresses" class="section-name selfRef">Authors' Addresses</a>
</h2>
<address class="vcard">
<div dir="auto" class="left"><span class="fn nameRole">Daniel Bourdrez</span></div>
<div class="email">
<span>Email:</span>
<a href="mailto:d@bytema.re" class="email">d@bytema.re</a>
</div>
</address>
<address class="vcard">
<div dir="auto" class="left"><span class="fn nameRole">Hugo Krawczyk</span></div>
<div dir="auto" class="left"><span class="org">AWS</span></div>
<div class="email">
<span>Email:</span>
<a href="mailto:hugokraw@gmail.com" class="email">hugokraw@gmail.com</a>
</div>
</address>
<address class="vcard">
<div dir="auto" class="left"><span class="fn nameRole">Kevin Lewi</span></div>
<div dir="auto" class="left"><span class="org">Meta</span></div>
<div class="email">
<span>Email:</span>
<a href="mailto:lewi.kevin.k@gmail.com" class="email">lewi.kevin.k@gmail.com</a>
</div>
</address>
<address class="vcard">
<div dir="auto" class="left"><span class="fn nameRole">Christopher A. Wood</span></div>
<div dir="auto" class="left"><span class="org">Cloudflare, Inc.</span></div>
<div class="email">
<span>Email:</span>
<a href="mailto:caw@heapingbits.net" class="email">caw@heapingbits.net</a>
</div>
</address>
</section>
</div>
<script>const toc = document.getElementById("toc");
toc.querySelector("h2").addEventListener("click", e => {
toc.classList.toggle("active");
});
toc.querySelector("nav").addEventListener("click", e => {
toc.classList.remove("active");
});
</script>
</body>
</html>