本篇文章主要介绍在ISO 14229-1标准中定义的UDS服务——$27 SecurityAccess,其为Tester提供了一种安全访问ECU的方法。
1 服务介绍
在通常情况下,车企出于安全考虑,会对一些涉及安全风险或保密数据的诊断服务加以限制,例如向ECU下载数据、从ECU上传数据、读取特定隐私数据等。若这些涉及安全因素的诊断服务被非法Tester直接在ECU中执行,则可能会损坏ECU和车辆,危害车辆安全或排放标准。
为了应对上述情况,$27 SecurityAccess服务为ECU提供了一种基于“种子——密钥”的安全访问机制,用于验证Tester的合法性。该安全访问机制的典型诊断流程如下所示:
- Tester向ECU请求seed
- ECU响应seed
- Tester向ECU发送key(基于收到的seed和特定的安全算法得出)
- ECU响应key有效/无效
只有ECU响应key有效(解锁自身),Tester才能正常使用那些因安全原因而受到限制的诊断服务。
关键点:
- 子功能参数requestSeed值应始终为奇数,且同一安全级别的相应的子功能参数sendKey值应等于requestSeed+1
- 在任何时刻,ECU中应只有一个安全级别处于活动状态。例如,当requestSeed = 0x03相关联的安全级别处于活动状态时,Tester又成功解锁了requestSeed = 0x01相关联的安全级别,则此时只有0x01安全级别支持的安全诊断服务功能才会解锁,先前与0x03安全级别有关的所有安全诊断服务功能将不在处于活动状态。(安全级别与受限制的诊断服务关系由主机厂定义)
- Tester首先通过$27服务的requestSeed参数请求ECU解锁,ECU通过requestSeed的肯定响应消息回复seed给Tester,然后Tester利用收到的seed和特定的安全访问算法计算key,并利用$27服务的sendKey参数发送key给ECU。ECU会将收到的key和内部存储或计算的key进行比较,若两个key匹配,则ECU对该安全级别下的安全诊断服务功能或安全数据访问解锁,并通过sendKey的肯定响应消息表明;若两个key不匹配,则将被视为错误的安全访问尝试,再一次进行安全访问尝试需要重新请求seed。
- 当ECU收到带requestSeed参数的请求消息时,若其对应的安全级别已经解锁,则ECU应通过requestSeed的肯定响应消息发送全0的seed给Tester,而对于处于锁定状态的安全级别,ECU绝不应该发送全零的种子。Tester可以通过此方法来检查ECU特定的安全级别是否被锁定。
- 当ECU上电后,或安全访问失败次数超过上限后,应激活主机厂规定的安全访问重试延时计时器。当ECU安全访问通过后,应关闭此安全访问重试延时计时器。
- 安全访问解锁不应妨碍正常的车辆通信或其他诊断通信。
- ECU在收到受限制的安全诊断服务请求而对应的安全级别未解锁时,应该发送否定响应。
- 某些诊断服务可能要求在一个特定的诊断会话进行安全访问解锁,这种情况下,应执行以下的诊断服务序列:
- 执行$10 DiagnosticSessionControl服务
- 执行$27 SecurityAccess服务
- 执行解锁的安全级别对应的诊断服务
2 服务数据格式
2.1 请求数据格式
以下是$27服务的请求数据格式:
字节序 | 参数 | 字节值 | 说明 |
---|---|---|---|
#Byte1 | SecurityAccess SID | 0x27 | 必选 |
#Byte2 | sub-function = [securityAccessType = requestSeed] | 0x01 0x03 0x05 – 0x7D | 必选 |
#Byte3 – #ByteN | securityAccessDataRecord[] = [parameter#1 : parameter#n] | 0x00 – 0xFF | 可选 |
字节序 | 参数 | 字节值 | 说明 |
---|---|---|---|
#Byte1 | SecurityAccess SID | 0x27 | 必选 |
#Byte2 | sub-function = [securityAccessType = sendKey] | 0x02 0x04 0x06 – 0x7E | 必选 |
#Byte3 – #ByteN | securityKey[] = [key#1(high byte) : key#n(low byte)] | 0x00 – 0xFF | 必选 |
2.1.1 securityAccessType
securityAccessType是$27服务的sub-function参数,用于指示ECU当前正在进行安全访问的步骤和安全级别。不同的安全级别由requestSeed值标识,该值和sendKey值具有固定关系。例如:
- requestSeed=0x03标识requestSeed=0x03和sendKey=0x04之间的固定关系
- requestSeed=0x01标识requestSeed=0x01和sendKey=0x02之间的固定关系
其具体定义如下表所示:
securityAccessType | Description |
---|---|
0x00 | ISOSAEReserved |
0x01 | requestSeed 指示车辆制造商定义的不同安全级别 |
0x02 | sendKey 指示车辆制造商定义的不同安全级别 |
0x03 0x05 0x07 – 0x41 | requestSeed 指示车辆制造商定义的不同安全级别 |
0x04 0x06 0x08 – 0x42 | sendKey 指示车辆制造商定义的不同安全级别 |
0x43 – 0x5E | ISOSAEReserved |
0x5F | ISO26021-2 values 指示ISO 26021-2中定义的不同安全级别,用于车载烟火装置的寿命终止激活 |
0x60 | ISO26021-2 sendKey values 指示ISO 26021-2中定义的不同安全级别,用于车载烟火装置的寿命终止激活 |
0x61 – 0x7E | 系统供应商规定 |
0x7F | ISOSAEReserved |
2.1.2 securityAccessDataRecord
可选参数,用于在请求种子信息时向ECU
发送数据,一般情况下不会使用。
2.1.3 securityKey
sendKey请求消息中的securityKey参数值是由ECU响应的securitySeed与特定的安全访问算法计算生成。
2.2 肯定响应数据格式
以下是$27服务的肯定响应数据格式:
字节序 | 参数 | 字节值 | 说明 |
---|---|---|---|
#Byte1 | SecurityAccess SID + 0x40 | 0x67 | 必选 |
#Byte2 | sub-function = [securityAccessType] | 0x00 – 0x7F | 必选 |
#Byte3 – #ByteN | securitySeed = [seed#1(high byte) : seed#n(low byte)] | 0x00 – 0xFF | 可选a |
- a:该参数只有当securityAccessType = requestSeed时,才会出现在ECU的响应消息中
2.2.1 securityAccessType
securityAccessType是对应$27服务请求报文中的securityAccessType参数回显。
2.2.2 securitySeed
securitySeed参数是ECU响应的种子数据值,用于Tester计算安全访问所需的密钥key。
2.3 否定响应数据格式
以下是$27服务的否定响应数据格式:
字节序 | 参数 | 字节值 | 说明 |
---|---|---|---|
#Byte1 | Negative Response SID | 0x7F | 必选 |
#Byte2 | SecurityAccess SID | 0x27 | 必选 |
#Byte3 | NRC | supportedNRC | 必选 |
supportedNRC的可选值如下表所示:
supportedNRC | NRC define | 描述 |
---|---|---|
0x12 | sub-functionNotSupported | ECU不支持该诊断请求服务的子功能 |
0x13 | incorrectMessageLengthOrInvalidFormat | 诊断请求指令的长度或格式不对 |
0x22 | conditionsNotCorrect | 执行诊断的条件不满足 |
0x24 | requestSequenceError | 诊断请求的发送顺序不正确 |
0x31 | requestOutOfRange | 诊断请求参数超出范围或DID/RID不支持 |
0x35 | invalidKey | 钥匙不匹配 |
0x36 | exceedNumberOfAttempts | 尝试解锁次数达上限 |
0x37 | requiredTimeDelayNotExpired | 请求解锁的重试延时未到 |
3 服务通信示例
3.1 安全访问ECU
本例展示了当ECU处于锁定状态时,Tester通过$27服务安全访问ECU的流程,其中,存在以下条件:
- sub-function bit7: SPR = 0
- sub-function requestSeed = 0x01
- sub-function sendKey= 0x02
- securitySeed = 0x3657
- securityKey = 0xC9A9
3.1.1 请求报文(requestSeed)
字节序 | 参数 | 字节值 |
---|---|---|
#Byte1 | SecurityAccess SID | 0x27 |
#Byte2 | sub-function = [securityAccessType = requestSeed] | 0x01 |
3.1.2 肯定响应报文(requestSeed)
字节序 | 参数 | 字节值 |
---|---|---|
#Byte1 | SecurityAccess SID + 0x40 | 0x67 |
#Byte2 | sub-function = [securityAccessType = requestSeed] | 0x01 |
#Byte3 | securitySeed = seed#1(high byte) | 0x36 |
#Byte4 | securitySeed = seed#2(low byte) | 0x57 |
3.1.3 请求报文(sendKey)
字节序 | 参数 | 字节值 |
---|---|---|
#Byte1 | SecurityAccess SID | 0x27 |
#Byte2 | sub-function = [securityAccessType = sendKey] | 0x02 |
#Byte3 | securityKey = key#1(high byte) | 0xC9 |
#Byte4 | securityKey = key#2(low byte) | 0xA9 |
3.1.4 肯定响应报文(sendKey)
字节序 | 参数 | 字节值 |
---|---|---|
#Byte1 | SecurityAccess SID + 0x40 | 0x67 |
#Byte2 | sub-function = [securityAccessType = sendKey] | 0x02 |
3.2 确认ECU安全访问状态
本例展示了当ECU处于解锁状态时,Tester通过$27服务确认ECU已处于安全访问状态的流程,其中,存在以下条件:
- sub-function bit7: SPR = 0
- sub-function requestSeed = 0x01
3.2.1 请求报文(requestSeed)
字节序 | 参数 | 字节值 |
---|---|---|
#Byte1 | SecurityAccess SID | 0x27 |
#Byte2 | sub-function = [securityAccessType = requestSeed] | 0x01 |
3.2.2 肯定响应报文(requestSeed)
字节序 | 参数 | 字节值 |
---|---|---|
#Byte1 | SecurityAccess SID + 0x40 | 0x67 |
#Byte2 | sub-function = [securityAccessType = requestSeed] | 0x01 |
#Byte3 | securitySeed = seed#1(high byte) | 0x00 |
#Byte4 | securitySeed = seed#2(low byte) | 0x00 |