CAN总线报文数据一致性校验

admin 2024年1月23日21:03:46评论12 views字数 2431阅读8分6秒阅读模式

点击上方蓝字谈思实验室

获取更多汽车网络安全资讯

CAN总线报文数据一致性校验

01

不安全的CAN总线

1、如何保证ECU接收到的数据是合法的?

比如ECU1接收ECU2发出的一帧0x100报文,协议层是不会区分是ECU1发的,还是非法接入OBD的CAN盒发的?如果ECU1接收到非ECU2发出的0x100报文岂不是很危险?

2、ECU如何知道另一个节点挂死

比如ECU1还是接收ECU2发出的一帧0x100报文,但是由于某些神秘原因(程序跑飞了)导致ECU2挂死或者掉线,那ECU1如何知道此时的接收到0x100无效?

CAN通讯是一种广播形式的通讯方式,自然协议层是无法做到数据合法性的校验,这部分工作需要应用层来完成。由此就出现了RollingCounter与Checksum。这两个东西好像也是功能安全的一部分,本期只是介绍这两个东西的原理,不对功能安全做过多讨论。

CAN总线报文数据一致性校验

一个规范的CAN矩阵协议,每一帧报文都会要求有这个两个信号。如上图,从bit52到bit55是RollingCounter,取值范围0~15,ECU没发一次自动累加,满15就归零。从bit56到bit63(byte8)都是Checksum,取值范围0x00~0xFF,用来表示该条报文的校验值。

对于判断发送报文ECU有没有挂死很简单,只要在接收端对RollingCounter进行判断,几个周期内协议栈上的buff没有得到更新则就能判断为节点异常。

对于报文合法性的判断则就要负责得多,且会有各种花样

CAN总线报文数据一致性校验

车企制定的通讯协议时,除了制定矩阵信号外,会规定Checksum的计算方法,比如这个是采用多项式的CRC校验算法。

CAN总线报文数据一致性校验

并且规定出需要校验的数据,有的是对矩阵的前7个byte进行校验,有的则要增加报文ID作为校验计算的输入,各种花样都有。

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ** * CRC8校验子程序0x1D(x8+x4+x3+x2+1)  * * * * * * * * * * * ** * 参数1,uint8_t *data:需要计算的数据  * * * * * * * * * * ** * 参数1,uint16_t len:需要计算的数据字节长度 * * * * * * * ** * 返回值,uint8_t crc8:计算出的CRC值 * * * * * * * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */uint8_t crc_8find(uint8_t *data, uint16_t len){    uint8_t crc8 = 0x00;    while( len-- )     {        crc8 = crc_table[crc8 ^ *data];        data++;    }    return crc8;}

甚至贴心的给出校验计算的伪代码,这函数写法C、C++应该都可以直接运行的。理解下上面的代码!

当ECU2发出0x100之前,会对RollingCounter累加,并且通过计算包含RollingCounter的前七个字节的CRC值,填充到数据域的第8个字节;

ECU1接收到0x100的时候使用同样的校验算法,计算数据域的前7个字节,并且与第8个字节发送源计算的CRC值进行比较。如果两者相同,则数据合法。

02

CANOE仿真

接下来在CANOE的CAPL进行RollingCounter与Checksum的模拟

CAN总线报文数据一致性校验

创建两个ECU节点,ECU1为发送节点,ECU2为接收节点。ECU2会对ECU1的节点做Checksum,如果非法数据会在log窗口中打印出来。ECU1会而这个IG是用来模拟非法的数据发送。

int GetCrcChecksum (int crc_position ,message *data){  byte checksum;  byte bitIndex;  byte byteIndex;  byte tdata;  checksum = 0x00;  for (byteIndex = DBLookup(data).dlc; byteIndex >= 1; byteIndex--)  {    if(byteIndex-1 != crc_position)    {      tdata = data.byte(byteIndex-1);    }    else    {      tdata = 0;    }    checksum ^= tdata;    for (bitIndex = 0; bitIndex < 8; bitIndex++)    {      if ((checksum & 0x80) != 0)      {            checksum = (checksum << 1) ^ 0x1D; // cb_CRC_POLY: 0x1D      }      else      {            checksum = (checksum << 1);      }    }  }  checksum &= 0xFF;  return (checksum);}

CAPL计算Checksum的函数,在ECU1与ECU2里都存在

on timer Timer1{   Req.rollingCounter_0x100=LiveCount;   Req.checksum_0x100=GetCrcChecksum(7,Req);   output(Req);   setTimer(Timer1,20);     LiveCount=LiveCount+1;     if(LiveCount==16)   {    LiveCount=0;   }

ECU1的定时器函数,发送前调用GetCrcChecksum函数生成Checksum

on message RCTest1{  if(this.checksum_0x100==GetCrcChecksum(7,this))  {      Rep=this;  }else  {    write("Invaild Message");  }}

ECU2接收事件中重新计算Checksum跟发送报文里的Checksum进行比较,不同则抛出错误

CAN总线报文数据一致性校验

按F2,开始仿真,可以监控到ECU1发送出来的rollingCounter与Checksum

CAN总线报文数据一致性校验

在Write窗口中打印ECU2接收到的数据

CAN总线报文数据一致性校验

在IG节点设置一个非法的报文,rollingcounter与Checksum都设置0

CAN总线报文数据一致性校验

对非法数据进行抛出。

来源:古德曼汽车工业

 精品活动推荐 

CAN总线报文数据一致性校验
CAN总线报文数据一致性校验

原文始发于微信公众号(谈思实验室):CAN总线报文数据一致性校验

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月23日21:03:46
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CAN总线报文数据一致性校验https://cn-sec.com/archives/2423563.html

发表评论

匿名网友 填写信息