1、0x27服务(安全访问服务)
0x27服务的目的就是能够允许去访问一些数据或者诊断服务,当然这些都是限制类型的访问,可能是出于保密、排放或者是安全因素。对于一些诊断服务,用于下载/上传例程或者数据到服务端,或者是从服务端读取一些特定内存值,这些情况下安全访问可能是有必要的。当一些不恰当的控制例程或者数据下载到ECU中,可能会损伤电子器件、车辆部件、或者是使得车辆不满足排放、安全、保密等标准。0x27服务采用了种子(Seed)和密钥(Key)的概念。
0x27服务具体的使用案例如下:
—— 客户端向ECU请求种子(Seed);
—— ECU向客户端发送种子(Seed);
—— 客户端向ECU发送密钥(Key)(可以基于随机数等一些方法计算出Key值);
—— ECU对客户端发送的密钥进行比对并应答,如果Key有效,那么ECU将会解锁;
请求种子(‘requestSeed’)子函数的参数值总是为奇数如0x01,0x03,0x05,在同样的安全等级下,发送密钥的子函数参数值则应该等于(‘requestSeed’)子函数的参数值加1,如27 01对应27 02;
在任何情况下,只有一种安全等级被激活。例如,如果与0x03(‘requestSeed’)子函数有关的安全等级处于活跃状态,并且客户端成功解锁了与0x01有关的安全等级,那么只有与0x01有关的安全功能才会被解锁使用。之前与0x03有关的其它安全功能,则当前不可使用。安全等级的编号是任意的,并不意味着安全等级之前有任何的关系。
客户端应该通过发送请求种子(‘requestSeed’)去请求ECU解锁(“unlock”),ECU应该在肯定应答消息中发送一个种子(Seed)。接下来,客户端拿到ECU给的种子值,通过随机数等方法计算得到密钥(Key)值,在‘sendKey’请求消息中反馈给ECU。ECU应该将客户端请求的密钥值与自身存储或者计算出的密钥值进行比对,如果二者匹配,ECU将会允许客户端去访问一些特定的服务/数据,并且对‘sendKey’请求指令做出肯定应答。如果二者不匹配,这就意味着客户端做了一次错误尝试,需要客户端从请求种子(‘requestSeed’)从头开始。
如果客户端支持安全访问,但是当前的安全等级已经被解锁,并且0x27服务的请求种子(‘requestSeed’)消息也已经得到了肯定应答,那么服务端就会发送值全部为0的种子值。在当前安全等级被锁住的情况下,客户端应该永不不会发送值全为0的种子值,客户端可以根据这个规则检查种子的应答值,来判定ECU是否被锁在某种特定的安全等级下。
当ECU上电/重启之后,客户端安全访问错误的尝试了一些次数后,汽车制造厂商要求在此种情况下应该延时一段时间才能使用安全访问的服务。当安全访问错误尝试的次数达到了汽车厂商规定的次数,或者是ECU上电/重启之后并且安全访问失败了,则对延时使用安全访问服务应该被支持。如果ECU支持延时的计时器,安全访问服务发送密钥被成功执行之后,用于显示ECU上电/重启后显示延时计时器的消息应该被清除。如果ECU支持延时计时器,并且不能判处出在ECU上电/重启前安全访问服务是否失败了,那么延时计时器应该总是处于激活状态。这种延时只有在ECU上电/重启时被锁住的情况,汽车制造厂商可以自主选择是否支持这种延时。
安全访问的尝试不应该影响到正常车辆通讯或者是其它诊断服务通讯。支持安全性的ECU应该在被锁住的时候,对安全访问服务发送拒绝类的消息。
在特定诊断会话下,成功地请求的某些诊断功能/服务,需要执行特定的安全访问序列。在这种情况下,则要求如下的安全访问序列:
——诊断会话控制服务(0x10服务)
——安全访问服务(0x27服务)
——保密的诊断服务
在ECU中不同的会话模式下,有不同的访问模式。
2、请求消息格式
请求消息的格式定义:
请求种子(‘requestSeed’),子函数的参数定义详见下表:
字节序号 | 参数值 | 约定 | 字节值 |
---|---|---|---|
#1 | SecurityAcces Request SID | M | 0x27 |
#2 | sub-function = [ securityAccessType = requestSeed ] | M | 0x01; 0x03; 0x05; 0x07-0x7D; |
#3 . . #n | securityAccessDataRecord[] = [ parameter#1 . . parameter#m | U . . U | 0x00-0xFF . . 0x00-0xFF |
发送密钥(‘SendKey’),子函数的参数定义详见下表:
字节序号 | 参数值 | 约定 | 字节值 |
---|---|---|---|
#1 | SecurityAcces Request SID | M | 0x27 |
#2 | sub-function = [securityAccessType = sendKey ] | M | 0x02; 0x04; 0x06; 0x08-0x7E; |
#3 . . #n | securityKey[] = [ parameter#1 . . parameter#m | M . . U | 0x00-0xFF . . 0x00-0xFF |
请求消息中子函数参数定义说明:
子函数参数——安全访问类型(securityAccessType)向ECU表明正在执行的动作,客户端想要访问的安全等级,种子和密钥的格式。如果ECU支持不同的安全等级,那么每种安全等级应该被请求种子(requestSeed)值定义,其与密钥发送(sendKey)值之间有固定的关系:
——“requestSeed = 0x01”就定义了“requestSeed = 0x01”和“sendKey = 0x02”之间的固定关系;
——“requestSeed = 0x03”就定义了“requestSeed = 0x03”和“sendKey = 0x04”之间的固定关系;
下表定义了请求种子(requestSeed)和密钥发送(sendKey)值(suppressPosRspMsgIndicationBit (bit 7)不显示):
Bit 6 - 0 | 描述 | 约定 |
---|---|---|
0x00 | ISOSAEReserved ISO保留 | M |
0x01 | requestSeed 汽车制造厂商定义了0x01——请求种子(requestSeed)的安全等级 | U |
0x02 | sendKey 汽车制造厂商定义了0x02——密钥发送(requestSeed)的安全等级 | U |
0x03,0x05, 0x07 - 0x41 | requestSeed 汽车制造厂商定义了请求种子(requestSeed)的不同安全等级 | U |
0x04,0x06, 0x08 - 0x42 | sendKey 汽车制造厂商定义了密钥发送(requestSeed)的安全等级 | U |
0x43 - 0x5E | ISOSAEReserved ISO保留 | U |
0x5F | ISO26021-2 values 汽车制造厂商定义了“车载打火装置报废期的激活”——请求种子(requestSeed)的安全等级 | U |
0x60 | ISO26021-2 sendKey values 汽车制造厂商定义了“车载打火装置报废期的激活”——密钥发送(requestSeed)的安全等级 | U |
0x61 - 0x7E | systemSupplierSpecific 系统供应商保留使用 | U |
0x7F | ISOSAEReserved ISO文档后续定义使用 | U |
请求消息中数据参数定义说明:
请求消息中数据参数定义说明详见下表:
定义 |
---|
安全密钥(高和低字节) 在请求消息中的密钥(“Key”)参数是根据种子(“Seed”)值基于安全算法计算得出的 |
安全访问数据记录 此参数用户可选,在请求种子消息时,可向客户端发送一些数据,例如包含客户端的标识符 |
3、肯定应答消息
肯定应答消息格式定义如下:
字节序号 | 参数名称 | 约定 | 字节值 |
---|---|---|---|
#1 | SecurityAccess Response SID | M | 0x67 |
#2 | sub-function = [ securityAccessType ] | M | 0x00 - 0x7F |
#3 . . #n | securitySeed[] = [ seed#1(high byte) . . seed#m(low byte) | C . . C | 0x00-0xFF . . 0x00-0xFF |
肯定应答消息数据参数定义:
Definition |
---|
securityAccessType 请求消息子函数参数中的bit6 - 0 |
securitySeed (high and low bytes) 种子是由ECU发送,客户端在计算密钥时需要使用的一个参数。当请求发送消息中了设置子函数要求服务发送种子时,安全种子(securitySeed)数据的字节值只会在响应消息中出现。 |
4、支持的否定应答码(NRC_)
该服务会支持一些否定应答码,哪些情况会产生哪些否定应答码具体如下表所示。当服务端在错误场景下使用该服务,以下否定应答码应该被使用。
NRC | 描述 |
---|---|
0x12 | sub-functionNotSupported 子函数参数不被支持时,会发送该NRC |
0x13 | incorrectMessageLengthOrInvalidFormat 消息长度不正确或格式无效时,会发送该NRC |
0x22 | conditionsNotCorrect 条件不正确时,会发送该NRC |
0x24 | requestSequenceError 请求序列不正确时,如客户端发送了密钥,却没有先请求种子,则会发送该NRC |
0x31 | requestOutOfRange 如果用户选择的安全访问数据记录(securityAccessDataRecord)中包含了无效数据,会发送该NRC |
0x35 | invalidKey 'sendKey’子函数的密钥值与ECU内部存储或计算得到的密钥值不匹配 |
0x36 | exceededNumberOfAttempts 错误访问尝试次数超出了最大值,延时计时器激活 |
0x37 | requiredTimeDelayNotExpired 在延时计时器激活时,发送了请求 |
5、0x27服务(安全访问服务)案例使用说明
案例的假设条件:
在如下给定的消息流案例中,如下的条件必须被满足,才能成功解锁服务端:
——请求种子的子函数:0x01 (requestSeed)
——发送密钥的子函数:0x02 (sendKey)
——服务端发送的种子(2字节):0x3657
——服务端的密钥(2字节):0xC9A9
案例1:服务端处于锁定状态
Step1:请求种子
Step1,安全访问服务(0x27服务)请求种子(子函数)的请求消息流案例,由客户端发往服务端:
字节顺序 | Description | 字节值 |
---|---|---|
#1 | SecurityAccess Request SID | 0x27 |
#2 | SecurityAccessType = requestSeed, suppressPosRspMsgIndicationBit = FALSE | 0x01 |
Step1,安全访问服务(0x27服务)请求种子(子函数)的应答消息流案例,由服务端发往客户端:
字节顺序 | Description | 字节值 |
---|---|---|
#1 | SecurityAccess Request SID | 0x67 |
#2 | SecurityAccessType = requestSeed | 0x01 |
#3 #4 | securitySeed [ byte#1 ] = seed#1 (high byte) securitySeed [ byte#2 ] = seed#2 (low byte) | 0x36 0x57 |
Step2:发送密钥
Step2,安全访问服务(0x27服务)发送密钥(子函数)的请求消息流案例,由客户端发往服务端:
字节顺序 | Description | 字节值 |
---|---|---|
#1 | SecurityAccess Request SID | 0x27 |
#2 | securityAccessType = sendKey, suppressPosRspMsgIndicationBit = FALSE | 0x02 |
#3 #4 | securityKey [ byte#1 ] = key#1 (high byte) securityKey [ byte#2 ] = key#2 (low byte) | 0xC9 0xA9 |
Step1,安全访问服务(0x27服务)发送密钥(子函数)的应答消息流案例,由服务端发往客户端:
字节顺序 | Description | 字节值 |
---|---|---|
#1 | SecurityAccess Request SID | 0x67 |
#2 | SecurityAccessType = sendKey | 0x02 |
案例2:服务端处于解锁状态
Step1:请求种子
Step1,安全访问服务(0x27服务)请求种子(子函数)的请求消息流案例,由客户端发往服务端:
字节顺序 | Description | 字节值 |
---|---|---|
#1 | SecurityAccess Request SID | 0x27 |
#2 | SecurityAccessType = requestSeed, suppressPosRspMsgIndicationBit = FALSE | 0x01 |
Step1,安全访问服务(0x27服务)请求种子(子函数)的应答消息流案例,由服务端发往客户端:
字节顺序 | Description | 字节值 |
---|---|---|
#1 | SecurityAccess Request SID | 0x67 |
#2 | SecurityAccessType = requestSeed | 0x01 |
#3 #4 | securitySeed [ byte#1 ] = seed#1 (high byte) securitySeed [ byte#2 ] = seed#2 (low byte) | 0x00 0x00 |