安全访问服务,主要功能是为了通过诊断安全地访问服务端,也就是ECU,而设置的一层保护机制。
一、安全访问机制
1.安全访问定义
什么是安全地访问?就是通过一个验证机制来确认发送请求的一方是不是官方认可的设备,也就是验证设备是否可信,验证通过之后才可以继续请求服务端的数据。
有哪些是需要安全访问通过之后才可以进行响应的呢?主要分为三类,第一类是操控类的服务,例如输入输出控制、例程控制服务等,第二类是写入类,例如通过DID写入数据,软件更新等,第三类不多见,有些比较重要的数据读取,有时候也需要先通过安全访问的验证。
安全访问主要使用种子和密钥来进行安全验证,验证过程中,通过计算相同种子得到的密钥,ECU对比设备发送过来的密钥和自己的密钥,来确定设备是否可信。
这里的算法就是主机厂定义好的,只有主机厂授权的设备制造商和ECU制造商知道,所以如果双方使用相同的算法,那么相同种子计算出来的密钥必然是相同的,也就验证了设备出自被授权的制造商之手。
这就跟间谍对暗号一样,事先约定好,上句是“天王盖地虎”,下句是“宝塔镇河妖”,那么交换秘密的时候,有人先说上句,对面对上来下句,身份确认完毕。
2.安全访问流程
具体的安全访问流程如下图所示:
①客户端首先发送请求种子的诊断请求
②服务端收到请求后,计算一个随机种子通过诊断响应发送给客户端
③客户端收到种子后,使用定义好的算法计算出密钥,然后通过诊断请求发送给服务端
④服务端收到密钥后,与自己计算的密钥作对比,如果一致,验证通过,如果不一致,验证失败
验证失败需要响应哪些NRC,可参照标准的附录I,里面有详细的状态切换图和响应规则。
需要注意的是请求种子和发送密钥两步操作是通过子功能来区分的,请求种子的子功能是奇数,发送密钥的子功能是偶数,且是请求种子的子功能加1。由此,子功能被分成了一对对的组,每一组是一个安全等级,不同的安全等级可以用来验证不同的设备,或者执行不同安全等级要求的操作,数字大小并不代表其等级的高低。
同一时刻最多只能有一个安全等级是解锁的状态,因此从一个安全等级接收到另外一个等级的请求并且解锁成功后,之前的安全等级将被重新锁定,而由于切换安全等级致使先前解锁的状态被锁定后,其依赖于被锁定的等级的服务和功能也一并被关闭。
如果被请求的安全等级当前是已经解锁的状态,那么在响应种子时,在放种子的位置都放上0,表示已经解锁了,你不要再请求了。并且实际上种子应该是一个随机数,一般全0和全F都不允许作为普通种子放到响应里,全0刚才说了,有特殊含义,全F有可能是寄存器的初始值,这样就无法分辨程序是否有错误了。
安全访问为了增加破解难度,一般会设置错误尝试次数和延时机制。当错误尝试超过次数的限值时,就会开启延时,延时时间内,不允许进行安全访问,也就是说请求种子会一直给否定响应。这个延时时间也可以在ECU复位或者启动的时候开启,或者更复杂一些,设置错误计数器在非易失寄存器里,上电或者复位之后要检查这个计数器,如果超过限值就开启延时。通常延时过了之后只允许再进行一次尝试,也就是计数器只减1,只有在安全访问通过之后才清零。
二、应用数据格式
1.请求报文
前面提到流程里有两对儿请求和响应,所以安全访问的请求报文有两个格式,分别是请求种子和发送密钥,两个格式很相似。
首先来看请求种子,第一个字节是服务ID0x27,第二个字节是子功能,注意这里只有1,3,5等奇数。后面的securityAccessDataRecord是可选的数据,标准里给的示例是用来标识客户端的ID,目前暂未遇到过使用该数据的,这个可以先不用管。
发送密钥的请求前两个字节分别是服务ID0x27和子功能,这里的子功能就是2,4,6等偶数值啦。因为是发送密钥的请求所以子功能后面是需要带密钥的,密钥长度由主机厂在开发需求的时候进行定义,但至少有一个字节,不然也说不过去。
2.响应报文
响应格式就更简单啦,包含响应的ID0x67(0x27+0x40),以及被请求的子功能。后面的种子是收到请求种子的时候要在响应里给出具体的种子,而如果收到的请求是发送密钥,则不需要后面的种子字节了。
三、数据示例
安全访问服务虽然流程稍微有些复杂,但实际格式并不复杂,所以我就不去标准里截图贴在这里了,简单贴一个实际数据的流程图来给大家说一下数据流是怎么样的。
上图的示例中,子功能是0x01和0x02这一对,种子是0x0102,密钥是0x0304,数据格式就不解释啦。
安全访问服务的否定响应有些复杂,里面会涉及不同的规则,后面再单独开一篇来说明如何阅读附录I。
附录I来啦,欢迎大家阅读和讨论~
https://blog.csdn.net/kalake/article/details/130633691