ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

UDS 27服务安全访问NRC 35/36/37触发条件与排查方法

UDS 27服务安全访问NRC 35/36/37触发条件与排查方法 做 UDS 诊断开发只要碰过 27 服务SecurityAccess安全访问基本都见过 NRC 0x35、0x36、0x37。这三个负响应码在实车测试和台架测试里出现频率非常高而且往往不是独立出现NRC 35 连续报几次下一次可能就变成 NRC 36等待时间不够马上重试又会冒出来 NRC 37。很多人排查的时候习惯直接去查表看到 0x35 是“invalid key”就以为只是密钥发错了。但只要在工程现场跟过一轮问题就会知道NRC 35/36/37 背后是一整套安全访问状态管理逻辑涉及 Seed 分配、Key 计算、尝试次数统计、延迟时间计时、会话状态切换。哪个环节没对上返回的错误码都不一样。这篇文章不展开讲 UDS 协议全部基础而是直接聚焦 27 服务下的 NRC 35、36、37它们各自在什么条件下触发三个错误码之间怎么联动报文中长什么样测试时怎么复现和排查以及工程开发中怎么尽量避免把这些错误码暴露给终端用户。内容面向诊断协议开发、测试工程师以及做售后诊断工具、产线刷写工具的同行。1. 27 服务与 NRC 35/36/37 的关系27 服务在 UDS 诊断协议里负责安全访问。ISO 14229 中定义的用途很明确当 ECU 中的某些服务比如 0x2E 写入、0x31 例程控制、0x34/0x36/0x37 刷写流程涉及安全敏感操作时诊断仪必须先通过 27 服务完成解锁之后才能执行这些受限服务。标准流程分两步诊断仪发送 27 服务的 Seed 请求子功能例如 0x01/0x03/0x05/0x07 等具体取决于 EC U 支持的级别。ECU 返回 Seed 数据。诊断仪根据约定的算法计算出 Key。诊断仪发送 27 服务的 Send Key 子功能例如 0x02/0x04/0x06/0x08 等把 Key 发给 ECU。ECU 校验通过后回复肯定响应之后安全状态置为 unlocked。这个流程中任何一步出错ECU 都会返回负响应。NRC 0x35、0x36、0x37 是集中在 Key 校验阶段的三个典型错误码NRC名称含义典型触发原因0x35invalidKey密钥无效校验未通过Key 计算错误、算法不匹配、Seed 使用错误、请求时机不对0x36exceedNumberOfAttempts尝试次数超过限制连续失败次数达到阈值安全访问被锁定0x37requiredTimeDelayNotExpired延迟时间未到在要求的等待时间内重复请求需要强调的是单看 NRC 名称容易误解为“三种独立错误”。实际工程中35、36、37 经常是一条链路上的不同阶段。理解它们的联动关系比背三个错误码的含义重要得多。2. NRC 0x35 invalidKey 的触发逻辑2.1 基本判定条件NRC 0x35 表示 ECU 收到的 Key 与根据当前 Seed 计算出的期望值不一致。诊断仪发了 Send Key 请求后ECU 完成以下动作校验当前是否处于允许发送 Key 的状态。使用当前保存的 Seed 和本地算法计算期望 Key。将收到的 Key 与期望 Key 逐字节比较。不一致则返回 0x35并触发一次失败计数。从报纹上看NRC 0x35 的返回格式为请求02 27 02 [Key字节1] [Key字节2] ... 响应03 7F 27 35其中03是负响应报文长度7F是负响应服务标识27是请求的服务 ID35是 NRC。2.2 常见原因分析NRC 35 出现频率最高的原因主要有这几种**算法不匹配。**这是最常见的一种。同一个平台下不同 ECU、不同软件版本可能使用不同的 Key 算法。很多诊断仪或自动化测试脚本里配了一套算法切换到另一个 ECU 型号时没有同步更新导致 Key 校验失败。**Seed 与 Key 的对应关系错误。**27 服务流程是先用 Seed 请求拿到 Seed再用这个 Seed 计算 Key。如果诊断仪使用了上一次会话的 Seed或者使用了另一个 ECU 返回的 Seed算出来的 Key 必然不匹配。**Key 长度不一致。**有的 ECU 返回 4 字节 Seed需要 4 字节 Key有的 ECU 返回 4 字节 Seed 但 Key 是 2 字节还有的 ECU Key 中包含校验字节。诊断仪侧如果按固定长度发送一旦长度不匹配NRC 35 就来了。**字节序处理错误。**部分应用层协议会约定 Seed 的字节序大端/小端算法计算时也要按相同字节序处理。开发时最容易在这个环节出错尤其是 Seed 在整个报文中是连续多字节数据时。**未请求 Seed 直接发 Key。**有的 ECU 对状态机要求很严格如果诊断仪没有先请求 Seed直接发送 Send Key也会返回 0x35。**安全等级不匹配。**27 服务有多个安全等级Level比如 Level 1 用于读特定数据Level 3 用于刷写。不同 Level 对应不同 Seed 请求子功能和 Key 算法。诊断仪用 Level 1 的算法去回 Level 3 的 KeyECU 返回 0x35。2.3 排查方向遇到 NRC 35按以下顺序排查抓取完整交互报文确认 Seed 请求和 Send Key 请求之间是否有其他服务插入。对比 Seed 请求返回的 Seed 和计算 Key 时使用的 Seed 是否一致。确认算法输入参数Level、Seed、字节序、Key 长度是否和 ECU 软件标定一致。在测试台架上确认 ECU 当前是否处于可解锁状态。有些 ECU 在特定条件下比如点火状态、整车模式下会临时关闭安全访问。3. NRC 0x36 exceedNumberOfAttempts 的触发逻辑3.1 基本判定条件NRC 0x36 表示尝试次数超限。ECU 内部会维护一个失败计数器每次 Key 校验失败就加一。当计数达到 ECU 标定的最大尝试次数后后续的 Send Key 请求直接返回 0x36不再执行 Key 校验。不同 ECU 对这个计数器的处理不一样有的 ECU 在连续失败达到 3 次后立即锁定。有的 ECU 在 Session 切换后清零。有的 ECU 在成功解锁后清零。有的 ECU 在下次上电或特定事件后清零。这些差异通常记录在 ECU 诊断规范或功能规范中开发前一定要拿到对应文档。ISO 14229 标准本身不强制规定尝试次数上限只要求 ECU 有能力在超限后拒绝进一步尝试。3.2 报纹表现请求02 27 02 11 22 33 44 响应03 7F 27 36从收到 0x36 开始即使后续发送的 Key 是正确的只要 ECU 还处于锁定状态仍然会返回 0x36。此时不需要再重复尝试因为 ECU 不会再校验 Key。3.3 常见原因与排查方向NRC 36 出现的场景通常有以下几种**连续测试失败未复位。**自动化测试脚本中如果用例执行失败后没有主动重启 ECU 或切换会话计数器就会累加最终导致后续所有用例全部报 0x36。**算法联调阶段反复试探。**拿到一个新 ECU算法还没确认测试人员反复用不同算法试 Key很容易触发锁定。**产线或售后工具逻辑缺陷。**工具界面提醒了“密钥错误”但用户反复点击重试ECU 直接锁定后续所有诊断操作无法执行。排查 NRC 36 时需要先确认 ECU 锁定的复位方式。常见复位手段包括断开 ECU 电源重新上电。切换到默认会话再重新请求解锁。等待 ECU 设定的解锁等待时间需要查看规范。通过特定例程或服务清除安全访问失败计数这个能力一般只给产线或供应商内部使用。工程上要特别注意NRC 36 一旦出现不能简单用脚本循环重试解决问题。反复重试只会让 ECU 处于更长时间的锁定状态。4. NRC 0x37 requiredTimeDelayNotExpired 的触发逻辑4.1 基本判定条件NRC 0x37 表示延迟时间未过。很多 ECU 在安全访问失败后不只是计数还会启动一个时间延迟定时器。在定时器未到期之前即使尝试次数没有超限ECU 也会拒绝新的 Send Key 请求返回 0x37。延迟时长由 ECU 标定决定。有的填 10 秒有的填 30 秒有的甚至需要到下次下电。标准没有统一值必须看具体项目的诊断规范。4.2 与 NRC 36 的区别这两个错误码容易混淆因为都是“不能继续尝试”的意思。维度NRC 36NRC 37触发机制失败次数达到上限延迟计时器未到期是否永久可能是会话级或上电级锁定通常是定时器到期后恢复恢复方式断电、会话切换、等待指定事件等待延迟时间结束常伴现象之前大概率报过 35之前大概率报过 35 或 36有些 ECU 在两个条件同时满足时会返回优先级更高的 NRC定义在规范里。常见做法是延迟未到期时先报 0x37延迟到期后如果计数已超限则报 0x36。4.3 报纹表现请求02 27 02 11 22 33 44 响应03 7F 27 374.4 常见触发场景**失败后退出发送 Key 请求太早。**比如 ECU 设定失败后 10 秒内不能重试诊断仪在第一次收到 0x35 后立即重发就会收到 0x37。**测试脚本未处理延迟等待。**自动化用例中失败重试逻辑没有加等待时间。上一轮用例失败后下一轮用例直接重新解锁正好撞上延迟窗口。**多个诊断仪同时访问。**如果一台 ECU 同时连接了多个诊断工具一个工具触发失败另一个工具在延迟窗口内继续请求也会收到 0x37。这在台架测试中容易出现。5. 35/36/37 的联动关系与状态机理解了单个 NRC 后把它们放在一条时间线上会更清楚。假设 ECU 标定如下仅为示意实际以项目规范为准最多允许 3 次连续失败。每次失败后延迟 10 秒才能再次尝试。锁定后需要重新上电才能解除。诊断仪连续发送错误 KeyECU 的响应顺序如下尝试次数报文响应说明第 1 次0x35Key 校验失败启动失败计数和延迟计时延迟内重试0x37延迟时间未到延迟后第 2 次0x35再次失败计数加一重新计时延迟后第 3 次0x35计数达到上限之后任何尝试0x36锁定不再校验 Key从这个流程可以看出0x35 是“结果错”。0x37 是“时机不对”。0x36 是“已被锁死”。排查时要先看当前处于哪一层。收到 0x37说明 ECU 没在锁死状态只是需要等收到 0x36说明前面已经积累了多次失败要先想办法解除锁定。6. 诊断测试环境搭建与 27 服务复现步骤6.1 测试环境清单在台架或实车上验证 NRC 35/36/37需要准备以下环境组件用途诊断工具CANoe、CANalyzer、PCAN、周立功 CAN 卡等支持发送 UDS 诊断报文总线硬件对应 CAN/LIN/CAN FD 接口设备与 ECU 连接ECU 测试对象支持 27 服务的控制器拿到诊断规范诊断数据库文件CDDCANdela Diagnostic Descriptor或 ODX包含 27 服务的参数定义上位机脚本环境CAPL、Python配合 vector 或 pcan 库、或者诊断仪配置软件确认 ECU 的物理寻址和功能寻址 ID。27 服务属于安全相关服务通常使用物理寻址不推荐用功能寻址发起 27 服务请求。6.2 用 CAPL 模拟发送 27 服务请求在 CANoe 中如果工程配置了诊断描述文件可以用 CAPL 的诊断对象来发送请求。// 请求 Seed 示例 diagRequest SecurityAccess_Seed req; req.SetSubFunction(0x01); req.Send(); // 请求发送 Key 示例 diagRequest SecurityAccess_Key keyReq; keyReq.SetSubFunction(0x02); keyReq.SetParameter(Key, 0x11223344); // 按实际参数名调整 keyReq.Send();实际 CAPL 代码需要根据 CDD 文件里的诊断对象名和参数 ID 来调整。如果工程没有配置 CDD可以使用canTx等底层函数直接发送十六进制报文。6.3 用 CAN 报文方式模拟交互假设物理寻址请求 ID 为 0x7E0响应 ID 为 0x7E8发送原始 CAN 报文的流程如下发送02 27 01 接收06 67 01 11 22 33 44 发送02 27 02 11 22 33 44 接收03 7F 27 35上面的例子中ECU 返回了 Seed11 22 33 44但发送 Key 时使用的是相同值11 22 33 44显然不符合常见算法规则ECU 返回 0x35 是合理的预期结果。6.4 用 Python 脚本构造连续失败场景如果使用 PCAN 或 python-can可以写一个简单脚本连续发送错误 Key观察 ECU 返回的 NRC 变化。import can bus can.interface.Bus(channelPCAN_USBBUS1, bustypepcan) def send_and_wait(data): msg can.Message(arbitration_id0x7E0, datadata, is_extended_idFalse) bus.send(msg) resp bus.recv(timeout1) return resp.data.hex() if resp else None # 请求 Seed print(send_and_wait([0x02, 0x27, 0x01])) # 发送错误 Key触发 NRC 35 print(send_and_wait([0x02, 0x27, 0x02, 0x00, 0x00, 0x00, 0x00])) # 立即重试可能触发 NRC 37 或继续 35/36 print(send_and_wait([0x02, 0x27, 0x02, 0x00, 0x00, 0x00, 0x00]))注意不同工具库的初始化方式和消息参数有差异请以实际使用的库为准。这段代码的逻辑是演示如何连续发送请求来复现 NRC 变化不是通用生产代码。6.5 验证步骤先正常请求 Seed确认 ECU 能返回肯定响应。发送错误 Key确认收到 0x35。在延迟窗口内立即重试确认收到 0x37如果 ECU 实现了该机制。连续按标定次数发送错误 Key确认最终收到 0x36。记录整个过程中 NRC 变化序列与 ECU 诊断规范进行对比。这里需要强调第 4 步会触发 ECU 锁定。执行前确认锁定的解除方式并且在实验完成后按照规范恢复 ECU 状态避免影响后续测试。7. 实车与台架中的典型问题案例7.1 刷写流程中报 NRC 36刷写场景中刷写工具先通过 27 服务解锁再执行 0x34/0x36/0x37 刷写流程。很多刷写工具在解锁失败后会在内部自动重试。如果重试逻辑没有次数限制且 ECU 的失败计数没有被复位连续刷写几台车后同批次 ECU 可能出现 0x36。原因是上一轮刷写失败后没有下电计数器已经接近上限下一轮刷写启动时紧接着又触发错误。这种问题的解决方向是刷写工具在失败后主动执行 ECU 下电、等待足够长时间并且解锁重试次数严格控制在 ECU 允许的范围之内。7.2 售后诊断仪报 NRC 37售后诊断仪连接车辆后诊断仪先执行了一次 27 服务解锁但输入了错误密钥可能是车型匹配错误。随后诊断仪再次发送请求ECU 返回 0x37导致用户认为诊断仪卡死。排查后发现诊断仪的“重试”按钮没有等待延迟时间用户点击一次就立刻重发一次。修复方式是在工具侧加入倒计时提示在 ECU 返回 0x37 后展示剩余等待时间并禁止提前重试。7.3 自动化测试脚本随机失败自动化测试中某条用例需要执行 27 服务解锁但脚本在会话切换后没有重新请求 Seed而是直接发送上一次的 Key导致偶发 NRC 35。这种问题隐蔽性较高因为用例顺序变化时才会暴露。建议在所有调用 27 服务的用例中强制先请求 Seed 再发 Key不要复用上一次的 Key 数据。8. 常见问题排查速查表问题现象可能原因排查方式解决方案第一次发 Key 就报 0x35算法不匹配、Seed 不对、字节序错误抓包对比 Seed 和 Key核对算法参数修正算法配置确保 Seed 与 Key 对应连续失败后报 0x36失败次数达到上限检查 ECU 规范确认锁定条件按规范要求下电或切换会话解除锁定重试太早报 0x37延迟未到期查看 ECU 标定的延迟时间等待延迟结束再重试会话切换后解锁失败状态被复位或 Seed 失效检查会话切换时序切换会话后重新请求 Seed使用功能寻址发 27 服务ECU 不支持或返回 NRC检查寻址方式配置改用物理寻址多个工具同时访问报 0x37另一个工具刚触发失败检查总线上是否有其他诊断请求串行化诊断访问重新上电后仍报 0x36ECU 标定为上电锁定或需要等待更久核对规范中的解锁条件按规范操作必要时联系 ECU 供应商9. 工程开发最佳实践9.1 工具侧的防护逻辑诊断工具或刷写工具中需要实现安全访问失败管理记录失败次数达到阈值后停止自动重试。收到 0x37 时提示等待时间不立即重发。收到 0x36 时不建议反复重试引导用户执行下电操作。每次解锁前明确请求新的 Seed不缓存旧 Key。9.2 测试脚本侧的建议自动化测试脚本中所有涉及 27 服务的用例都要设计前置和后置步骤前置步骤确认 ECU 处于可解锁会话状态。执行步骤请求 Seed计算 Key发送 Key。后置步骤如果失败记录当前 NRC并按照规范清除失败计数或复位 ECU。脚本中不能写死单个重试次数而是要读取 ECU 规范中定义的阈值将重试次数设置为小于该阈值的值。9.3 数据与权限管理27 服务的安全访问 Key 算法属于敏感信息。在项目开发中建议算法模块独立管理不随 UI 项目散落各处。Key 相关日志脱敏禁止在共享日志中明文输出完整 Key。工具发布前进行安全访问模块的代码审查避免密钥算法泄露。同时必须强调27 服务安全访问本质上是为了防止未授权操作。开发、测试和使用诊断工具时必须确保已获得 ECU 供应商或整车厂的合法授权只能在授权范围内进行诊断、维修、测试或产线操作。不得利用 27 服务绕过安全限制实施未授权刷写、修改或读取受保护数据。10. 不同 OEM 项目中的差异点很多工程师在自己项目里踩过 35/36/37 的坑后换一个整车厂的项目发现同样的错误码出现逻辑完全不同这是正常现象。不同 OEM 和不同 ECU 供应商对 27 服务的实现差异非常大尝试次数上限可能不同3 次、5 次、10 次都存在。延迟时间可能从 0 秒到几十秒不等。有些 ECU 在 0x36 后只允许上电解锁。有些 ECU 允许切换扩展会话后部分复位失败计数。有些 ECU 对“成功解锁后再请求解锁”的行为有额外限制。部分控制器支持多个安全等级各等级有独立的失败计数。因此面对任何新项目第一件事不是写代码而是拿到并阅读该 ECU 的诊断规范或安全访问规范。规范中通常包含 Seed 算法、Key 算法、失败计数逻辑、延迟逻辑、解锁逻辑、每个安全等级的使用场景以及特殊注意事项。没有规范就动手实现基本是在给自己埋坑。11. 总结NRC 0x35、0x36、0x37 是 UDS 27 服务开发中最常遇到的三个负响应码也是一个安全访问状态机的三个关键节点。0x35 代表 Key 校验结果失败属于直接错误0x36 代表尝试次数超限属于锁定状态0x37 代表延迟时间未到属于时序限制。三者经常串联出现排查时必须结合完整报文序列、ECU 诊断规范中的失败计数和延迟参数、以及工具自身的重试策略才能快速定位问题。实际工程中建议在诊断工具和自动化测试脚本里把失败重试逻辑做好收到 0x37 就等收到 0x36 就别再硬试拿到规范先确认解锁条件而不是盲目发请求。把这些基础逻辑理顺NRC 35/36/37 就不会再是你项目里的疑难问题。
返回列表