news 2026/10/31 2:07:14

OPRF应用之OPAQUE增强型口令认证密钥交换协议【3】

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OPRF应用之OPAQUE增强型口令认证密钥交换协议【3】

摘要

本文是对RFC 9807所描述的增强型口令认证密钥交换协议OPAQUE的学习与梳理,包括:1)协议整体执行流程、2)注册方案和在线认证方案、3)关键模块OPRF与3DH。文章保留了原标准的章节对应关系,方便对照RFC原文阅读。

关键词:口令认证、OPAQUE、OPRF、aPAKE、3DH、密钥交换


本文导读

这是啥——这是RFC 9807 OPAQUE协议的配套学习笔记,先总览、再分模块、最后看流程,适合对照原文阅读,也适合想快速搞懂原理的读者通读一遍。

哪个读——密码协议研究者、安全开发工程师,以及正在学习PAKE、OPRF的童鞋。阅读前建议先了解OPRF(不经意伪随机函数,可参考RFC 9497)和DH密钥交换。

啷个读——建议先看第2章的架构总览,建立两个阶段和三条消息的整体印象;再按兴趣深入第3、4章的两个关键模块;第6、7章是完整的注册和登录流程,完整详情可以随时配套阅读RFC原文。

结算——OPAQUE用OPRF把口令隐蔽起来,让服务器在看不到口令的情况下,仍能和客户端完成双向认证并协商出会话密钥;即使服务器数据库泄露,攻击者也无法用彩虹表等手段批量破解口令。

5. 结构体汇总

这一章把所有结构体按使用阶段集中列一遍,主要目的是分清每个结构体在什么阶段出现。

图5-1结构体汇总图

按阶段梳理:

注册阶段(OPRF相关)

  • 客户端:注册请求RegistrationRequest,内含OPRF盲化点blinded_message
  • 服务器:注册响应RegistrationResponse,内含OPRF求值点evaluated_message、服务器公钥
  • 客户端:注册记录RegistrationRecord,内含客户端公钥、掩码密钥masking_key、信封envelope

在线阶段(OPRF + AKE相关)

  • KE1:OPRF请求credential_request(含盲化点)、AKE请求auth_request(含client_nonce、客户端临时公钥)
  • KE2:OPRF响应credential_response(含求值点、masking_nonce、密文masked_response)、AKE响应auth_response(含server_nonce、服务器临时公钥、server_mac)
  • KE3:仅含客户端认证标签client_mac

6. 注册阶段(对应第5章)

6.1 注册阶段全流程概述

注册阶段共三条消息:

  • RegistrationRequest:客户端发往服务器,只包含序列化后的OPRF盲化消息;
  • RegistrationResponse:服务器发回客户端,包含OPRF求值结果和服务器AKE公钥;
  • RegistrationRecord:客户端发往服务器,包含客户端公钥、掩码密钥和完整信封,作为服务器永久存储的用户凭证。

图6-1注册阶段交互图(复用图2-3)

下图为注册阶段密钥派生的完整数据流。

图6-4注册密钥派生数据流

OPAQUE用一个叫信封(Envelope)的结构来管理客户端凭证。信封是由客户端在注册时创建、再发给服务器存储的,而不是由服务器生成。服务器从始至终只负责保管信封,无法知道信封里密钥的具体内容,更无法在注册环节就替用户决定密钥;每次登录时服务器把信封原样发回,客户端才能恢复其中的密钥材料,供AKE使用。换句话说,服务器在整个过程中只是一个加密储物柜,钥匙始终在客户端手里。

应用可以把密钥材料和身份标识绑定。如果某一方没有指定身份,就默认用该方的公钥作为身份。应用凭证里必须包含这样几类值:

  • client_private_key、client_public_key:客户端AKE密钥
  • server_public_key:服务器AKE公钥
  • client_identity:客户端身份,如账户名或邮箱
  • server_identity:服务器身份,通常是域名

6.2 结构体——CleartextCredentials凭证(对应第4章)

6.2.1 CleartextCredentials定义

明文凭证结构体定义如下:

struct {
uint8 server_public_key[Npk]; // 服务器公钥
uint8 server_identity<1..2^16-1>; // 服务器身份,变长
uint8 client_identity<1..2^16-1>; // 客户端身份,变长
} CleartextCredentials;

这里的变长字段遵循TLS表示语言的编码规则:字段内容前加2字节的大端长度前缀。因此CleartextCredentials序列化后的字节顺序是固定的:

表6-1 CleartextCredentials序列化顺序

顺序

内容

长度

1

server_public_key

固定Npk字节

2

server_identity的长度

2字节(大端)

3

server_identity内容

长度值指定

4

client_identity的长度

2字节(大端)

5

client_identity内容

长度值指定

6.2.2 CreateCleartextCredentials(构造凭证)

cleartext_credentials = CreateCleartextCredentials(server_public_key, client_public_key, server_identity, client_identity)

  • 功能:根据应用凭证信息构造CleartextCredentials。
  • 关键步骤:如果没有提供某一方身份,就用该方公钥代替;然后组装成结构体返回。

6.3 结构体——Envelope信封(对应4.1节)

6.3.1 Envelope定义(对应4.1.1节)

struct Envelope {
uint8 envelope_nonce[Nn]; // 随机nonce
uint8 auth_tag[Nm]; // 完整性校验码
}

信封由客户端使用,目的是保证服务器公钥和双方身份的完整性,防止交互过程中身份被替换。认证标签计算:

auth_tag = MAC(auth_key, envelope_nonce || server_public_key || Encode(server_identity) || Encode(client_identity))

其中auth_key是从OPRF结果派生出的完整性密钥。

6.3.2 Store(创建信封,对应4.1.2节)

(envelope, client_public_key, masking_key, export_key) =
Store(rpwd, server_public_key, server_identity, client_identity)

  • 功能:客户端在注册时创建信封。
  • 输入:随机化口令rpwd、服务器公钥、双方身份。
  • 输出:信封、客户端公钥、掩码密钥、导出密钥。
  • 关键步骤:
    1. 随机生成envelope_nonce;
    2. 只通过KDF的Expand,从rpwd派生出四类密钥:

masking_key = Expand(rpwd, "MaskingKey", Nh) # 掩码密钥,服务器侧防枚举
auth_key = Expand(rpwd, envelope_nonce || "AuthKey", Nh) # 认证密钥,生成信封标签
export_key = Expand(rpwd, envelope_nonce || "ExportKey", Nh) # 导出密钥,应用层使用
seed = Expand(rpwd, envelope_nonce || "PrivateKey", Nseed) # 私钥种子

    1. 用seed派生客户端AKE公钥((_, client_public_key) = DeriveDiffieHellmanKeyPair(seed));
    2. 构造明文凭证,用auth_key对nonce、公钥、双方身份计算MAC;
    3. 组装成信封返回。

图6-2 Store流程图

6.3.3 Recover(恢复信封,对应4.1.3节)

(client_private_key, cleartext_credentials, export_key) = Recover(randomized_password, server_public_key, envelope, server_identity, client_identity)

  • 功能:客户端在登录时恢复信封中的凭证。
  • 输出:客户端私钥、明文凭证、导出密钥;恢复失败抛出EnvelopeRecoveryError。
  • 关键步骤:
    1. 从rpwd派生出auth_key、export_key和私钥种子;
    2. 用seed派生客户端AKE公私钥;
    3. 构造明文凭证,重算MAC,与信封里的auth_tag做恒时比较,不一致就报错并清除所有中间值;
    4. 验证通过则输出私钥、明文凭证和导出密钥。

Recover里重算MAC可以简写为:

expected_tag = MAC(auth_key, envelope.nonce || cleartext_credentials)

这与Store里那串"nonce || server_public_key || Encode(身份)"在字节上一致,因为CleartextCredentials序列化后恰好就是这些内容。

图6-3 Recover流程图

6.4 CreateRegistrationRequest(注册请求,对应5.2.1节)

(request, blind) = CreateRegistrationRequest(password)

  • 功能:客户端发起注册请求。
  • 关键步骤:执行OPRF的Blind得到(blind, blinded_element),把盲化点序列化成blinded_message,组装成RegistrationRequest:

struct {
uint8 blinded_message[Noe];
} RegistrationRequest;

盲化失败时抛出InvalidInputError。

6.5 CreateRegistrationResponse(注册响应,对应5.2.2节)

response = CreateRegistrationResponse(request, server_public_key, credential_identifier, oprf_seed)

  • 功能:服务器生成注册响应。
  • 关键步骤:
    1. 只用Expand从oprf_seed派生OPRF密钥种子:

seed = Expand(oprf_seed, credential_identifier || "OprfKey", Nok)
(oprf_key, _) = DeriveKeyPair(seed, "OPAQUE-DeriveKeyPair")

    1. 反序列化客户端的盲化点,执行BlindEvaluate;
    2. 把求值点编码,连同服务器公钥组装成RegistrationResponse:

struct {
uint8 evaluated_message[Noe];
uint8 server_public_key[Npk];
} RegistrationResponse;

6.6 FinalizeRegistrationRequest(完成注册,对应5.2.3节)

(record, export_key) = FinalizeRegistrationRequest(password, blind, response, server_identity, client_identity)

  • 功能:客户端生成注册记录,完成注册。
  • 关键步骤:
    1. 反序列化求值点,执行OPRF的Finalize得到oprf_output;
    2. 用KSF拉伸:stretched_oprf_output = Stretch(oprf_output);
    3. 用Extract得到随机化口令:

randomized_password = Extract("", oprf_output || stretched_oprf_output)

    1. 调用Store生成信封、客户端公钥、掩码密钥和导出密钥;
    2. 组装成RegistrationRecord:

struct {
uint8 client_public_key[Npk];
uint8 masking_key[Nh];
Envelope envelope;
} RegistrationRecord;

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/31 2:07:13

mfc120u.dll文件在Windows系统中出现错误解决办法

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

作者头像 李华
网站建设 2026/10/31 2:07:12

mfc100.dll文件在Windows系统中出现错误解决办法

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

作者头像 李华
网站建设 2026/10/31 2:05:09

微信小程序 canvas 组件实战——在手机上实现自由绘图

一、引言 绘图交互一直是小程序开发中最能体现“动手能力”的场景之一。本文基于案例《canvas组件》&#xff0c;介绍如何用小程序的 canvas 2D 接口实现一个自由绘图板&#xff1a;手指在画布上滑动即可留下线条&#xff0c;支持一键清空画布&#xff0c;并进一步拓展了“点击…

作者头像 李华
网站建设 2026/10/31 2:04:53

从数据孤岛到多模融合:KaiwuDB时序引擎在物联网场景的实战指南

在物联网项目的技术选型阶段&#xff0c;一个反复出现的困境是&#xff1a;时序数据需要一个专门的引擎来处理高频写入和降采样查询&#xff0c;设备台账、告警规则和用户权限又需要一个关系引擎来保证事务和关联查询的准确性。传统做法是把两者拼在一起&#xff0c;时序库负责…

作者头像 李华
网站建设 2026/10/31 2:04:53

RIDAR:通过自动检测与运行时干预保障自主科研智能体的科研完整性

RIDAR:通过自动检测与运行时干预保障自主科研智能体的科研完整性 原文网页:https://arxiv.org/html/2610.31372v2 PDF链接:https://arxiv.org/pdf/2610.31372v2 arXiv编号:arXiv:2610.31372v2 [cs.AI] 摘要 自主科研智能体被越来越多地用于自动化完成大量科学研究工作,但该…

作者头像 李华
网站建设 2026/10/31 2:04:29

圆桌对话《智能体的边界与真相:从 AI 编码到 AI 办公》直面行业共性命题:当 AI 全面接手执行类工作,人的核心价值究竟该锚定在何处?

2026 年 10 月 24 日至 25 日&#xff0c;"具身同行&#xff0c;智构未来"为主题的 2026 长沙 1024 程序员日暨 AI 构建者大会在世界计算长沙智谷拉开帷幕。大会由长沙开发者科技有限公司&#xff08;CSDN&#xff09;主办、长沙软件园有限公司协办&#xff0c;线下参…

作者头像 李华