尧图精选

车载CAN安全通信:AUTOSAR SecOC认证与Freshness配置

🕒 发布时间:2026/9/18 8:57:41 📁 来源:尧图网络
简介AUTOSAR_PRS_SecOcProtocol.pdf 是 AUTOSAR 组织发布的 R20-11 版《Secure Onboard Communication Protocol》规范文档面向智能驾驶、车辆网络与车载信息安全方向的工程师、架构师及高校研究者用于理解车载安全通信协议的设计依据与合规要求。文档围绕协议目的与目标、适用范围、约束与假设、限制条件、层间依赖、典型用例、需求追溯、术语缩写以及协议规范展开重点涉及安全实体、I-PDU 认证与验证流程可帮助读者把握 SecOC 在车载以太网与 CAN 等场景中的安全通信机制。资源为单一 PDF 文件压缩包约 322KB内容为 AUTOSAR 官方规范原文结构完整、章节清晰适合按目录快速检索协议条款与需求描述。目前已有 459 人浏览学习可作为智能驾驶与车辆标准方向查阅、引用和方案设计时的参考底稿。对正在推进车载安全通信、功能安全或电子电气架构开发的读者而言可据此梳理安全通信需求、核对协议实现边界并用于前期预研、技术选型与合规自查。1. 一条 CAN 报文被伪造的成本低到可以忽略组合仪表上某个报文被注入了错误的挡位信号ECU 照单全收车已经动了。这类场景在整车网络里不稀奇因为 CAN 和车载以太网本身都不带发送方身份证明谁把报文发上来接收方就信谁。AUTOSAR_PRS_SecOcProtocol.pdf 这份规范AUTOSAR FO R20-11Document ID 969给的是一层 PDU 级补丁SecOC 模块在发送侧给 Authentic I-PDU 挂上认证信息接收侧取下来重算比对确认数据来自正确的 ECU 且值没被改过。它的设计目标很直白——开销尽量小能作为 add-on 加到既有架构上所以默认走对称 MAC 而非数字签名。整车网络、网关、域控上做安全通信的人绕不开这 28 页。2. Secured I-PDU 字段布局与 Authenticator 生成截断长度和新鲜度计数器怎么定SecOC 做的事用一句话讲清楚在报文尾上贴一张既绑定内容、又绑定时间的封条。但封条怎么贴、贴多厚、时间信息放哪全由配置参数决定这些参数直接换算成 RAM、总线带宽和 CPU 的开销。R20-11 把设计拆成三层实体Authentic I-PDU 是业务数据本身Secured I-PDU 是它带上 Authentication Information 后在网络上跑的样子Authentication Information 又由 Freshness Value 的一部分和 Authenticator 的一部分拼成。任何一层长度变了收发两端的代码都得跟着改所以先看清结构再谈参数。2.1 Authentic I-PDU、Secured I-PDU 与 Authentication Information规范里把原始报文叫 Authentic I-PDU它可以是一整条 I-PDU也可以只截取其中一部分做保护。发送侧把它复制进 Secured I-PDU再在尾部追加认证信息接收侧拿到 Secured I-PDU 后要把 Authenticator 和 Freshness Value 拆出来把剩下的业务数据还原成 Authentic I-PDU 交给上层。这三者关系看似简单但工程里最容易踩的坑是「保护哪些字节」的配置有些项目只保护载荷的高 4 字节低 4 字节明文传输接收侧还原时若按整条 PDU 重算 MAC比对必然失败。一条 Secured I-PDU 的典型字段拼装关系如下Secured I-PDU 字段长度来源示例值是否参与 MAC 计算Authentic I-PDU受保护部分PDU 自身的截取配置8 字节是Authenticator截断 MACSecOCAuthInfoTruncLength24 bit否它本身是计算结果Freshness Value截断SecOCFreshnessValueTruncLength8 bit是但用完整 FV 参与表里最后一行是很多人第一次接触时容易误解的地方报文里带出去的可能只是完整 FV 的最后 8 位但 CPU 在算 MAC 时用的是 FM 给的完整计数器或时间戳。接收侧同样如此它必须能还原出与发送侧一致的完整 FV才能算出相同的 MAC。2.2 Freshness Value 与 Freshness Manager 的职责边界新鲜度不是 SecOC 模块自己产生的它来自外部的 Freshness ManagerFM。规范明确了分工每个可唯一标识的 Secured I-PDU、也就是每条安全通信链路都从 FM 取自己的新鲜度。使用计数器方案时FM 在把认证信息交给接收侧之前需要先把计数器自增否则收发两端会停在同一个值上重放攻击就挡不住了。使用时间戳方案时FM 负责提供一个单调、两侧可对齐的时间参考。FM 不参与 MAC 计算它只提供数值真正的密码学运算走 Crypto Stack——规范引用了 FIPS-180-4SHA和 FIPS 197AES也就是说 CMAC-AES-128 这类算法是常见落点。CP 平台上SecOC 通过 Csm、CryIf 往下调 Crypto Driver这意味着 Crypto 模块的性能和 key 的存储方式会直接影响 SecOC 的实时性CAN 周期报文密集的工况下要先评估这一点。提示FV 是否随报文传输和 FV 是否参与 MAC 计算是两件事。规范明确写了无论 FV 有没有出现在 Secured I-PDU 的载荷里生成 Authenticator 时都视为已使用该 FV。配置时把这两个开关混淆是初期联调收不到报文的常见原因。2.3 Authenticator 生成、截断与 Data IDAuthenticator 在对称方案下就是 MAC。生成过程是把 Data ID、受保护的业务数据、完整 Freshness Value 按约定顺序拼成一段输入交给 CMAC 算法得到完整的 128 bit 输出再按 SecOCAuthInfoTruncLength 截断只把前若干字节放进报文。截断是为了省总线带宽代价是抗暴力猜测的强度下降——24 bit 截断意味着攻击者理论上平均 2^23 次尝试就能蒙中一次所以重放窗口和错误计数必须配合起来。发送侧构造过程用 C 代码体现比看规范文字更直观/* 简化版发送侧把 Authentic I-PDU 封装为 Secured I-PDU */ #include stdint.h #include string.h #define SECOC_DATA_ID 0x0001u /* 每条安全链路唯一收发两侧必须一致 */ #define SECOC_TRUNC_LEN_BYTES 3u /* 24 bit 截断 MAC对应 SecOCAuthInfoTruncLength24 */ #define SECOC_FV_FULL_BYTES 8u /* FM 提供的完整计数器长度 */ #define SECOC_FV_TRUNC_BYTES 1u /* 报文里实际携带的 FV 长度 */ typedef struct { uint8_t authenticPdu[8]; /* 受保护的业务数据示例 8 字节 */ uint8_t fvFull[SECOC_FV_FULL_BYTES];/* FM 给出的完整新鲜度 */ } SecOCTxInput_t; void SecOC_BuildTxPdu(const SecOCTxInput_t *in, uint8_t *outSecuredPdu) { uint8_t mac[16]; /* CMAC 完整输出128 bit */ uint8_t macInput[2 8 SECOC_FV_FULL_BYTES]; uint16_t idx 0; /* 1. 业务数据原样落到 Secured I-PDU 头部 */ memcpy(outSecuredPdu, in-authenticPdu, sizeof(in-authenticPdu)); /* 2. 组装 MAC 输入Data ID 业务数据 完整 FV */ macInput[idx] (uint8_t)(SECOC_DATA_ID 8); macInput[idx] (uint8_t)(SECOC_DATA_ID 0xFFu); memcpy(macInput[idx], in-authenticPdu, sizeof(in-authenticPdu)); idx sizeof(in-authenticPdu); memcpy(macInput[idx], in-fvFull, SECOC_FV_FULL_BYTES); idx SECOC_FV_FULL_BYTES; /* 3. 计算 CMAC只把前 3 字节写进报文尾 */ AesCmac_Generate(macInput, idx, mac); memcpy(outSecuredPdu[sizeof(in-authenticPdu)], mac, SECOC_TRUNC_LEN_BYTES); /* 4. 再补 1 字节截断 FV方便接收侧对齐计数器 */ outSecuredPdu[sizeof(in-authenticPdu) SECOC_TRUNC_LEN_BYTES] in-fvFull[SECOC_FV_FULL_BYTES - SECOC_FV_TRUNC_BYTES]; }这段代码的关键在第二步Data ID 被放在 MAC 输入最前面它的作用是防止不同安全链路之间发生报文搬移——把 A 链路的 Secured I-PDU 直接抄到 B 链路上B 接收侧算出来的 MAC 会因为 Data ID 不同而立即失配。Data ID 的取值通常和 PDU ID 挂钩配置工具生成时最好保持唯一不要图省事全填 0。第三步的 AesCmac_Generate 在真实工程里不会直接调驱动而是走 Csm_MacGenerate 之类的接口由 Crypto Stack 决定算法和密钥句柄。截断长度 SECOC_TRUNC_LEN_BYTES 直接对应 SecOCAuthInfoTruncLength改大改小要同步改接收侧配置和总线负载预算。以经典 CAN 的 8 字节载荷为例扣掉 3 字节 MAC 和 1 字节 FV业务数据只剩 4 字节如果原报文本身就是 8 字节满载就必须做载荷截取把不参与保护的字段挪到 Secured I-PDU 之外。这一步在项目里往往牵动通信矩阵越早定越好。2.4 计数器同步与失步代价计数器方案下接收侧维护一个期望值只有在收到的 FV 落在接收窗口内、且 MAC 验证通过时才接受报文。规范允许用截断 FV 在报文里做粗对齐但真正判定靠的是内部计数器。一旦接收侧因为丢帧、复位或总线切换导致计数器落后发送侧太多即便报文完全合法也会被丢弃这在实测时表现为「偶发丢帧、无故障码」很容易被误判成总线问题。3. SecOC Profile 1/2/3 选型与配置参数24Bit-CMAC-8Bit-FV 还是 No-FV规范把常见组合收敛成三个 Security Profile它们的差别不在算法本身而在「认证信息和新鲜度各带多少出门」。选型决定了报文长度、总线负载和抗重放能力也决定了配置参数怎么填。Profile 1 和 Profile 2 用同样的 24 bit CMAC区别只在 FV 是否随报文传输Profile 3 是另一套方案国内项目很少用了解即可。真正需要花时间的是参数表里的几个长度字段它们之间互相牵制改一个往往要动三个。3.1 三个 Profile 的字段差异Profile别名AuthenticatorFreshness典型落地场景Profile 124Bit-CMAC-8Bit-FV24 bit CMAC8 bit FV 随报文传输载荷短、需要快速自恢复的安全信号Profile 224Bit-CMAC-No-FV24 bit CMAC不传输两侧独立维护总线负载敏感、报文位宽紧张Profile 3JASPAR按 JASPAR 定义按 JASPAR 定义特定区域方案通用性低Profile 1 因为把 FV 带在报文里接收侧即使短暂失步也能靠这 8 bit 快速重新对齐代价是每条报文多占 1 字节。Profile 2 省下这 1 字节但对 FM 两侧同步的要求更高复位后的恢复逻辑必须自己写。工程上常见的判断标准是如果这条安全链路允许在复位后有一段「静默期」重新同步选 Profile 2如果要求复位后立刻能收报文选 Profile 1。3.2 SecOCAuthInfoTruncLength 等长度参数怎么定这几个参数构成一条约束链任何一个改动都要往上下游传导SecOCAuthInfoTruncLengthAuthenticator 截断后的位数Profile 1/2 默认 24。调大到 32 会多占 1 字节安全性提升有限收益不高调到 16 以下总线省了但抗暴力猜测强度下降明显。SecOCFreshnessValueLengthFM 提供的完整 FV 长度常见 8 字节或 4 字节。它决定计数器的溢出周期8 字节计数器在 10 ms 周期报文的场景下几乎不可能走完。SecOCFreshnessValueTruncLength报文里实际携带的 FV 位数Profile 1 取 8Profile 2 取 0。这个值不能大于完整 FV 长度否则接收侧无从还原。SecOCDataId每条安全链路的唯一标识参与 MAC 计算取值的唯一性必须在通信矩阵层面保证。以一条 8 字节 CAN 报文为例按 Profile 1 配置 24 bit MAC 加 8 bit FVSecured I-PDU 总长变成 12 字节超出经典 CAN 单帧容量必须启用 CAN FD 或者把协议改成在不保护字段之外只取 4 字节保护。很多项目在这里第一次发现通信矩阵预留的位宽不够需要提前和网络设计方确认。这也是为什么规范强调「对既有系统的影响要尽量小」——它想的是加一层保护而不是把总线重新设计一遍。3.3 非对称签名方案下的三处改动规范用全套对称密码学词汇描述但留了口子允许非对称方案。改用数字签名后配置上有三处必须改改错任何一处都会导致收发两端行为不一致第一密钥模型从「收发共享一把密钥」变成「发送侧私钥 接收侧公钥」私钥不能出现在接收侧公钥不能反推私钥。第二SecOCAuthInfoTruncLength 必须设成完整签名长度因为签名验证需要完整输入截断后无法验证这一点和 MAC 截断的直觉完全相反。第三接收侧不再是「自己重算一遍再比对」而是调用验证算法输入是受保护数据加完整计数器加签名输出一个布尔结果。第一点和第三点工程上的含义是非对称方案的接收侧代码结构和对称方案完全不同不能靠加个开关切过去。3.4 ECUC 配置片段示例在 AUTOSAR 工具链里这些参数最终落到 ECUC 模块的配置容器中。下面是一段简化后的 ARXML 片段表示一条安全链路的通用配置ECUC-CONTAINER-VALUE SHORT-NAMESecOCConfig_EngineStatus/SHORT-NAME DEFINITION-REF DESTECUC-PARAM-CONF-CONTAINER-DEF /AUTOSAR/EcucDefs/SecOC/SecOCGeneral /DEFINITION-REF PARAMETER-VALUES ECUC-NUMERICAL-PARAM-VALUE DEFINITION-REF DESTECUC-INTEGER-PARAM-DEF /AUTOSAR/EcucDefs/SecOC/SecOCGeneral/SecOCAuthInfoTruncLength /DEFINITION-REF VALUE24/VALUE /ECUC-NUMERICAL-PARAM-VALUE ECUC-NUMERICAL-PARAM-VALUE DEFINITION-REF DESTECUC-INTEGER-PARAM-DEF /AUTOSAR/EcucDefs/SecOC/SecOCGeneral/SecOCFreshnessValueTruncLength /DEFINITION-REF VALUE8/VALUE /ECUC-NUMERICAL-PARAM-VALUE ECUC-NUMERICAL-PARAM-VALUE DEFINITION-REF DESTECUC-INTEGER-PARAM-DEF /AUTOSAR/EcucDefs/SecOC/SecOCGeneral/SecOCDataId /DEFINITION-REF VALUE1/VALUE /ECUC-NUMERICAL-PARAM-VALUE /PARAMETER-VALUES /ECUC-CONTAINER-VALUE这段配置里 SecOCDataId 的取值必须和发送侧一致而 SecOCAuthInfoTruncLength 和 SecOCFreshnessValueTruncLength 共同决定报文长度。工具链生成代码后建议在集成阶段用总线工具抓一帧 Secured I-PDU手工核对尾部的 MAC 字节数和 FV 字节数比对着 ARXML 反查快得多。4. 接收侧验证失败排查Freshness 失步、重放窗口与 DEM 上报发送侧跑通不代表链路能用接收侧才是工作量的大头。SecOC 的验证是「全对才放行」FV 窗口、MAC 比对、Data ID 任何一项不对报文都会被静默丢弃上层应用只会看到数据不再更新。排查这类问题时把失败原因分类比逐条抓包有效得多。规范在接收侧定义了验证成功的处理路径、跳过认证的特例以及错误处理与丢弃策略这三块合起来就是排查地图。4.1 验证成功的交付路径接收侧收到 Secured I-PDU 后先提取 Authenticator 和 FV再用本地 FV 和受保护数据重算 MAC与收到的截断 MAC 逐位比对同时检查 FV 是否落在接收窗口内。两项都通过时把 Authentic I-PDU 通过 PduR 向上交付并更新本地 Freshness 计数器。规范里还留了一个「跳过认证」的特例某些 Secured I-PDU 在配置上允许不做验证直接放行这通常用于开发阶段或诊断报文量产配置里要确认这个开关处于关闭状态。注意交付路径上还有一道坎。SecOC 验证通过并不等于上层一定收到数据PduR 的路由表、上层 SWC 的接收使能、以及 CanTp 分段场景下的重组顺序都可能把报文拦掉。排查顺序应该是先确认 SecOC 侧验证结果再看 PduR 路由最后看应用层。4.2 验证失败的分类与丢弃策略接收侧验证失败可以拆成几类每类的处理动作不同失败类型触发条件常见处理MAC 失配重算 MAC 与收到的截断值不一致丢弃报文累加验证失败计数FV 超窗口收到的 FV 落在接收窗口之外丢弃并触发重新同步FV 重复FV 等于或小于已用过的值判定为重放丢弃并计数长度/Routing 错误Secured I-PDU 长度与配置不符丢弃并上报开发错误MAC 失配的排查方向是收发两侧的 Data ID、密钥、算法、FV 是否一致任何一项不同都会持续失配而不是偶发。FV 超窗口和重复则通常是偶发先看丢帧率和复位记录。规范对错误上报的要求和 DEM 模块的接口是对齐的验证失败计数最终会走 Dem_SetEventStatus 落到故障事件里配置阶段要给这类事件分配好事件 ID 和去抖策略否则一次总线抖动就会刷出一堆故障码。4.3 计数器失步的恢复手段计数器失步最常见的诱因是接收侧 ECU 复位而发送侧没有复位发送侧计数器已经跑到很远的地方。恢复逻辑通常这样做接收侧在连续若干次 FV 超窗口后主动向 FM 请求重新同步或者请求发送侧下发一次带完整 FV 的特殊报文。这段逻辑不在 SecOC 模块内部需要应用层或 FM 配合实现属于项目自研部分。/* 接收侧验证流程骨架仅示意判定顺序 */ SecOC_VerifyResultType SecOC_VerifyRxPdu(const uint8_t *securedPdu, uint16_t securedLen) { uint8_t rxMac[3]; uint8_t calcMac[16]; uint8_t macInput[2 8 8]; uint32_t rxFv, localFv; /* 1. 长度自检与配置的 12 字节8 业务 3 MAC 1 FV比对 */ if (securedLen ! SECOC_EXPECTED_LEN) { return SECOC_E_LENGTH; /* 走开发错误上报 */ } /* 2. 取出报文尾部的截断 MAC 和截断 FV */ memcpy(rxMac, securedPdu[8], 3); rx securedPdu[11]; localFv FreshnessManager_GetCurrent(0x0001u); /* 3. 用本地完整 FV 参与计算而非报文里的 1 字节 */ BuildMacInput(macInput, securedPdu, localFv); AesCmac_Generate(macInput, sizeof(macInput), calcMac); /* 4. 先比 MAC 再判窗口避免把噪声当成计数器问题 */ if (memcmp(rxMac, calcMac, 3) ! 0) { return SECOC_E_MAC; /* 大概率是配置不一致 */ } if (!Freshness_InWindow(rx, localFv)) { return SECOC_E_FRESHNESS; /* 触发重新同步 */ } return SECOC_E_OK; }这段骨架把判定顺序固定成「长度、MAC、窗口」好处是能把配置类问题和同步类问题分开。如果持续返回 SECOC_E_MAC基本可以断定收发两侧某个配置对不上用不着去查总线如果 MAC 通过但窗口频繁失败说明密码学部分是对的问题在 FV 管理和复位时序上。返回值最终映射到 DEM 事件时建议给 MAC 失败和 FV 失败分配不同的事件 ID否则日志里两种故障混在一起定位成本翻倍。4.4 与 DEM、BSWM 的联动验证失败事件进入 DEM 后去抖策略要按报文的周期来配。10 ms 周期的安全报文如果配成立即上报一次 100 ms 的总线干扰就会产生十几个事件常见的做法是用计数器去抖连续失败达到阈值再置位。BSWM 一般不直接消费 SecOC 的验证结果但如果项目设计了「安全通信失效则降级」的策略就需要在 BSWM 规则里引用 DEM 事件这一层联动要在架构阶段就说清楚事后补会很别扭。5. CP 通信栈集成验证进阶CanTp 分段、SOME/IP 边界与旁路手段SecOC 在不同通信范式下的行为差别很大规范自己也承认协议兼容性受限于 AP 和 CP 之间的通信方式。CP 平台上它可能挂在直接的 CanIf 发送路径上也可能经过 CanTp 分段传输以太网侧走 SOME/IP 时规范明确不支持 Authentic PDU 和 Cryptographic PDU 分开传输也不支持把载荷的一部分当作新鲜度信息。集成阶段把这些边界摸清能省掉大量返工。5.1 分段传输下的 SecOC 位置直接传输和触发传输场景下SecOC 处理的是完整 I-PDU集成相对直接。走 CanTp 传输协议时问题变成「在分段前还是重组后做认证」如果 SecOC 挂在 PduR 之上认证的是重组后的完整 I-PDU实现简单但需要缓存整个报文如果挂在 CanIf 之下就要处理分段边界与 MAC 校验的关系复杂度高但时延低。常见做法是把 SecOC 放在 PduR 与上层之间让 CanTp 先把报文重组完整再做验证代价是接收侧多一份缓冲。5.2 SOME/IP 场景的两个限制规范对 SOME/IP 的两条限制要记住不支持 Authentic PDU 与 Cryptographic PDU 分开传输不支持把载荷的一部分当作新鲜度信息。落到集成上就是不能把 MAC 单独放一个 SOME/IP 服务里发出去也不能在报文里划出一段字段既当业务数据又当 FV。如果项目原本的以太网设计正好是分散式布局需要调整到「认证信息和业务数据同包」的形态。5.3 用旁路脚本快速定位收发不一致联调阶段最快的定位手段不是反复烧写配置而是在 PC 侧抓帧后离线复算 MAC。用 Python 做一遍离线验证能立刻判断是配置问题还是代码问题# 离线复算 SecOC 截断 MAC用于和总线抓包结果比对 from Crypto.Hash import CMAC from Crypto.Cipher import AES DATA_ID 0x0001 KEY bytes.fromhex(000102030405060708090a0b0c0d0e0f) def calc_trunc_mac(payload: bytes, fv_full: bytes) - str: # 输入顺序必须与发送侧代码一致Data ID 业务数据 完整 FV mac_input DATA_ID.to_bytes(2, big) payload fv_full c CMAC.new(KEY, ciphermodAES) c.update(mac_input) # Profile 1/2 取前 3 字节对应 SecOCAuthInfoTruncLength24 return c.hexdigest()[:6] if __name__ __main__: payload bytes.fromhex(1122334455667788) # 抓包得到的业务数据 fv_full (1234).to_bytes(8, big) # 发送侧当次的完整计数器 print(截断 MAC , calc_trunc_mac(payload, fv_full))脚本跑出来的 6 位十六进制就是报文中应该出现的截断 MAC拿它和抓包结果对比差一位都说明配置或输入顺序不一致。最值得怀疑的几处密钥字节序、Data ID 大小端、FV 是否用了完整值、输入拼接顺序。把这四个点在收发两侧对齐大多数持续失配问题会在十几分钟内定位。5.4 一个容易被忽略的验证技巧做压力验证时故意构造一组 FV 超窗口的报文注入总线看接收侧是否按预期丢弃并正确触发重新同步再构造一组历史 FV 的报文确认重放被拦截。这两个用例能覆盖 SecOC 最核心的新鲜度机制比单纯跑长时间通信更能暴露问题。验证通过后把失败计数和恢复次数的日志打开一段时间观察量产前的长稳表现。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →