UDS诊断服务-27服务
2026/8/5 16:17:36 网站建设 项目流程

一、27 服务的本质:对暗号

把 ECU 想象成一栋有门禁的大楼。你想进去干活(刷写、写参数、清码),得先跟保安对暗号。

  • 你说:"我要对暗号。"→ ECU 给你一个随机数(种子 / Seed)
  • 你按约定规则把随机数变换一下,报回去→ 这就是密钥(Key)
  • 保安核对:你报的跟它算的一样吗?→ 一样就放行,不一样就拒绝

就这么简单。

27 服务是单向的:诊断仪向 ECU 证明"我是自己人"。ECU 不需要反过来向你证明它是谁。如果你需要验证 ECU 身份(比如确认对面不是伪造节点),那是读 DID、走 TLS 握手、或者 OEM 自定义协议的事,不是 27 的事。


二、报文格式:就那几个字节,多一个都是错

请求种子

27 <奇数子功能> [可选附加数据]

没有附加数据时,就 2 个字节

27 01

有附加数据时(比如 OEM 要求携带设备标识),直接跟在子功能后面:

27 01 12 34

没有"数据长度"字段。没有填充零。没有保留字节。报文总长度由传输层隐式确定,ECU 通过总长度推断数据部分有多少字节。

发送密钥

27 <偶数子功能> <密钥数据>
27 02 BA EF 21 70

子功能 0x02(安全等级 1 的"发送密钥"),后面跟 4 字节密钥。没有长度字段。

ECU 响应

场景响应
种子响应67 <奇数子功能> <种子数据>
密钥验证通过67 <偶数子功能>
否定响应7F 27 <NRC>

具体示例:

你发:27 01 ECU回:67 01 AB CD 12 34 ← 种子,4字节 你发:27 02 BA EF 21 70 ECU回:67 02 ← 验证通过,就2字节 你发:27 02 00 00 00 00 ← 故意发错 ECU回:7F 27 35 ← 密钥不对

种子长度

种子多长由 OEM 定义:4 字节、8 字节、16 字节都有可能。你从响应总长度减去 2(SID + 子功能)就知道种子有几字节。不需要额外的"长度字段"告诉你。


三、子功能配对:奇偶规则

27 服务唯一需要"记"的规则:

安全等级请求种子(奇数)发送密钥(偶数)
10x010x02
20x030x04
30x050x06
40x070x08
………………
630x7D0x7E

规律:同一等级,请求种子 = 2n−1,发送密钥 = 2n。最多 63 个安全等级。

但每个等级"能干什么",标准不管

ISO 14229-1 只规定了编号配对规则。每个等级对应什么权限、需要什么会话前提、用什么算法——全是 OEM 在诊断规范(CDD/ODX)里定义的。

你看到的"等级 1 = 读 VIN"、"等级 2 = 清 DTC"、"等级 3 = 刷写"——那是某个 OEM 自己的划分。换一个品牌,等级 1 可能压根不存在,等级 3 可能是清码权限。

永远查诊断规范。别"记"等级含义。


四、安全等级隔离:解锁了不等于万能

这是很多人踩过的坑:以为解锁了一个安全等级,就能干所有事。

标准规定:安全等级之间互相独立

ISO 14229-1 明确说:每个安全等级是独立的权限域。解锁等级 1 不代表你拥有等级 2 的权限,解锁等级 3 也不代表你自动拥有等级 1 和 2 的权限。

实际表现

你解锁了等级 1(27 01/02) → 可以执行等级 1 允许的操作 → 尝试执行等级 2 的操作 → 7F xx 33(securityAccessDenied) 你又解锁了等级 3(27 05/06) → 可以执行等级 3 允许的操作 → 等级 1 的权限还在吗?取决于 OEM 实现 → 有些 ECU:解锁新等级后,旧等级权限保留 → 有些 ECU:解锁新等级后,旧等级权限被替换

三种常见的 OEM 实现策略

策略行为典型场景
累加型解锁等级 N 后,等级 1~N 的权限全部可用老车型、低安全需求
替换型解锁等级 N 后,只有等级 N 的权限可用,旧权限失效高安全需求、新能源 BMS
独立型每个等级完全独立,互不影响,需要分别解锁最严格的安全架构

怎么知道你的 ECU 是哪种?查规范。或者实测:解锁等级 3 后,试着执行一个等级 1 的操作,看是否返回 0x33。

实操建议

如果你的诊断流程需要多个安全等级的权限:

  1. 查规范确认隔离策略
  2. 如果是替换型或独立型,按顺序从低到高解锁,或者在需要时重新解锁目标等级
  3. 不要假设"高等级包含低等级"——这个假设在很多 ECU 上是错的

五、种子不过期。安全访问不过期。

这是流传最广的两个误解,必须掰清楚。

种子没有倒计时

标准不规定种子有效期。种子在以下情况失效:

事件种子是否失效
你又请求了一个新种子✅ 旧种子被替换
会话切换(如10 01切回默认)✅ 失效
ECU 复位(11 01✅ 失效
你拿着种子想了 30 秒再发密钥❌ 不失效
你拿着种子想了 5 分钟再发密钥❌ 不失效(只要会话还在)

种子没有"5 秒有效期"、"10 秒有效期"这种说法。只要你不做上面前三件事,种子一直有效。

安全访问没有独立的"权限有效期"

安全访问的生命周期与会话绑定:

事件安全访问是否失效
会话存续中,你啥也不干不失效
你发3E 00保活不失效
S3 超时(TesterPresent 超时),会话退回默认失效(会话变了)
你主动切会话失效
ECU 复位失效
诊断仪拔线失效(会话无法保活,最终 S3 超时)

不是"30 秒没操作就回收"。只要会话活着(靠3E 00保活),安全访问一直在。

实操建议

解锁后如果你要连续做很多操作(写 VIN、写标定、跑例程),每隔 3~4 秒发一次3E 00。不是为了"保活安全访问",是为了保活会话——安全访问跟着会话走。


六、NRC 速查:别望文生义

27 服务相关的 NRC(完整版)

NRC标准名称人话翻译你大概干了什么
0x12subFunctionNotSupported这个安全等级我不认识请求了 ECU 没定义的等级
0x13incorrectMessageLengthOrInvalidFormat报文格式不对多塞了零,或少了字节
0x22conditionsNotCorrect现在不是时候前提条件不满足
0x24requestSequenceError你步骤错了没请求种子就直接发密钥;或发了密钥后又发密钥
0x31requestOutOfRange超出范围安全等级编号超了
0x33securityAccessDenied权限不够没解锁,或解锁的等级不对
0x35invalidKey密钥算错了算法不对、密钥值不对、字节序反了
0x36exceededNumberOfAttempts你错太多次了连续 N 次 0x35 后触发
0x37requiredTimeDelayNotExpired惩罚时间没到,别急触发了 0x36 后,等待期内又来请求
0x78requestCorrectlyReceived-ResponsePending在处理,等一下别重发,等最终响应
0x7FserviceNotSupportedInActiveSession当前会话不允许 27没切到对的会话

重点讲讲 0x24:requestSequenceError

这个 NRC 专门针对违反 27 服务交互顺序的情况。

触发场景:

你干了什么为什么错
没发27 01就直接发27 02没请求种子就想发密钥,ECU 不知道你要验证哪个种子
发了27 02后又发27 02密钥只能发一次,第二次就是序列错误
发了27 01拿到种子后,又发27 01(同等级)有些 ECU 认为这是序列错误(旧种子被丢弃,新种子生成);有些 ECU 允许(视为刷新种子)。查规范确认
解锁成功后,又发27 01(同等级)已经解锁了还请求种子,部分 ECU 返回 0x24

0x24 vs 0x35 的区别:

  • 0x35 = 你发了密钥,但算错了(格式对,内容错)
  • 0x24 = 你发的时机就不对(根本不该在这个时候发这个报文)

实操排查:收到 0x24 时,检查你的诊断仪状态机是不是乱了。最常见的原因是:上一轮解锁失败后,诊断仪没有重置状态,直接又发了一个27 02

最容易搞混的三个

0x35 vs 0x36:

  • 0x35 = 你这一次算错了,还能再来
  • 0x36 = 你已经连续错了好几次了,ECU 触发惩罚

0x36 vs 0x37:

  • 0x36 = "你错太多次了"(触发惩罚的那一刻)
  • 0x37 = "惩罚时间还没过,你急什么"(惩罚期内)

0x12 vs 0x31:

  • 0x12 = ECU 压根不支持这个子功能(比如 ECU 只实现了等级 1 和 2,你请求等级 5)
  • 0x31 = 子功能编号超出 ECU 定义的范围

惩罚机制(Delay Time)

第 1 次密钥错误:7F 27 35("算错了,再来") 第 2 次密钥错误:7F 27 35("又算错了") 第 3 次密钥错误:7F 27 36("你错太多次了,等 10 秒") ↓ 等待期内 你又来请求:7F 27 37("我说了等 10 秒,你急什么") ↓ 10 秒后 重新来:27 01 → 拿新种子 → 算密钥 → 27 02

注意:

  • 尝试次数上限和惩罚时间都是 OEM 定义的,标准不规定具体值
  • 惩罚期间,请求种子也会被拒绝(回 0x37)
  • 惩罚结束后,必须重新请求种子,旧种子已经无效

七、完整实操:解锁安全等级 1,从头到尾

场景:我要解锁安全等级 1,然后写一个配置参数。

先查规范:这个 ECU 的安全等级 1 需要扩展会话(10 03)。算法是简单异或,固定密钥 =11 22 33 44

第 1 步:切会话 你发:10 03 ECU回:50 03 00 32 01 F4 ("好,扩展会话已开") 第 2 步:请求种子 你发:27 01 (就 2 个字节) ECU回:67 01 AB CD 12 34 ("好,种子:AB CD 12 34,4 字节") 第 3 步:算密钥 (异或算法,固定密钥 = 11 22 33 44) AB ^ 11 = BA CD ^ 22 = EF 12 ^ 33 = 21 34 ^ 44 = 70 密钥 = BA EF 21 70 第 4 步:发送密钥 你发:27 02 BA EF 21 70 ECU回:67 02 ("验证通过。你进来了。") 第 5 步:干活 你发:2E 02 00 03 20 ECU回:6E 02 00 第 6 步:保活(如果还有后续操作) 你发:3E 00 ECU回:7E 00 第 7 步:搞定,切回默认会话 你发:10 01 ECU回:50 01 (安全访问随会话结束而失效)

整个 27 服务交互,核心就 4 个报文:27 0167 01 <seed>27 02 <key>67 02


八、AES 算法详解:高安全等级的标配

当 OEM 觉得异或、CRC 不够安全时,就会上 AES。这是目前车载 ECU 高安全等级的主流选择。

AES 在 27 服务中的角色

AES 是对称加密算法。在 27 服务中,它被当作一个"伪随机函数"使用——不是用来加密数据,而是用来把种子变换成密钥。

输入:种子(Seed)+ 预共享密钥(Secret Key) 输出:密钥(Key) Key = AES_Encrypt(Secret_Key, Seed)

ECU 和诊断仪持有相同的 Secret Key。诊断仪用 Secret Key 加密 Seed 得到 Key,发给 ECU。ECU 用同样的 Secret Key 加密同一个 Seed,对比结果。一致就通过。

AES-128 vs AES-256

参数AES-128AES-256
密钥长度16 字节32 字节
块大小16 字节(固定)16 字节(固定)
安全强度足够应对当前车载威胁更高,面向未来
ECU 计算开销较低较高(约慢 30%~40%)
典型应用多数乘用车 ECUADAS、BMS、网关等高安全 ECU

注意:AES 的块大小永远是 16 字节。这和密钥长度无关。AES-128 和 AES-256 的区别只在密钥长度,不在块大小。

种子长度与 AES 块大小的匹配问题

AES 每次处理 16 字节。但种子不一定是 16 字节。怎么办?

种子长度处理方式说明
16 字节直接加密完美匹配,一次 AES 运算
< 16 字节填充(Padding)到 16 字节常见填充方式见下文
> 16 字节分块处理CBC 模式或截断取前 16 字节

填充方式(Padding)

当种子不足 16 字节时,必须填充到 16 字节才能送入 AES。常见填充方式:

填充方式规则示例(种子 = AB CD 12 34,4 字节)
Zero Padding末尾补 0x00AB CD 12 34 00 00 00 00 00 00 00 00 00 00 00 00
PKCS#7补 N 个值为 N 的字节AB CD 12 34 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C
OEM 自定义补固定值或特定模式查规范

填充方式由 OEM 定义。用错了填充方式,算出来的密钥一定不对,但你不会收到 0x13(格式错误),只会收到 0x35(密钥错误)——因为报文格式是对的,只是内容错了。

工作模式

AES 有多种工作模式。在 27 服务中:

模式是否常用说明
ECB✅ 最常用种子作为明文块直接加密。简单、快速、无需 IV
CBC少见需要 IV(初始化向量),增加复杂度
CTR / GCM极少见通常用于数据传输加密,不用于 27 服务

绝大多数 OEM 在 27 服务中使用 AES-ECB。原因很简单:27 服务只需要一个"确定性变换",不需要流加密或认证加密的特性。ECB 在这个场景下完全够用。

密钥派生:Secret Key 从哪来?

AES 的 Secret Key 不是硬编码在代码里的字符串。通常有两种来源:

来源说明
OEM 统一分配同一平台所有 ECU 使用相同 Secret Key,诊断仪内置
ECU 个体绑定Secret Key 与 ECU 序列号/DID 绑定,每个 ECU 不同。诊断仪需要从 OEM 服务器动态获取

后者更安全(一个 ECU 的密钥泄露不影响其他 ECU),但诊断工具的实现也更复杂。

AES 调试排查清单

当你用 AES 算法却总是收到 0x35 时,按这个顺序排查:

  1. Secret Key 对不对?版本是否匹配?是否用了旧的密钥文件?
  2. 种子有没有看错?是不是把上一个种子当成了当前的?
  3. 填充方式对不对?Zero Padding 还是 PKCS#7?
  4. 工作模式对不对?ECB 还是 CBC?如果用 CBC,IV 是什么?
  5. 字节序对不对?Secret Key 和种子的字节序是大端还是小端?
  6. 输出截取规则对不对?AES 输出 16 字节,但 ECU 可能只取前 4/8 字节作为密钥。取哪几个字节?

第 6 点是最容易忽略的。AES-128-ECB 输出永远是 16 字节,但很多 ECU 只取前 4 字节或前 8 字节作为最终密钥。剩余字节丢弃。查规范确认截取规则。

一个完整的 AES-128-ECB 示例

已知: Secret Key = 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF 种子 = AB CD 12 34(4 字节) 填充方式 = Zero Padding 工作模式 = ECB 输出截取 = 前 4 字节 步骤: 1. 填充种子到 16 字节: AB CD 12 34 00 00 00 00 00 00 00 00 00 00 00 00 2. AES-128-ECB 加密: Plaintext = AB CD 12 34 00 00 00 00 00 00 00 00 00 00 00 00 Key = 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF Ciphertext = 6B 1C 4E 8A ...(16 字节输出) 3. 截取前 4 字节: Key = 6B 1C 4E 8A 4. 发送: 27 02 6B 1C 4E 8A

九、会话与安全等级的关系

标准不规定"哪个会话支持哪个安全等级"

"默认会话支持等级 1,扩展会话支持等级 2/3,编程会话支持等级 4"——这不是标准规定,是某个 OEM 的配置。

实际情况千差万别:

可能的配置说明
默认会话不允许 27很常见。想解锁?先切会话
扩展会话允许等级 1~3常见
编程会话允许等级 1~5常见
默认会话允许等级 1少见,但存在

查规范。别猜。

读 VIN 需要安全验证吗?

大多数 OEM:不需要。

你发:22 F1 90 ECU回:62 F1 90 4C 5A 57 41 ...

默认会话,无安全验证,直接读。VIN 是车辆标识,年检、保险、二手车交易都要读。

写 VIN 才需要:编程会话 + 安全验证 + 通常只允许写一次。


十、常见问题排查

27 01,ECU 回7F 27 7F

当前会话不允许 27。

→ 先切会话:10 03(或 10 02,查规范) → 再发:27 01

27 01,ECU 回7F 27 12

这个安全等级 ECU 不支持。

→ 查规范,确认 ECU 支持哪些等级 → 也许只支持等级 1(27 01/02),你发了 27 05 它不认识

发密钥,ECU 回7F 27 24

步骤错了。

→ 检查状态机:是不是没请求种子就发了密钥? → 是不是发了密钥后又发了一次密钥? → 重置诊断仪状态,重新走完整流程:27 01 → 67 01 → 27 02

发密钥,ECU 回7F 27 35

密钥算错了。排查清单:

  • 算法对不对?(异或?AES?CRC?)
  • Secret Key / 固定密钥对不对?(是不是用了旧版本?)
  • 字节序对不对?(大端还是小端?)
  • 种子有没有看错?
  • 密钥长度对不对?
  • (AES 专属)填充方式对不对?
  • (AES 专属)工作模式对不对?
  • (AES 专属)输出截取规则对不对?

发密钥,ECU 回7F 27 36

连续错太多次了。

→ 等。等惩罚时间过去(查规范,通常 10 秒~10 分钟) → 等完了,重新走:27 01 → 拿新种子 → 算密钥 → 27 02 → 旧种子已经废了,必须重新请求

惩罚期内发27 01,ECU 回7F 27 37

惩罚时间没到。

→ 继续等。别反复请求 → 等够了再发 27 01

解锁成功了,但执行操作时报7F xx 33

安全等级不对,或权限已被替换。

→ 查规范,确认操作需要什么等级 → 确认 ECU 的安全等级隔离策略(累加/替换/独立) → 如果是替换型,重新解锁目标等级

十一、传输层:CAN ID 不是 27 服务的一部分

有些资料把报文写成:

18 DA F1 00 27 01

让人以为18 DA F1 00是 27 服务报文的一部分。

不是。那是传输层的事:

内容标准
CAN 传输层CAN ID = 0x18DAF100 / 0x18DA00F1ISO 15765-4
UDS 应用层27 01/67 01 AB CD 12 34ISO 14229-1

27 服务的报文就是27 01CAN ID 负责路由,跟 27 服务的格式无关。以太网(DoIP)上,27 服务的报文还是27 01,只是搬运方式变了。


十二、27 服务在诊断流程里的位置

10 03 ← 切扩展会话 ↓ 27 01 / 27 02 ← 解锁安全等级 1 ↓ 22 F1 90 ← 读 VIN(如果需要) ↓ 10 02 ← 切编程会话(如果需要更高权限) ↓ 27 05 / 27 06 ← 解锁安全等级 3 ↓ 2E F1 90 ... ← 写 VIN ↓ 31 01 02 02 ← 校验写入(如果 OEM 定义了) ↓ 10 01 ← 切回默认会话,安全访问自动失效

27 在这个链条里是门禁卡——它本身不干活,但没有它,后面的活干不了。


十三、速查卡

┌──────────────────────────────────────────────────────────────┐ │ 27 服务(SecurityAccess)速查 │ │ │ │ 请求种子:27 <奇数> (2 字节起步) │ │ 发送密钥:27 <偶数> <key> │ │ │ │ 种子响应:67 <奇数> <seed> │ │ 密钥确认:67 <偶数> (就 2 字节) │ │ 否定响应:7F 27 <NRC> │ │ │ │ 没有"数据长度"字段 │ │ 没有种子"有效期"(标准不规定) │ │ 没有独立的"权限有效期"(与会话同生命周期) │ │ 单向验证(诊断仪 → ECU) │ │ 安全等级互相独立(隔离策略由 OEM 定义) │ │ 安全等级含义、算法、尝试次数、惩罚时间 → 全是 OEM 定义 │ │ │ │ 子功能配对: │ │ 0x01/0x02 = 等级1 0x03/0x04 = 等级2 │ │ 0x05/0x06 = 等级3 ……最多到 0x7D/0x7E = 等级63 │ │ │ │ NRC: │ │ 0x12 = 子功能不支持 │ │ 0x24 = 步骤错了(没请求种子就发密钥 / 重复发密钥) │ │ 0x33 = 权限不够(等级不对或被替换) │ │ 0x35 = 密钥错了 │ │ 0x36 = 错太多次了 │ │ 0x37 = 惩罚时间没到 │ │ 0x7F = 会话不对 │ │ │ │ AES 调试优先级: │ │ Secret Key → 种子 → 填充 → 模式 → 字节序 → 输出截取 │ │ │ │ 生命周期: │ │ 会话在 → 安全访问在 │ │ 会话断 / 切换 / 复位 → 安全访问失效 │ │ 用 3E 00 保活会话 │ └──────────────────────────────────────────────────────────────┘

写在最后

27 服务的报文格式是 UDS 里最简单的之一——请求 2 个字节起步,响应 2 个字节起步,没有子功能嵌套,没有掩码,没有例程参数。

它之所以让人觉得复杂,是因为三样东西叠在一起:安全的神秘感 + OEM 的自定义 + 算法的细节。但只要拆开看:

  • 格式:就那几个字节,标准写得清清楚楚
  • 权限:查规范,别猜
  • 算法:AES 也好异或也好,本质都是"确定性变换",调通了就是调通了

下次在台架前坐下,打开诊断工具,发一个27 01,看着 ECU 回一串种子——那一刻你会觉得,所谓"安全访问",也不过就是两个字节的事。剩下的,不过是耐心和细心。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询