1. 引言
在UDS刷写流程中,安全访问(0x27 Service) 是最关键的一道防线。它的作用是防止未经授权的操作------在刷写固件之前,ECU会要求上位机证明自己拥有合法的访问权限。这个验证过程通常基于 种子-密钥(Seed-Key) 机制:
-
上位机请求种子 :发送
27 01请求,ECU返回一个随机数(种子) -
上位机计算密钥:将种子输入到车厂提供的专用DLL中,计算出对应的密钥
-
上位机发送密钥 :发送
27 02+ 密钥,ECU验证通过后开放刷写权限
TOOMOSS_SID27_SecurityAccess.vi 就是负责完成这个完整流程的子VI。它调用通信基座发送请求和接收响应,并通过调用外部安全访问DLL(通常由车厂提供)完成种子到密钥的转换。
2. 子VI功能概述
2.1 设计目标
-
发送
27 09请求种子,接收ECU返回的种子数据 -
调用外部安全访问DLL,将种子转换为密钥
-
发送
27 0A+ 密钥,接收ECU的验证结果 -
返回最终执行状态
2.2 UDS 0x27服务协议说明
请求种子(27 09):
请求:Byte 0: SID = 0x27, Byte 1: subFunction = 0x9
响应(肯定):Byte 0: SID = 0x67, Byte 1: subFunction = 0x09, Byte 2~N: 种子数据
发送密钥(27 0A):
请求:Byte 0: SID = 0x27, Byte 1: subFunction = 0x0A, Byte 2~N: 密钥数据
响应(肯定):Byte 0: SID = 0x67, Byte 1: subFunction = 0x0A
否定响应(两种请求共用):
Byte 0: SID = 0x7F, Byte 1: 0x27, Byte 2: NRC
2.3 输入参数
| 控件 | 类型 | 说明 |
|---|---|---|
| 设备句柄 | U32 | 由TOOMOSS_OpenDev(CAN).vi返回的设备句柄 |
| 通道号 | 枚举(CAN1/CAN2) | 选择使用CAN1还是CAN2通道 |
| 物理地址 | U32 | 请求报文ID(发送给ECU的CAN ID) |
| 响应地址 | U32 | 期望的响应报文ID(ECU回复的CAN ID) |
| 安全访问DLL库路径 | 字符串 | 车厂提供的安全访问DLL的完整路径 |
2.4 输出参数
| 控件 | 类型 | 说明 |
|---|---|---|
| 响应数据 | U8数组 | 完整的安全访问响应数据(包含27 02的响应) |
| 返回值 | I32 | 0表示成功,-1表示失败 |
| 错误信息 | 字符串 | 失败时的错误描述 |
3. 前面板设计

4. 程序框图设计
4.1 整体流程
步骤1: 发送27 01请求种子 → 调用TOOMOSS_SendAndWaitResp.vi
↓
判断响应是否成功
↓ 成功
步骤2: 从响应数据中提取种子
↓
步骤3: 调用GenerateKeyExByDLL.vi → 获取密钥
↓
步骤4: 发送27 02 + 密钥 → 调用TOOMOSS_SendAndWaitResp.vi
↓
判断响应 → 返回最终结果
4.2 第一步:请求种子(27 09)
构造请求数据 [0x27, 0x09],调用通信基座发送:
| 通信基座参数 | 值 |
|---|---|
| 设备句柄 | 子VI输入 |
| 通道号 | 子VI输入 |
| 物理地址 | 子VI输入 |
| 响应地址 | 子VI输入 |
| 请求数据 | [0x27, 0x09] |
| 数据长度 | 2 |
| 超时时间 | 500ms |
判断响应:
-
若返回值 ≤ 0 → 请求种子失败,返回 -1
-
若响应首字节 == 0x7F → 收到否定响应,解析NRC,返回 -1
-
若响应首字节 == 0x67 → 肯定响应,进入下一步

4.3 第二步:提取种子数据
从27 09的肯定响应中提取种子:
响应格式 :[0x67, 0x09, seed0, seed1, seed2, ...]
-
种子起始位置:索引2
-
种子长度:响应长度 - 2(减去SID和子功能)
-
使用
数组子集函数从索引2开始提取

4.4 第三步:调用密钥生成DLL
将上一步提取的种子数据传递给 GenerateKeyExByDLL.vi:
| 输入参数 | 来源 |
|---|---|
安全访问DLL库路径 |
子VI输入 |
种子数据 |
从27 09响应中提取的种子数组 |
种子长度 |
种子数组的实际长度 |
输出:
-
密钥数据(U8数组) -
密钥长度(I32) -
返回值(0表示成功,非0表示失败)
错误处理:
- 若GenerateKeyExByDLL.vi返回非0 → 密钥计算失败,返回-1

4.5 第四步:发送密钥(27 0A)
将SID(0x27)、子功能(0x0A)和密钥数据拼接为完整请求:
请求数据构造:
[0x27, 0x0A] + 密钥数据
使用 创建数组 或 连接数组 函数将这三部分合并。
调用通信基座发送:
| 通信基座参数 | 值 |
|---|---|
| 设备句柄 | 子VI输入 |
| 通道号 | 子VI输入 |
| 物理地址 | 子VI输入 |
| 响应地址 | 子VI输入 |
| 请求数据 | [0x27, 0x0A, 密钥字节...] |
| 数据长度 | 2 + 密钥长度 |
| 超时时间 | 500ms |
判断响应:
-
若返回值 ≤ 0 → 发送密钥失败,返回 -1
-
若响应首字节 == 0x7F → 收到否定响应,解析NRC,返回 -1
-
若响应首字节 == 0x67 → 安全访问成功,返回 0

4.6 常见NRC错误信息映射
| NRC | 含义 | 错误信息 |
|---|---|---|
| 0x12 | 子功能不支持 | "该ECU不支持安全访问服务" |
| 0x22 | 条件不满足 | "当前会话不支持安全访问" |
| 0x33 | 安全访问被拒绝 | "安全访问被拒绝,请检查密钥是否正确" |
| 0x35 | 无效密钥 | "密钥不匹配,请检查密钥生成算法" |
| 0x36 | 超出尝试次数 | "解锁尝试次数已达上限" |
| 0x37 | 时间延迟未到 | "需要等待一段时间后才能再次尝试" |
| 其他 | 未知 | "安全访问失败,NRC=0x%02X" |
5. GenerateKeyExByDLL.vi 接口设计
5.1 子VI功能说明
GenerateKeyExByDLL.vi 是一个封装子VI,它动态调用车厂提供的安全访问DLL,将输入的种子数据转换为密钥数据。该DLL的函数原型通常是:
c
typedef int (*pGenerateKeyEx)(const unsigned char *iSeedArray,
unsigned short iSeedArraySize,
const unsigned int iSecurityLevel,
const char *iVariant,
unsigned char *ioKeyArray,
unsigned int iKeyArraySize,
unsigned int &oSize);
5.2 输入参数
| 控件 | 类型 | 说明 |
|---|---|---|
| DLL库路径 | 字符串 | 安全访问DLL的完整路径 |
| 种子数据 | U8数组 | 从ECU接收的种子 |
| 种子长度 | U16 | 种子数据的字节数 |
| 安全等级 | U32 | 通常为1,表示安全访问Level 1(可扩展) |
| 变体名称 | 字符串 | 空字符串或特定变体标识 |
| 密钥缓冲区大小 | U32 | 密钥数组的最大长度(建议16) |
5.3 输出参数
| 控件 | 类型 | 说明 |
|---|---|---|
| 密钥数据 | U8数组 | 计算出的密钥 |
| 密钥长度 | U32 | 密钥的实际字节数 |
| 返回值 | I32 | 0表示成功,非0表示失败 |


6. 典型调用示例
6.1 成功的安全访问流程
| 步骤 | 方向 | 数据 | 说明 |
|---|---|---|---|
| 1 | Tx | 27 01 |
请求种子 |
| 2 | Rx | 67 01 12 34 56 78 |
返回种子 12 34 56 78 |
| 3 | --- | --- | DLL计算密钥(假设结果为 A1 B2 C3 D4) |
| 4 | Tx | 27 02 A1 B2 C3 D4 |
发送密钥 |
| 5 | Rx | 67 02 |
验证通过,安全访问成功 |
6.2 密钥错误导致失败
| 步骤 | 方向 | 数据 | 说明 |
|---|---|---|---|
| 1 | Tx | 27 01 |
请求种子 |
| 2 | Rx | 67 01 12 34 56 78 |
返回种子 |
| 3 | --- | --- | DLL计算密钥(但算法错误或版本不匹配) |
| 4 | Tx | 27 02 XX YY ZZ WW |
发送错误密钥 |
| 5 | Rx | 7F 27 35 |
NRC=0x35,密钥无效 |
7. 错误处理
| 错误场景 | 返回值 | 错误信息 |
|---|---|---|
| 设备句柄无效 | -1 | "设备句柄无效,请检查设备是否已打开" |
| 请求种子超时 | -1 | "请求种子超时,ECU未响应" |
| 请求种子否定响应 | -1 | 根据NRC返回对应错误信息 |
| GenerateKeyExByDLL返回非0 | -1 | "密钥计算失败,请检查DLL库是否正确" |
| 发送密钥超时 | -1 | "发送密钥超时,ECU未响应" |
| 发送密钥否定响应 | -1 | 根据NRC返回对应错误信息 |
8. 注意事项
| 要点 | 说明 |
|---|---|
| DLL路径 | 安全访问DLL通常由车厂或算法提供商提供,且路径中不应包含中文或特殊字符 |
| 种子长度 | 不同ECU的种子长度不同(常见4字节、6字节或8字节),子VI应自动适应 |
| 密钥长度 | 密钥长度通常与种子长度相同,但也可能不同,需根据实际DLL输出确定 |
| 尝试次数 | 部分ECU限制了安全访问的尝试次数(通常5次),超过后需等待或复位ECU |
| 会话切换 | 安全访问通常需要在扩展会话(0x03)下执行,若收到NRC=0x7E,请先切换会话 |
| 超时时间 | 部分ECU的种子生成和密钥验证需要额外计算时间,建议超时设为1000ms以上 |
| 安全等级 | 本子VI默认使用Level 1(请求种子/发送密钥),部分ECU可能需要Level 2以上的安全访问(如27 05/27 06),可根据需要扩展 |
9. 总结
TOOMOSS_SID27_SecurityAccess.vi 是UDS刷写流程中最复杂的诊断服务之一。它涉及两个步骤的请求-响应交互,并且需要依赖外部安全访问DLL完成种子到密钥的转换。
本子VI的设计将种子请求、密钥计算和密钥发送三个环节串联为完整流程,调用者只需传入设备信息和安全访问DLL路径即可完成安全访问验证,无需关心内部协议细节。
在实际项目中,由于不同ECU的种子长度、密钥长度和安全访问算法各不相同,该子VI应设计为高度可配置的通用模块,以适应不同项目的需求。
下一篇将介绍 TOOMOSS_SID34-36-37_DownloadFlow.vi --- 下载流程,敬请期待。