TIMAC 学习笔记(三)

本文主要内容参考 《Security on TI IEEE 802.15.4 Compliant RF Devices》、《Design Note DN108》、《IEEE 802.15.4协议规范》来考察MAC层的安全机制。

1. MAC层安全机制

先简要介绍一下MAC层的帧格式,下图为通用MAC帧类型。

其中的,Frame Control域结构如下:

Frame Type表示帧类型,MAC层共有四种类型的帧,信标帧、数据帧、命令帧和确认帧。

Security Enable是MAC层的安全保护使能帧,当它设置为1时,Auxiliary Security Header就必须要存在。此域的包含一些同安全传输相关的设置,例如安全级别、密钥来源等,安全帧域长度随着不同的安全级别设置而取不同的数值。以下是安全域的组成。

当开启安全后,Security control位不能为0,用来表示安全级别,Security control字节中的[BIT1,BIT0]表示Security level,[BIT3,BIT2]表示key identifier mode.Key identifier仅仅的那个key identifier mode 大于0时才会被包含在传输帧中。详情如下图。

Frame counter用来确保每个帧的唯一性。

在IEEE 802.15.4-2006规范中,ENC-MIC用在MAC命令帧传输上,ENC用到MAC数据帧上,MIC用在信标帧上。

2. AES加密模式

AES是一种加密方法,结合不同的密钥,能够一次对指定长度的数据进行加密。当待加密的数据有很多时,就会有不同的策略来使用AES来加密。常用的有ECB、CTR、CBC-MAC、CCM几种模式。

2.1 ECB模式

 ECB模式就是最基本的使用密钥,一次对16个字节的明文进行加密。这种加密模式的缺点就是,同样的明文输入会产生同样的密文输出,这使得它很容易在数据中识别出来。为了改进这种缺陷,人们提出了ECB-CBC模式。

2.2 ECB-CBC模式

 这种模式,在ECB的基础上,后一个待加密明文在进入加密之前,与前一个加密密文输出进行异或,然后进行加密阶段。这样,每段密文输出独立于所有明文块,那么第一个明文块怎么保证它的独立性呢?人们引入了一个IV,在第一个明文块加密前,先与此IV进行异或处理,然后进行后续的链式加密处理。IV向量需要在收发双方之间保持同步。

2.3 CFB模式

优点:

1.隐藏了明文模式;

2.分组密码转化为流模式;

3.可以及时加密传送小于分组的数据;

缺点:

1.不利于并行计算;

2.误差传送:一个明文单元损坏影响多个单元;

3.唯一的IV;

2.3 OFB模式

优点:

1.隐藏了明文模式;

2.分组密码转化为流模式;

3.可以及时加密传送小于分组的数据;

缺点:

1.不利于并行计算;

2.对明文的主动攻击是可能的;

3.误差传送:一个明文单元损坏影响多个单元;

以上部分内容转载自:

   happyhippy作者:Silent Void
     出处:http://happyhippy.cnblogs.com/
     转载须保留此声明,并注明在文章起始位置给出原文链接。

2.3 CTR模式

 CTR模式只是仅仅用来加密的模式,为了确保唯一性,对于每个帧,需要有一个随机数nonce。这个随机数被收发双方用一个已知的Key来加密,用加密后的密文与带加密的明文异或。CTR模式每次只对16个字节块加密,如果最后一个字节块不足16个字节,则补0填充。

2.4 CBC-MAC模式

CBC-MAC仅仅用来做完整性验证。这种模式不包含加密帧,仅仅用于认证。被认证的数据划分为以16个字节为单位的块,不足的补0.这种操作模式产生的结果为16字节的数据,只取前M个字节(M=4,8,16),具体取决于软件设置多少位的认证字节数。

2.5 CCM模式

 CCM模式是CTR模式和CBC-MAC的混合体,既有加密功能、又有验证功能。它会先在帧上添加认证帧,然后对进行CTR模式的加密。这里有IV向量,详细组成如下:

Sequence counter计算一个帧中16个字节块数。Flags标志域由如下组成:

Reserved保留位,设置为0.Adata用于指示传输帧中是否有认证数据.M是认证域的长度,具体编码为(认证字节长度-2)/2,有效值范围在[4-16]之间。

3. 抓包分析

基于TIMAC的安全数据发送分析

Level = 5 ,说明是加密加上MIC32,即4个字节的验证码,Key_id_mode等于1,Key_index等于3.

4. AES加密相关

  CC2530片上含有硬件AES加密引擎,内部可以通过字节传输或者DMA传输,它能够直接支持ECB、CTR、CBC-MAC这几种模式,不能直接支持CCM模式,需要软件来配合使用CTR模式和CBC_MAC模式。

AES协处理器以16个字节为单位工作。一大块数据加载进AES处理器,加密自动执行,结果必须在下一大块数据载入之前,读取出来。在每块数据加载之前,一个开始加密的命令,必须发送给协处理器。

当使用CFB、OFB或者CTR模式时,16字节的加密块将分成4组,每组4个字节。每4个字节加载进入,然后读取4个字节的加密密文结果。

CBC-MAC是CBC模式的变体,当工作在CBC-MAC模式时,一次载入16个字节的数据,除了最后一块数据,在最后一块数据载入之前,需要将加密模式设置为CBC.当最后一块数据载入完成后,读取出来的就是消息的认证码。

CCM模式是CBC-MAC模式和CTR模式的结合。

以下以相关的具体代码来分析AES硬件加密引擎的使用。

在实验这个AES加密引擎的时候,参考了《DN108 Using Encrytion in CC111xFx_CC243x and CC251xFx swra173.pdf》,但是,一步一步按照文档上的来,会卡死在最后一步。这个地方折腾了我好久好久,经过和datasheet详细对比后,终于解决了这个问题。

unsigned char iv_nonce[SIZE_OF_AES_BLOCK]
  = {0xf1, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff};

  /******************************************************************************
 * @fn      SmartLock_Encrypt
 *
 * @brief   Performs CCM encryption.
 *          the Output buffer must large than input buffer. and the length of
 *          the Output buffer should be the 16 multiple.
 * input parameters
 *
 * @param   Input    - Pointer to pre-encrypt string
 * @param   Len      - Length of Input[] in octets
 * @param   AesKey   - Pointer to AES Key
 *
 * output parameters
 *
 * @param   Output   - Pointer to after-encrypt string
 *
 * @return  None
 *
 */
extern void SmartLock_Encrypt(uint8 *Input,uint8 *Output,uint8 Len,uint8 *AesKey);
void SmartLock_Encrypt(uint8 *Input,uint8 *Output,uint8 Len,uint8 *AesKey)
{
  uint8 i, j;
  //HalAesInit();
#if 1
  uint8 blocks,remainder;
  uint8 *bptr;

  //Calcute the AES block length
  blocks = Len >> 4;
  remainder = Len & 0x0f;
  if(remainder)blocks++;

  bptr = (uint8 *)osal_mem_alloc(blocks * SIZE_OF_AES_BLOCK);
  if(!bptr)return;
  osal_memcpy(bptr,Input,Len);
  if(Len != SIZE_OF_AES_BLOCK){
    osal_memcpy(bptr+Len,0,SIZE_OF_AES_BLOCK - remainder);
  }
#endif  

  #if 0
  AES_SET_MODE(AES_MODE_CTR);         //CTR mode.16 bytes divide into 4 group.
  #else
  AES_SET_MODE(AES_MODE_CBC);
  //AES_SET_MODE(AES_MODE_CFB);
  //AES_SET_MODE(AES_MODE_OFB);
  //AES_SET_MODE(AES_MODE_ECB);
  #endif

  //1. Download Key (Set ENCCS.CMD = 10b),
  // and start corresponding AES process (ENCCS.ST = 1)
  AES_SET_OPERATION(AES_LOAD_KEY);
  AES_START();
  for (i = 0; i < SIZE_OF_AES_BLOCK; i++)
  {
    ENCDI = AesKey[i];
  }

  // Monitor AES (ENCCS.RDY) to wait until key downloaded
  while(!(ENCCS & 0x08));

  //2. Dwonload IV/NONCE (Set ENCCS.CMD = 11b)
  // and start corresponding AES process (ENCCS.ST = 1)
  AES_SET_OPERATION(AES_LOAD_IV);
  AES_START();
  for (i = 0; i < SIZE_OF_AES_BLOCK; i++)
  {
    ENCDI = iv_nonce[i];
  }

  // Monitor AES (ENCCS.RDY) to wait until IV/NONCE downloaded
  while(!(ENCCS & 0x08));

  //////////////////////////////////////////////////////////////////////////////
  AES_SET_OPERATION(AES_ENCRYPT);
  // 3. Perform AES encryption/decryption on allocated AES buffer ("aes_buffer_1"):
#if 0 // use for CFB OFB CTR mode
  for (j = 0; j < blocks; j++)
  {
     AES_START();
    // In CTR mode need to write data in block of 32 bits
    unsigned short jj, k;
    for(jj = 0; jj < 4 ; jj++)
    {
        // Writing the input data with zero-padding
        for(k = 0; k < 4; k++)
        {
          ENCDI = bptr[(j*SIZE_OF_AES_BLOCK) + 4*jj + k];
          //ENCDI = Input[(j*SIZE_OF_AES_BLOCK) + 4*jj + k];
        }
        while(!(ENCCS & 0x08))
        {
          wait_count++;
          if(wait_count == 0x00FF)
          {
              wait_count = 0;
              break;
          }
        }
        // Read out data for every 4th byte
        for(k = 0; k < 4; k++)
        {
          Output[(j*SIZE_OF_AES_BLOCK) + 4*jj + k] = ENCDO;
        }
    }
  }
#else //use for ECB CBC mode
    for(j = 0; j< blocks ; j++)
    {
        AES_START();
        unsigned short jj, k;

        // Writing the input data with zero-padding
        for(k = 0; k < 16; k++)
        {
          ENCDI = bptr[(j*SIZE_OF_AES_BLOCK) + k];
          //ENCDI = Input[(j*SIZE_OF_AES_BLOCK) + 4*jj + k];
        }

        while(!(ENCCS & 0x08))
        {
          wait_count++;
          if(wait_count == 0x00FF)
          {
              wait_count = 0;
              break;
          }

        }
        // Read out data for every 4th byte
        for(k = 0; k < 16; k++)
        {
          Output[(j*SIZE_OF_AES_BLOCK) + k] = ENCDO;
        }
    }
#endif

#if 1
  osal_mem_free(bptr);
#endif
}

/******************************************************************************
 * @fn      SmartLock_Decrypt
 *
 * @brief   Performs CCM decryption.
 *          the Output Buffer must great than the Input Buffer, and the Output
 *          Buffer length must be the 16 multiple.
 * input parameters
 *
 * @param   Input    - Pointer to pre-decrypt string
 * @param   Len      - Length of Input[] in octets
 * @param   AesKey  - Pointer to AES Key or Pointer to Key Expansion buffer.
 *
 * output parameters
 *
 * @param   Output   - Pointer to after-decrypt string
 *
 * @return  None
 *
 */
extern void SmartLock_Decrypt(uint8 *Input,uint8 *Output,uint8 Len,uint8 *AesKey);
void SmartLock_Decrypt(uint8 *Input,uint8 *Output,uint8 Len,uint8 *AesKey)
{
  unsigned short i, j;
  //HalAesInit();
#if 1
  uint8 blocks,remainder;
  uint8 *bptr;

  //Calcute the AES block length
  blocks = Len >> 4;
  remainder = Len & 0x0f;
  if(remainder)blocks++;

  bptr = (uint8 *)osal_mem_alloc(blocks * SIZE_OF_AES_BLOCK);
  if(!bptr)return;
  osal_memset( bptr, 0, blocks * SIZE_OF_AES_BLOCK );
#endif  

#if 0
    AES_SET_MODE(AES_MODE_CTR);
#else
    AES_SET_MODE(AES_MODE_CBC);
    //AES_SET_MODE(AES_MODE_CFB);
    //AES_SET_MODE(AES_MODE_OFB);
    //AES_SET_MODE(AES_MODE_ECB);
#endif

  //1. Download Key (Set ENCCS.CMD = 10b),
  // and start corresponding AES process (ENCCS.ST = 1)
  AES_SET_OPERATION(AES_LOAD_KEY);
  AES_START();
  for (i = 0; i < SIZE_OF_AES_BLOCK; i++)
  {
    ENCDI = AesKey[i];
  }

  // Monitor AES (ENCCS.RDY) to wait until key downloaded
  while(!(ENCCS & 0x08));

  //2. Dwonload IV/NONCE (Set ENCCS.CMD = 11b)
  // and start corresponding AES process (ENCCS.ST = 1)
  AES_SET_OPERATION(AES_LOAD_IV);
  AES_START();

  for (i = 0; i < SIZE_OF_AES_BLOCK; i++)
  {
    ENCDI = iv_nonce[i];
  }

  // Monitor AES (ENCCS.RDY) to wait until IV/NONCE downloaded
  while(!(ENCCS & 0x08));
  //////////////////////////////////////////////////////////////////////////////
  AES_SET_OPERATION(AES_DECRYPT);

  // 3. Perform AES encryption/decryption on allocated AES buffer ("aes_buffer_1"):
#if 0  //test for CFB OFB CTR mode
  for (j = 0; j < blocks; j++)
  {
    AES_START();
    // In CTR mode need to write data in block of 32 bits
    unsigned short jj, k;
    for(jj = 0; jj < 4 ; jj++)
    {
        // Writing the input data with zero-padding
        for(k = 0; k < 4; k++)
        {
          ENCDI = Input[(j*SIZE_OF_AES_BLOCK) + 4*jj + k];
        }
        while(!(ENCCS & 0x08))
        {
            wait_count++;
            if(wait_count == 0xFF)
            {
              wait_count = 0;
              break;
            }

        }
        // Read out data for every 4th byte
        for(k = 0; k < 4; k++)
        {
          bptr[(j*SIZE_OF_AES_BLOCK) + 4*jj + k] = ENCDO;
          //Output[(j*SIZE_OF_AES_BLOCK) + 4*jj + k] = ENCDO;
        }
    }
  }
#else //test ECB CBC mode
  for (j = 0; j < blocks; j++)
  {
    AES_START();

     // In CBC mode need to write data in block of 16 bytes
    unsigned short jj, k;

    // Writing the input data with zero-padding
    for(k = 0; k < 16; k++)
    {
      ENCDI = Input[(j*SIZE_OF_AES_BLOCK) + k];
    }
    while(!(ENCCS & 0x08))
    {
        wait_count++;
        if(wait_count == 0xFF)
        {
            wait_count = 0;
            break;
        }
    }
    // Read out data for every 4th byte
    for(k = 0; k < 16; k++)
    {
      bptr[(j*SIZE_OF_AES_BLOCK) + k] = ENCDO;
      //Output[(j*SIZE_OF_AES_BLOCK) + 4*jj + k] = ENCDO;
    }
  }
#endif         

#if 1
  osal_memcpy(Output,bptr,Len);
  osal_mem_free(bptr);
#endif
}

这里面要特别注意下面这句话。

while(!(ENCCS & 0x08)) { wait_count++; if(wait_count == 0xFF) { wait_count = 0; break; } } 在等待硬件加密完成时,不能一直用while循环死等,要有超时推出处理,否则,就会卡死在这里,这是血泪的教训。

AES加密要求16字节块对齐,因此,如果加密字节不是16字节的倍数,输出缓存需要足够的空间(16字节的倍数)来容纳加密密文。

上述两个函数实现了ECB、CBC、CFB、OFB、CTR模式的加密。最后在考虑各种加密模式的优劣性,选用CBC模式加密。CCM模式太复杂,就没研究了。

时间: 2024-10-25 08:21:49

TIMAC 学习笔记(三)的相关文章

Caliburn.Micro学习笔记(三)----事件聚合IEventAggregator和 Ihandle&lt;T&gt;

Caliburn.Micro学习笔记(三)----事件聚合IEventAggregator和 Ihandle<T> 今天 说一下Caliburn.Micro的IEventAggregator和IHandle<T>分成两篇去讲这一篇写一个简单的例子 看一它的的实现和源码 下一篇用它们做一个多语言的demo 这两个是事件的订阅和广播,很强大,但用的时候要小心发生不必要的冲突. 先看一下它的实现思想 在Caliburn.Micro里EventAggregator要以单例的形式出现这样可以

OpenCV for Python 学习笔记 三

给源图像增加边界 cv2.copyMakeBorder(src,top, bottom, left, right ,borderType,value) src:源图像 top,bottem,left,right: 分别表示四个方向上边界的长度 borderType: 边界的类型 有以下几种: BORDER_REFLICATE # 直接用边界的颜色填充, aaaaaa | abcdefg | gggg BORDER_REFLECT # 倒映,abcdefg | gfedcbamn | nmabcd

NFC学习笔记——三(在windows操作系统上安装libnfc)

本篇翻译文章: 这篇文章主要是说明如何在windows操作系统上安装.配置和使用libnfc. 一.基本信息 1.操作系统: Windows Vista Home Premium SP 2 2.硬件信息: System: Dell Inspiron 1720 Processor: Intel Core 2 Duo CPU T9300 @ 2.5GHz 2.5GHz System type: 32-bit Operating System 3.所需软件: 在windows操作系统上安装软件需要下列

swift学习笔记(三)关于拷贝和引用

在swift提供的基本数据类型中,包括Int ,Float,Double,String,Enumeration,Structure,Dictionary都属于值拷贝类型. 闭包和函数同属引用类型 捕获则为拷贝.捕获即定义这些常量和变量的原作用域已不存在,闭包仍然可以在闭包函数体内引用和修改这些值 class属于引用类型. Array的情况稍微复杂一些,下面主要对集合类型进行分析: 一.关于Dictionary:无论何时将一个字典实例赋给一个常量,或者传递给一个函数方法时,在赋值或调用发生时,都会

加壳学习笔记(三)-简单的脱壳思路&amp;调试思路

首先一些windows的常用API: GetWindowTextA:以ASCII的形式的输入框 GetWindowTextW:以Unicaode宽字符的输入框 GetDlgItemTextA:以ASCII的形式的输入框 GetDlgItemTextW:以Unicaode宽字符的输入框 这些函数在使用的时候会有些参数提前入栈,如这函数要求的参数是字符串数目.还有大小写啦之类的东西,这些东西是要在调用该函数之前入栈,也就是依次push,就是说一般前面几个push接着一个call,那前面的push可能

【Unity 3D】学习笔记三十四:游戏元素——常用编辑器组件

常用编辑器组件 unity的特色之一就是编辑器可视化,很多常用的功能都可以在编辑器中完成.常用的编辑器可分为两种:原有组件和拓展组件.原有组件是编辑器原生的一些功能,拓展组件是编辑器智商通过脚本拓展的新功能. 摄像机 摄像机是unity最为核心组件之一,游戏界面中显示的一切内容都得需要摄像机来照射才能显示.摄像机组件的参数如下: clear flags:背景显示内容,默认的是skybox.前提是必须在render settings 中设置天空盒子材质. background:背景显示颜色,如果没

马哥学习笔记三十二——计算机及操作系统原理

缓存方式: 直接映射 N路关联 缓存策略: write through:通写 write back:回写 进程类别: 交互式进程(IO密集型) 批处理进程(CPU密集型) 实时进程(Real-time) CPU: 时间片长,优先级低IO:时间片短,优先级高 Linux优先级:priority 实时优先级: 1-99,数字越小,优先级越低 静态优先级:100-139,数据越小,优先级越高 实时优先级比静态优先级高 nice值:调整静态优先级   -20,19:100,139   0:120 ps

lucene学习笔记(三)

好几天没更新了.更新一下,方便自己和大家学习. 这是最基本的代码 package index; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document;

python 学习笔记 三 字典

字典 Python的高效的key/value哈希表结构叫做"dict", dict的内容可以写成一系列的key:value对并放入{ }中, 相当于: dict = {key1:value1, key2:value2, ...}, 一个空的字典就是俩个大括号{ }. 下面是从一个空字典创建字典以及一些关键点: 数字, 字符串和元组可以作为字典的key, value可以是任何类型(包括字典). ## Can build up a dict by starting with the the