zoukankan      html  css  js  c++  java
  • AES加密算法C代码分析

    0.引言

    对于加密算法的软件实现,通常已经有很多的成熟的库可供选择,只需要根据自己的要求进行选择即可相应的库即可(有的可能需要进行些许修改)。这里选择的是C语言实现的一个开源密码库mbedTLS,mbedTLS由XySSL发展而来,后改为PolarSSL,PolarSSL被ARM公司收购后改成了mbedTLS,主要用于物联网等安全嵌入式领域。mbedTLS实现了常见的分组加密算法、hash算法、RSA以及ECC公钥密码体制,一个适用于嵌入式的SSL协议以及X509证书等,基本能够满足大部分的嵌入式安全应用。

    1.AES加密算法代码分析

    这里不再详细的介绍AES的数学原理以及设计思路等,只是结合软件进行代码分析,关于AES的官方文档可以在NIST网站上下载得到。

    1)数据结构

    数据结构与算法密切相关,通常分组加密算法定义的数据结构都较为类似,mbedTLS的AES定义了如下数据结构:

    typedef struct
    {
        int nr;                     /*!<  number of rounds  */
        uint32_t *rk;               /*!<  AES round keys    */
        uint32_t buf[68];           /*!<  unaligned data    */
    }
    mbedtls_aes_context;

    2)算法主体

    分组加密算法的软件实现通常会采用“查找表”的方式来提高算法的运算速度,通过表格或者预计算表格直接查表得到对应的算法运算结果。

    对算法的分析仅仅以加密算法为例,解密算法的过程基本类似,只是前向表格改为逆向表格而已。

    下面先给出代码再进行分析:

     1 void mbedtls_aes_encrypt( mbedtls_aes_context *ctx,
     2                           const unsigned char input[16],
     3                           unsigned char output[16] )
     4 {
     5     int i;
     6     uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3;
     7 
     8     RK = ctx->rk;
     9 
    10     GET_UINT32_LE( X0, input,  0 ); X0 ^= *RK++;
    11     GET_UINT32_LE( X1, input,  4 ); X1 ^= *RK++;
    12     GET_UINT32_LE( X2, input,  8 ); X2 ^= *RK++;
    13     GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++;
    14 
    15     for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- )
    16     {
    17         AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
    18         AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 );
    19     }
    20 
    21     AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
    22 
    23     X0 = *RK++ ^ 
    24             ( (uint32_t) FSb[ ( Y0       ) & 0xFF ]       ) ^
    25             ( (uint32_t) FSb[ ( Y1 >>  8 ) & 0xFF ] <<  8 ) ^
    26             ( (uint32_t) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^
    27             ( (uint32_t) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 );
    28 
    29     X1 = *RK++ ^ 
    30             ( (uint32_t) FSb[ ( Y1       ) & 0xFF ]       ) ^
    31             ( (uint32_t) FSb[ ( Y2 >>  8 ) & 0xFF ] <<  8 ) ^
    32             ( (uint32_t) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^
    33             ( (uint32_t) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 );
    34 
    35     X2 = *RK++ ^ 
    36             ( (uint32_t) FSb[ ( Y2       ) & 0xFF ]       ) ^
    37             ( (uint32_t) FSb[ ( Y3 >>  8 ) & 0xFF ] <<  8 ) ^
    38             ( (uint32_t) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^
    39             ( (uint32_t) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 );
    40 
    41     X3 = *RK++ ^ 
    42             ( (uint32_t) FSb[ ( Y3       ) & 0xFF ]       ) ^
    43             ( (uint32_t) FSb[ ( Y0 >>  8 ) & 0xFF ] <<  8 ) ^
    44             ( (uint32_t) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^
    45             ( (uint32_t) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 );
    46 
    47     PUT_UINT32_LE( X0, output,  0 );
    48     PUT_UINT32_LE( X1, output,  4 );
    49     PUT_UINT32_LE( X2, output,  8 );
    50     PUT_UINT32_LE( X3, output, 12 );
    51 }

    分析可以得到算法的过程为:

    轮密钥加->N-1轮轮变换->末轮变换

    其中末轮变换只有:字节置换(subbyte)/行移位(shiftrow)/轮密钥加(addroundkey)

    中间的轮变换则为:字节置换(subbyte)/行移位(shiftrow)/列混合(mixcol)/轮密钥加(addroundkey)

    上述代码中,RK为轮密钥,FSb为S盒(Subbyte)的查找表,FTx则包括字节置换与列混合两个过程,因为行移位为线性变换,其运算过程可以和列混合进行交换。

    AES_ROUND由宏定义得到,代码如下:

     1 #define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3)     
     2 {                                               
     3     X0 = *RK++ ^ FT0[ ( Y0       ) & 0xFF ] ^   
     4                  FT1[ ( Y1 >>  8 ) & 0xFF ] ^   
     5                  FT2[ ( Y2 >> 16 ) & 0xFF ] ^   
     6                  FT3[ ( Y3 >> 24 ) & 0xFF ];    
     7                                                 
     8     X1 = *RK++ ^ FT0[ ( Y1       ) & 0xFF ] ^   
     9                  FT1[ ( Y2 >>  8 ) & 0xFF ] ^   
    10                  FT2[ ( Y3 >> 16 ) & 0xFF ] ^   
    11                  FT3[ ( Y0 >> 24 ) & 0xFF ];    
    12                                                 
    13     X2 = *RK++ ^ FT0[ ( Y2       ) & 0xFF ] ^   
    14                  FT1[ ( Y3 >>  8 ) & 0xFF ] ^   
    15                  FT2[ ( Y0 >> 16 ) & 0xFF ] ^   
    16                  FT3[ ( Y1 >> 24 ) & 0xFF ];    
    17                                                 
    18     X3 = *RK++ ^ FT0[ ( Y3       ) & 0xFF ] ^   
    19                  FT1[ ( Y0 >>  8 ) & 0xFF ] ^   
    20                  FT2[ ( Y1 >> 16 ) & 0xFF ] ^   
    21                  FT3[ ( Y2 >> 24 ) & 0xFF ];    
    22 }

    mbedTLS给出了两种实现,1.ROM_TABLE的方式,所有表格直接给出,不再一一列出各种表格;2.表格预计算的方式,由于AES的设计是基于有限域的,表格预计算需要一些有限域的辅助函数,整个预计算的过程如下:

     1 #define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 )
     2 #define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) )
     3 #define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 )
     4 
     5 static int aes_init_done = 0;
     6 
     7 static void aes_gen_tables( void )
     8 {
     9     int i, x, y, z;
    10     int pow[256];
    11     int log[256];
    12 
    13     /*
    14      * compute pow and log tables over GF(2^8)
    15      */
    16     for( i = 0, x = 1; i < 256; i++ )
    17     {
    18         pow[i] = x;
    19         log[x] = i;
    20         x = ( x ^ XTIME( x ) ) & 0xFF;
    21     }
    22 
    23     /*
    24      * calculate the round constants
    25      */
    26     for( i = 0, x = 1; i < 10; i++ )
    27     {
    28         RCON[i] = (uint32_t) x;
    29         x = XTIME( x ) & 0xFF;
    30     }
    31 
    32     /*
    33      * generate the forward and reverse S-boxes
    34      */
    35     FSb[0x00] = 0x63;
    36     RSb[0x63] = 0x00;
    37 
    38     for( i = 1; i < 256; i++ )
    39     {
    40         x = pow[255 - log[i]];
    41 
    42         y  = x; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF;
    43         x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF;
    44         x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF;
    45         x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF;
    46         x ^= y ^ 0x63;
    47 
    48         FSb[i] = (unsigned char) x;
    49         RSb[x] = (unsigned char) i;
    50     }
    51 
    52     /*
    53      * generate the forward and reverse tables
    54      */
    55     for( i = 0; i < 256; i++ )
    56     {
    57         x = FSb[i];
    58         y = XTIME( x ) & 0xFF;
    59         z =  ( y ^ x ) & 0xFF;
    60 
    61         FT0[i] = ( (uint32_t) y       ) ^
    62                  ( (uint32_t) x <<  8 ) ^
    63                  ( (uint32_t) x << 16 ) ^
    64                  ( (uint32_t) z << 24 );
    65 
    66         FT1[i] = ROTL8( FT0[i] );
    67         FT2[i] = ROTL8( FT1[i] );
    68         FT3[i] = ROTL8( FT2[i] );
    69 
    70         x = RSb[i];
    71 
    72         RT0[i] = ( (uint32_t) MUL( 0x0E, x )       ) ^
    73                  ( (uint32_t) MUL( 0x09, x ) <<  8 ) ^
    74                  ( (uint32_t) MUL( 0x0D, x ) << 16 ) ^
    75                  ( (uint32_t) MUL( 0x0B, x ) << 24 );
    76 
    77         RT1[i] = ROTL8( RT0[i] );
    78         RT2[i] = ROTL8( RT1[i] );
    79         RT3[i] = ROTL8( RT2[i] );
    80     }
    81 }

    在有限域运算中,使用了对数表的方式来实现有限域的乘法操作,这是AES设计者在提交算法是所提供的一种计算方式。

    38~50行代码进行有限域求逆算法(使用对数表),再进行仿射变换,求得S盒,同时可以得到逆向S盒。AES的S盒设计为(A*x-1+b),A为2进制矩阵,b为2进制列向量(0x63)。

    再计算FTx,FTx的计算需要有限域乘法操作,其乘法为固定乘法操作,主要有x2与x3,(逆变换乘数为0x0e,0x09,0x0d,0x0b)。其中有限域的乘法运算也是基于对数表完成的。

    2.算法简介

    ……

  • 相关阅读:
    iaf——接口自动化测试框架
    性能优化系列
    MVC架构简介及其测试策略
    10种常见的软件架构模式
    软件开发框架分析和架构模式
    安全测试基础&安全测试---AppScan扫描工具
    WEB安全测试要点总结
    大数据Hadoop Hive HBase Spark Storm
    第三方授权方式1
    java-weixin-tools接入微信
  • 原文地址:https://www.cnblogs.com/lkiller/p/5093099.html
Copyright © 2011-2022 走看看