前言
在没开发过SecOC之前,总听别人说SecOC有什么新鲜度值、MAC,甚至还需要一条叫什么同步报文的东西。
新鲜度值?技术这么枯燥的东西,居然跟食物这么沾边?!
在我们广东,这么新鲜的东西是要被吃掉的...

另外,大家都知道,SecOC关键目的也是报文校验嘛,所以MAC我能理解,就类似于CRC校验的Checksum,无非就是算法复杂一些,算出来的结果占用报文位置多一些。
但是,SecOC的同步报文我就不理解了。
我校验我自己,为啥还会跟你(同步报文)有关系呀?

如果是CRC校验,我只需要知道我自己这条报文的数据和校验算法就可以了呀!
另外,还有密钥(Key),这啥呀这是?
如果接触的多一些,还会了解到,SecOC还跟存储、HSM有关。
HSM?这可是到信息安全领域了呀?
如果是用Autosar配置的话,又涉及各种加密模块:SecOC、Csm、CryIf、Crypto
SecOC整这么复杂的吗?
......
朋友们,别慌,其实SecOC的复杂,主要是它涉及到东西有点多,但真正去实现一遍,会发现它其实就是纸老虎,主打一个什么都蹭一点:
比如HSM:实际上只是调用了HSM的一个计算校验值的接口。
又比如存储,不知道的以为多厉害,要存多少东西呢,其实就存了一个东西:ECU上电次数。
好了朋友们,废话不多说,本篇文章,我们一步步去拆解SecOC的完整功能。
CRC校验
在研究SecOC之前,我们先看看我们熟悉的报文CRC校验(或E2E)。
报文CRC校验很简单,它关键就2个东西:Checksun和Counter
举个栗子:一帧报文8个字节。
Checksum放在Byte0,Counter放在Byte1的低四位。
如下图所示:

①所谓Checksum,就是把Byte1~Byte7的数据用CRC校验算法算出一个结果,然后把这个结果放到Byte0。

②所谓Counter,就是发送方每发送一帧报文,这个报文内的Counter值就+1,加到14或15就重新回到0继续重新累加。(需要注意的是,Counter也会加入到Crc校验中)
实际报文数据举例如下:

校验过程简单举例如下(另外,如E2E_Profile01的校验,在Crc校验之前,还会在校验数据前面加入DataID):

由上可见,报文CRC校验是非常简单的,它东西都是流于报文表面的,只要知道了CRC校验算法就行了。
关于报文CRC,我们稍微总结一下:
1 、CRC校验的关键点:Checksum 和Counter
2 、从校验层面来看,CRC校验报文的结构就两部分:待校验数据+校验结果
从CRC报文角度理解SecOC报文
好了,了解了CRC校验,我们接下来用CRC报文跟SecOC报文做对比,进而理解SecOC报文。
我们先贴一张SecOC的报文图留个印象。
如下图所示,这是一帧16Byte的SecOC报文。

我们从下面两个点入手,让SecOC报文跟CRC报文做对比。
1、首先,SecOC报文中关键的东西也是只有2个:FreshValue、MAC

①SecOC的MAC,Crc的Checksum:你可以理解成同一个东西,都是通过校验算法后,得出来的结果 而已。只不过SecOC用的算法高级一点,算出的结果要叫做MAC(Message Authentication Code)。
②SecOC的FreshValue,Crc的Counter:你也可以理解成同一个东西,只不过,Crc的Counter简单一点,只有报文计数功能 :从0-14(或15)计数。而FreshValue的功能则多一些,不仅仅只有报文计数功能(至于其它功能,我们先不管)。
2、其次,SecOC报文跟CRC报文结构实际上是一样的,都是:待校验数据+校验结果。

它们的区别在于:
CRC校验报文,它不跟你表面一套背地一套,它表面是什么,那么需要校验的东西就是什么。

而SecOC就有点恶心人了,SecOC报文的"待校验数据"中新鲜度值(FreshValue)是不完整的、"校验结果"也不是完整的,如下图所示:

图中的Secured I-PDU是指总线中的一条报文数据。
可见,报文里面放的中新鲜度值(FreshValue)是截取完整中的一部分,"校验结果"(MAC)也是截取的也是完整的一部分。
所以,概括来说,SecOC就是CRC的加强升级版本罢了。
我们要实现CRC报文时,就2个步骤:
第一步:实现Counter功能(每发一帧Counter+1,达到最大值后重置为0)
第二步:使用CRC算法,校验待校验数据,算出Checksum。
实际上,我们要实现一帧SecOC报文,也是2个步骤:
第一步:获取完整的FreshValue
第二步:使用算法,校验完整的待校验数据,算出MAC。
所以,我们只要把FreshValue和Mac搞明白了,SecOC功能就清楚了。
报文重放攻击
SecOC的Freshness Value即新鲜度值。
朋友们,为啥它不叫别的名字,非要叫新鲜度值呢?
其实,就如它的字面意思一样理解:ECU发出的每条SecOC报文要一直保持新鲜,如不新鲜的话,接收方就不收了。
在了解新鲜度值的作用之前,我们又需要掏出CRC报文来说一说了。
对于CRC报文,我们前面说过,CRC报文所有的关键信息都是流于报文表面的。
如下图所示,CRC报文的接收方一直只做了一件固定的事情:

即:把待校验数据经过一下CRC算法计算,再把算出来的校验结果与接收的校验结果做对比,如果对比通过,则认为这条报文是正确的。
朋友们,现假设我们用CAN盒子采集ECU-A发出来的CRC报文。
然后在车上把这个ECU-A去掉,再把我们之前录下来的ECU-A的CRC报文发到车上去。
那么,别的ECU会不会收我们CAN盒子发的这些CAN数据呢?
答案必然是必然会收的。
因为我们录下来CRC报文,Counter是连续且正常累加的,Checksum的值也是对的。
朋友们,这就是所谓的报文重放攻击。

现在我们假设,我们ECU实现了一种升级版的CRC报文:Counter计数没有最大值,每发出一条报文,Counter可以一直累加,永远不会重置回到0。
并且,接收方收到一条报文后,会先判断这条CRC报文的Counter值是否比前面接收的那条大1,如果不是,就不接收这条报文。

这种情况下,如果你再用CAN盒子录下ECU这种升级版的CRC报文,然后进行重放攻击。
结果如何呢?
虽然说,你录制的报文的Checksum肯定是对的,但你录制的这种升级版的CRC报文,它的Counter永远是旧的、永远"不新鲜"。
因此,重放的每一条报文接收方都不会接收。
所以,接收方能防御你的重放攻击。
而SecOC报文的新鲜度值(FreshValue),就是起了这种升级版Counter的一个作用,只不过,新鲜度值并不是简单的报文次数累加。

那么,新鲜度值如果不是简单的报文发送次数累加,它是如何做到每帧发出来的都如此"新鲜"呢?
这个问题,我们接下来讲解新鲜度值的时候,跟大家一起详细探讨。
结语
好了,对于SecOC报文的基本实现和功能作用,我们现在有了基础的理解了。
下篇文章,我们深入研究新鲜度值的实现。
返回目录: