1. 程式人生 > >AES加密演算法C程式碼分析

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.演算法簡介

……

相關推薦

AES加密演算法C程式碼分析

0.引言 對於加密演算法的軟體實現,通常已經有很多的成熟的庫可供選擇,只需要根據自己的要求進行選擇即可相應的庫即可(有的可能需要進行些許修改)。這裡選擇的是C語言實現的一個開源密碼庫mbedTLS,mbedTLS由XySSL發展而來,後改為PolarSSL,PolarSSL被

AES加密演算法C++實現

(1)aes.h #ifndef aes_h__ #define aes_h__ class AES { public: AES(unsigned char* key); virtual ~AES(); unsigned char* Cipher(unsigned char* inpu

aes加密演算法java程式碼實現

這周學習下aes加密演算法,網上一搜發現沒java程式碼版的,查閱了aes演算法原理及幾篇文章,自己照著原理把java版程式碼做出來了。本文僅呈現演算法的java程式碼實現,關於演算法原理可查閱最底部的參考文獻。 Aes加密及解密流程圖 package com.vk.

openssl AES 加密演算法程式碼例項

一、AES演算法簡介 1、AES演算法介紹         密碼學中的高階加密標準(Advanced Encryption Standard,AES),又稱 Rijndael加密法,是美國聯邦政府採用的一種區塊加密標準。這個標準用來替代原先的DES,已經被多方分析且廣

c++實現aes加密演算法,對字串進行加密

我的blog中,已經寫過一篇關於aes加密演算法的呼叫。不過使用的引數必須時unsigned char型別。我們在 程式設計中使用最多的char型別,我從網上下載了一個程式碼,追加了一部分程式碼。     其主要功能進行實現unsigned char型別資料到char

AES加密演算法原始碼c++版(其實跟c版差不多)

打包下載 //============================================================================ // 檔名: AES.h (c++) // 作者    : 幽靈劍客 // 版本    : 2008021

C++ 128位 AES加密演算法

宣告檔案 AES.h #ifndef _AES_H_ #define _AES_H_ #include <Windows.h> class CAES { public: /* * 功 能:初始化 * 參

AES加密演算法的java實現

在實現AES演算法的時候,其實步驟和我之前寫的那個DES加密演算法的差不多的 也是一樣,網上的基本都是基於一個內建好的字串進行加密,我這裡就新添加了一些新的功能 轉載使用的話,請註明一下哦! package function; import java.util.*; import ja

實驗二 擴充套件歐幾里得演算法c++程式碼

#include<iostream> #include<stdio.h> using namespace std; int x,y,q; void extend_Eulid(int a,int b) { if(b==0) { x=1; y=0; q=a; }

Go語言與AES加密演算法 —— 簡介、AES演算法案例

AES簡介 高階加密標準(英語:Advanced Encryption Standard,縮寫:AES),在密碼學中又稱Rijndael加密法,是美國聯邦政府採用的一種區塊加密標準。這個標準用來替代原先的DES,已經被多方分析且廣為全世界所使用。經過五年的甄選流程,高階加密標準由美國國家標準

php實現封裝aes加密演算法,與前端互動

class AesSecurity { /** * method 為AES-128-CBC時 * @var string傳入要加密的明文 * 傳入一個16位元組的key * 傳入一個16位元組的初始偏移向量IV */ priv

AES加密演算法詳解

AES 是一個對稱密碼分組演算法,分組長度為128bit,金鑰長度為128、192 和 256 bit。 整個加密過程如下圖所示。 1.金鑰生成演算法  金鑰擴充套件過程:     1)  將種子金鑰按下圖所示的格式排列,然後每32bit分別記為w[0]、w[1]、w[2]、w

探索安全-- AES加密演算法

最近收到訊息在加密演算法領域具有一定地位的 AES加密演算法(256位) 面臨著被破解的境遇,所以呢,簡單來聊一聊       AES 設計有三個金鑰長度:128,192,256位,相對而言,AES的128金鑰比DES的56金鑰強1021倍[2]。AES

AES加密演算法的詳細介紹與實現

#include <stdio.h> #include <stdlib.h> #include <string.h> #include "aes.h" /** * S盒 */ static const int S[16][16] = { 0x63, 0

base64加密演算法C++實現

  base64編碼原理:維基百科 - Base64   其實編碼規則很簡單,將字串按每三個字元組成一組,因為每個字元的 ascii 碼對應 0~127 之間(顯然,不考慮其他字符集編碼),即每個字元的二進位制以 8 bit 儲存,$ 3 \times 8 = 4 \times 6 $,這樣就可以很方便的轉

AES加密演算法簡介

AES-對稱加密演算法       屬於對稱加密演算法。       對稱加密演算法只是為了區分非對稱加密演算法。其中鮮明的特點是對稱加密是加密解密使用相同的金鑰,而非對稱加密加密和解密時使用的金鑰不一樣。對於大部分情況我們都使

MD5加密演算法C語言實現

md5.h #ifndef MD5_H #define MD5_H typedef struct { unsigned int count[2]; unsigned int state[4]; unsigned char buffe

java使用AES加密c++使用crypto++解密

最近在做一個專案,需要用到加密解密,java端用AES加密了,準備把加好密的資料傳送到c++寫的服務端(crypto++開源庫)。搞了幾天,從不會到會,配置差點把我搞瘋了,太它媽的蛋疼。 編譯器:vs2017 我用的是cryptopp-CRYPTOPP_7_0_0這個

歸併排序演算法 C程式碼實現

合併排序(MERGE SORT)是又一類不同的排序方法,合併的含義就是將兩個或兩個以上的有序資料序列合併成一個新的有序資料序列,因此它又叫歸併演算法。它的基本思想就是假設陣列A有N個元素,那麼可以看成陣列A是又N個有序的子序列組成,每個子序列的長度為1,然後再兩兩合併,得到

《統計學習方法》+樸素貝葉斯演算法+C++程式碼(簡單)實現

        首先,學習樸素貝葉斯演算法得了解一些基本知識,比如全概率公式和貝葉斯公式,這些知識隨便找一本書或者在網上都能夠獲得。在此,這裡僅關注貝葉斯演算法本身,以及其具體的實現(以例4.1的例子為參考)。     貝葉斯演算法:     程式設計實現以上演算法,