UDS 28服务不是“输密码”,而是ECU和Tester之间的一场精密暗号交锋
你有没有遇到过这样的场景:
用诊断仪连上BMS,想读个标定参数,结果弹出“Security Access Required”;
换到刷写模式,发了10 03进扩展会话,再发27 01请求种子——CANoe抓包里秒回67 01 XX XX XX XX,可Tester端算出来的Key一发过去,ECU直接甩回来一个7F 27 35(invalidKey);
翻遍Dcm配置、查了CryptoIf日志、确认了seed没被复用、甚至把AES加密函数单步跟到了最后一行……还是失败。
这不是算法写错了,也不是密钥填反了。
这是你在和一套运行在MCU上的、毫秒级响应的、带状态守门人的动态认证系统打交道——而它根本不打算让你“猜对”。
UDS 28服务(Security Access),从来就不是ISO标准里一个冷冰冰的0x27服务编号。它是ECU在裸奔的CAN总线上,为自己筑起的第一道可信边界:不靠口令,不靠连接,只靠一次真随机、一次密钥派生、一次原子状态跃迁。下面我们就抛开协议文档的套话,从芯片寄存器、TRNG硬件、AUTOSAR调度间隙、甚至CAN FD帧间隔这些真实战场细节出发,带你真正“拿下”28服务。
它到底在做什么?三个动作,缺一不可
很多工程师把28服务理解成“先要个seed,再算个key,最后解锁”。这没错,但太静态了。实际上,ECU内部正同时运行着三套紧密咬合的机制:
- 熵源引擎:每次
27 01进来,不是调个rand()就完事——它必须触发TRNG外设,等硬件完成振荡器采样、模拟噪声提取、后处理去偏,最终吐出4字节满足NIST SP 800-90A的seed。STM32H7的RNG_CR寄存器第2位(IE)必须置1,否则Rng_GetRandomBytes()会卡死在轮询循环里; - 状态守门人:安全等级不是变量,是状态机。
SECURITY_LEVEL_0不是“没登录”,而是“拒绝一切受保护服务”的硬性拦截点。一旦进入WAITING_FOR_KEY态,Dcm模块对所有2E/31/11服务的请求都会直接返回7F xx 33(securityAccessDenied),连进DiagIf_WriteDataByIdentifier()的门都摸不到; - 时效熔断器:安全定时器不是软件
delay(3000)。它必须绑定到GPT硬件通道(比如TC2xx的GTM TOM或H7的LPTIM),中断优先级高于Dcm主任务,超时即刻清空SecurityState.seedValid并回调Dcm_ClearSecurityLevel()——这个动作甚至不能放在主循环里做,否则中断来了还来不及清标志,Tester又发来一个27 02,就会触发未定义行为。
这三者不是顺序执行,而是并发存在、互相制约。你看到的是一次CAN报文交互,背后是硬件熵源、实时定时器、诊断协议栈、加密驱动四层资源的协同调度。
种子不是“给个数”,而是一次硬件握手
很多人忽略了一个关键事实:UDS标准从不规定seed怎么生成,只规定它必须不可预测、不可重放、单次有效。这意味着,如果你在调试阶段用seed[