国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

AES-128算法實現(xiàn)(附C++源碼)

這篇具有很好參考價值的文章主要介紹了AES-128算法實現(xiàn)(附C++源碼)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

AES-128算法實現(xiàn)(附C++源碼)

前言

這次寫AES算法的實驗,發(fā)現(xiàn)還是比較麻煩的。同時,身邊的很多同學對于該算法的編程實現(xiàn)會覺得比較晦澀,再加上AES本身的算法本身也比較復雜,使得實現(xiàn)起來比較麻煩,除此之外,很多同學也反映出網(wǎng)上的很多源碼的程序都不能跑?;谶@些情況,我決定出這么的一篇blog,希望能夠幫助你們理解AES算法并完成對應的編程實現(xiàn)。

AES的算法流程

不妨參考下圖

AES-128算法實現(xiàn)(附C++源碼)

或者參考這個來自課件的流程圖,會更清楚

AES-128算法實現(xiàn)(附C++源碼)

如你所見,AES的流程會分為幾部分:密鑰拓展、輪密鑰加、字節(jié)代換、行位移列混淆。 其中后面四部分會出現(xiàn)在迭代輪數(shù)中,也在解密中 會有對應的 逆操作。

幾個你會用到的常量

S盒
// s 盒, 用于密鑰生成和加密時的字節(jié)代換
static const int S[16][16] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
	0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
	0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
	0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
	0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
	0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
	0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
	0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
	0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
	0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
	0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
	0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
	0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
	0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
	0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
	0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };

逆S盒
// 逆s 盒, 用于在解密時的 逆字節(jié)變換
static const int S1[16][16] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
	0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
	0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
	0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
	0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
	0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
	0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
	0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
	0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
	0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
	0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
	0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
	0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
	0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
	0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
	0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };

常量輪值表

與網(wǎng)上其他大大的不同,我采用了long long 存儲,主要是為了防止超限。

// 常量輪值表
// 這里將原來的復制粘貼過來的輪常量類別改成了 long long
// 原因在于第8位超出int限,數(shù)據(jù)溢出
static const long long Rcon[10] = { 
	0x01000000, 0x02000000,
	0x04000000, 0x08000000,
	0x10000000, 0x20000000,
	0x40000000, 0x80000000,
	0x1b000000, 0x36000000 
};

密鑰拓展

密鑰拓展的主要是需要先將現(xiàn)有的密鑰進行分組,這里是分成了四組,然后進行40次拓展,我們假設的原始的分好組的占最終的 keys[0:3], 對于任意的 i >= 4, i < 44, 有:
k e y s [ i ] = { k e y s [ i ? 1 ] ⊕ k e y s [ i ? 4 ] , i % 4 ! = 0 T ( k e y s [ i ? 1 ] ) ⊕ k e y s [ i ? 4 ] , i % 4 = = 0 keys[i] = \left\{ \begin{aligned} keys[i - 1] \oplus keys[i - 4], \qquad i \% 4 != 0 \\ T(keys[i-1]) \oplus keys[i - 4], \qquad i \% 4 == 0 \end{aligned} \right. keys[i]={keys[i?1]keys[i?4],i%4!=0T(keys[i?1])keys[i?4],i%4==0?
T函數(shù)是一個復雜函數(shù),涉及到字循環(huán)、字節(jié)代換、輪常量異或。

vector<string> extend_key(string& key)
{
	// 先分組
	vector<string> w_key = group_key(key);
	for (int i = 0; i < 40; ++i)
	{
		string w = "";
		int index = 4 + i;
		string temp = w_key[index - 1];
		// 4 的倍數(shù)的時候,需要調用T函數(shù)
		if (index % 4 == 0)
		{
			temp = T(temp, index / 4 - 1);
		}
		w = string_xor(temp, w_key[index - 4]);

		// 壓入數(shù)組中
		w_key.push_back(w);
	}

	return w_key;
}

輪密鑰加

該部分其實在不同的輪數(shù)中,將密文或者明文與對應密鑰部分做異或操作。我使用的是字符串存儲,所以也做了字符串異或的操作。

// 一開始的先進行一次輪密鑰加
vector<string> texts = group_key(plain_text);
for (int i = 0; i < 4; ++i)
{
texts[i] = string_xor(texts[i], keys[i]);
}
// 寫一個字符串對應的16進制數(shù)異或的函數(shù)
string string_xor(string s1, string s2)
{
	long long num1 = str_long(s1), num2 = str_long(s2);
	long long num = num1 ^ num2;
	// 再把數(shù)字轉為字符串
	string ans = int_to_chs(num);
	// 不足8位的時候補位
	while (ans.length() < 8)
	{
		ans = "0" + ans;
	}
	return ans;
}

字節(jié)代換

其實就是用當前的坐標找到S盒或者逆S盒對應的替換值,先將字符轉成數(shù)值坐標,再利用坐標替換,然后再轉換成數(shù)值即可。

// 字節(jié)代換 的實現(xiàn)
string wordbyte_sub(string& wi_1)
{
	int len = wi_1.length();
	string ans = "";
	for (int i = 0; i < len; i += 2)
	{
		// 先獲取當前的下標
		int x = ch_to_int(wi_1[i]), y = ch_to_int(wi_1[i + 1]);
		// 然后獲取當前的數(shù)字
		int num = S[x][y];
		// 先將數(shù)值轉化為字符串
		string s = int_to_chs(num);
		// 然后不足的話補0
		while (s.length() < 2)
		{
			s = "0" + s;
		}

		// 加起來
		ans += s;
	}
	return ans;
}

行移位

其實就是根據(jù)在矩陣中第幾行,然后循環(huán)左移或者右移多少位。

由于我是采用字符串數(shù)組實現(xiàn),所以這里的行移位其實對應到代碼中其實是列移位。

// 行移位函數(shù)
vector<string> move_row(vector<string>& s)
{
	vector<string> ans = s;
	// 幾個比較麻煩的地方
	// 我的字符串數(shù)組其實每個是對應一列, 所以其實是對應到列進行移位
	// 一行對應有兩個16進制數(shù),所以需要兩個一起移動,其實就是對應兩列一起動
	for (int i = 0; i < 4; ++i)
	{
		int k = i * 2;
		// 就原本矩陣對應的行移位,對于字符串數(shù)組就是列移位
		for (int j = 0; j < 4; ++j)
		{
			ans[j][k] = s[(j + i) % 4][k];
			ans[j][k + 1] = s[(j + i) % 4][k + 1];
		}
	}
	return ans;
}

列混淆

這一部分需要將矩陣與另外一個矩陣相乘,不過這里有一個簡單的轉換公式。

AES-128算法實現(xiàn)(附C++源碼)

上面是逆變換操作,則是分別對應 ×e,b,d,9.

和行移位類似,這里的列混淆在代碼中其實就是一個行操作。

除此之外,在操作的時候,這些乘法不妨將其拆解成2的i次冪,這樣我們可以在 GF(2^8)上直接進行移位操作。

// 接下來就是列混淆
vector<string> col_confuse(vector<string>& s)
{
	vector<string> ans = s;
	// 算法中對應的是列,這邊就直接變成了行,即字符
	for (int i = 0; i < 4; ++i)
	{
		// 需要先將字符串拆分成兩兩一組,共4組
		auto temp = split_s(s[i]);
		// 先轉成數(shù)字
		int s0 = str_long(temp[0]), s1 = str_long(temp[1]), s2 = str_long(temp[2]), 
			s3 = str_long(temp[3]);
		// 計算混淆后的值
		int t0 = power(s0) ^ power(s1) ^ s1 ^ s2 ^ s3;
		int t1 = s0 ^ power(s1) ^ power(s2) ^ s2 ^ s3;
		int t2 = s0 ^ s1 ^ power(s2) ^ s3 ^ power(s3);
		int t3 = s0 ^ power(s0) ^ s1 ^ s2 ^ power(s3);
		// 轉換成字符串再相加
		ans[i] = int_ch2(t0) + int_ch2(t1) + int_ch2(t2) + int_ch2(t3);
	}
	return ans;
}

完整源碼(C++)

輸入和輸出

輸入:

0
0123456789abcdeffedcba9876543210
0f1571c947d9e8590cb7add6af7f6798

輸出:

ff0b844a0853bf7c6934ab4364148fb9

輸入:

1
ff0b844a0853bf7c6934ab4364148fb9
0f1571c947d9e8590cb7add6af7f6798

輸出:

0123456789abcdeffedcba9876543210
#include<iostream>
#include<string>
#include<vector>

using namespace std;

// 用于只選取低8bit
#define MOD 256

// s 盒, 用于密鑰生成和加密時的字節(jié)代換
static const int S[16][16] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
	0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
	0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
	0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
	0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
	0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
	0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
	0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
	0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
	0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
	0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
	0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
	0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
	0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
	0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
	0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };

// 逆s 盒, 用于在解密時的 逆字節(jié)變換
static const int S1[16][16] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
	0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
	0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
	0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
	0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
	0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
	0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
	0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
	0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
	0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
	0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
	0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
	0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
	0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
	0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
	0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };

// 常量輪值表
// 這里將原來的復制粘貼過來的輪常量類別改成了 long long
// 原因在于第8位超出int限,數(shù)據(jù)溢出
static const long long Rcon[10] = { 
	0x01000000, 0x02000000,
	0x04000000, 0x08000000,
	0x10000000, 0x20000000,
	0x40000000, 0x80000000,
	0x1b000000, 0x36000000 
};

// 將字符轉整數(shù)
int ch_to_int(char& ch);

// 將16進制字符串轉為數(shù)字
long long str_long(string str)
{
	long long ans = 0;
	// 遍歷字符串,將字符串的內(nèi)容變?yōu)?6進制數(shù)字
	for (char ch : str)
	{
		ans = ans * 16 + ch_to_int(ch);
	}
	return ans;
}

// 出于方便考慮,還是寫一個字符轉成數(shù)字的函數(shù)
int ch_to_int(char& ch)
{
	int ans = 0;
	// 數(shù)字的時候
	if (ch >= 48 && ch <= 57)
	{
		ans = ch - '0';
	}
	// 16進制中a 到 f
	else if (ch >= 'a' && ch <= 'f')
	{
		ans = ch - 'a' + 10;
	}
	// 這個在本實驗的樣例中,其實不會運行到的
	else if (ch >= 'A' && ch <= 'F')
	{
		ans = ch - 'A' + 10;
	}
	return ans;
}

// 然后再寫一個數(shù)字轉16進制字符串的吧,只考慮小寫吧
// 針對的其實是單個16進制
string int_to_chs(long long num)
{
	string ans = "";
	while (num)
	{
		// 通過位運算得到低四位
		int x = num & 0xf;
		// 根據(jù)數(shù)值進行區(qū)分
		if (x <= 9)
		{
			char ch = x + '0';
			ans += ch;
		}
		else
		{
			char ch = x - 10 + 'a';
			ans += ch;
		}
		// 移位,其實相當于 / 16
		num >>= 4;
	}
	// 然后反轉字符
	int left = 0, right = ans.length() - 1;
	// 雙指針實現(xiàn)字符串反轉
	while (left < right)
	{
		char  ch = ans[left];
		ans[left] = ans[right];
		ans[right] = ch;
		left++;
		right--;
	}
	return ans;
}

// 得先分組
vector<string> group_key(string& key)
{
	// 四組
	vector<string> groups(4);
	// 初始下標
	int index = 0;
	// 分組
	for (string& g : groups)
	{
		g = key.substr(index, 8);
		index += 8;
	}
	return groups;
}

// 字節(jié)循環(huán)
string loop_wordbyte(string& wi_1);

// 字節(jié)代換
string wordbyte_sub(string& wi_1);

// 輪常量異或
string xor_with_const(string& wi_1, int rounds);


// 拓展的時候,下標為4 的倍數(shù)時,需要麻煩一些,需要使用一個變換的T函數(shù)
string T(string& wi_1, int round)
{
	// T 變換由3部分構成, 所以可以再寫三個函數(shù)
	// 先進行字循環(huán)
	string ans = loop_wordbyte(wi_1);
	// 然后字節(jié)代換
	ans = wordbyte_sub(ans);
	// 最后是輪異或
	ans = xor_with_const(ans, round);

	return ans;
}

// 字節(jié)循環(huán)實現(xiàn)
string loop_wordbyte(string& wi_1)
{
	string ans = wi_1.substr(2) + wi_1.substr(0, 2);
	return ans;
}

// 字節(jié)代換 的實現(xiàn)
string wordbyte_sub(string& wi_1)
{
	int len = wi_1.length();
	string ans = "";
	for (int i = 0; i < len; i += 2)
	{
		// 先獲取當前的下標
		int x = ch_to_int(wi_1[i]), y = ch_to_int(wi_1[i + 1]);
		// 然后獲取當前的數(shù)字
		int num = S[x][y];
		// 先將數(shù)值轉化為字符串
		string s = int_to_chs(num);
		// 然后不足的話補0
		while (s.length() < 2)
		{
			s = "0" + s;
		}

		// 加起來
		ans += s;
	}
	return ans;
}

// 輪常量異或
string xor_with_const(string& wi_1, int rounds)
{
	// 先將字符串變?yōu)閿?shù)字
	long long num = 0;
	for (int i = 0; i < 8; ++i)
	{
		char ch = wi_1[i];
		num = num * 16 + ch_to_int(ch);
	}
	// 計算異或結果
	num ^= Rcon[rounds];

	// 將num轉化為字符串
	string res = int_to_chs(num);
	while (res.length() < 8)
	{
		res = "0" + res;
	}
	return res;
}

// 寫一個字符串對應的16進制數(shù)異或的函數(shù)
string string_xor(string s1, string s2)
{
	long long num1 = str_long(s1), num2 = str_long(s2);
	long long num = num1 ^ num2;
	// 再把數(shù)字轉為字符串
	string ans = int_to_chs(num);
	// 不足8位的時候補位
	while (ans.length() < 8)
	{
		ans = "0" + ans;
	}
	return ans;
}


// 先要進行密鑰的拓展
vector<string> extend_key(string& key)
{
	// 先分組
	vector<string> w_key = group_key(key);
	for (int i = 0; i < 40; ++i)
	{
		string w = "";
		int index = 4 + i;
		string temp = w_key[index - 1];
		// 4 的倍數(shù)的時候,需要調用T函數(shù)
		if (index % 4 == 0)
		{
			temp = T(temp, index / 4 - 1);
		}
		w = string_xor(temp, w_key[index - 4]);

		// 壓入數(shù)組中
		w_key.push_back(w);
	}

	return w_key;
}

// 行移位函數(shù)
vector<string> move_row(vector<string>& s)
{
	vector<string> ans = s;
	// 幾個比較麻煩的地方
	// 我的字符串數(shù)組其實每個是對應一列, 所以其實是對應到列進行移位
	// 一行對應有兩個16進制數(shù),所以需要兩個一起移動,其實就是對應兩列一起動
	for (int i = 0; i < 4; ++i)
	{
		int k = i * 2;
		// 就原本矩陣對應的行移位,對于字符串數(shù)組就是列移位
		for (int j = 0; j < 4; ++j)
		{
			ans[j][k] = s[(j + i) % 4][k];
			ans[j][k + 1] = s[(j + i) % 4][k + 1];
		}
	}
	return ans;
}

// 寫個函數(shù)分割一下字符串,長度為8變4組
vector<string> split_s(string& s)
{
	vector<string> ans;
	for (int i = 0; i < s.length(); i += 2)
	{
		ans.emplace_back(s.substr(i, 2));
	}
	return ans;
}

string int_ch2(int num)
{
	string ans = int_to_chs(num);
	// 這里是為了確保只有兩位字符串
	while(ans.length() < 2)
	{
		ans = "0" + ans;
	}
	return ans;
}

// 移位函數(shù),其實就是在GF(2^8)的范圍進行冪次操作
int power(int num)
{
	int ans = (num << 1) % MOD;
	// 如果第七位是1
	if (num & 0x80)
	{
		ans ^= 0x1b;
	}
	return ans;
}

// 接下來就是列混淆
vector<string> col_confuse(vector<string>& s)
{
	vector<string> ans = s;
	// 算法中對應的是列,這邊就直接變成了行,即字符
	for (int i = 0; i < 4; ++i)
	{
		// 需要先將字符串拆分成兩兩一組,共4組
		auto temp = split_s(s[i]);
		// 先轉成數(shù)字
		int s0 = str_long(temp[0]), s1 = str_long(temp[1]), s2 = str_long(temp[2]), 
			s3 = str_long(temp[3]);
		// 計算混淆后的值
		int t0 = power(s0) ^ power(s1) ^ s1 ^ s2 ^ s3;
		int t1 = s0 ^ power(s1) ^ power(s2) ^ s2 ^ s3;
		int t2 = s0 ^ s1 ^ power(s2) ^ s3 ^ power(s3);
		int t3 = s0 ^ power(s0) ^ s1 ^ s2 ^ power(s3);
		// 轉換成字符串再相加
		ans[i] = int_ch2(t0) + int_ch2(t1) + int_ch2(t2) + int_ch2(t3);
	}
	return ans;
}

// 寫一個測試函數(shù)
void show(vector<string>& text)
{
	for (auto t : text)
	{
		cout << t;
	}
	cout << endl;
}

// 先定義一個 aes 加密函數(shù)
void aes(string& plain_text, string& key)
{
	// 先拓展密鑰
	vector<string> keys = extend_key(key);

	int index = 0;
	// 然后就是10輪迭代
	// 需要知道明文其實是32位,所以需要搞4下
	// 可以先把明文也分組

	// 一開始的先進行一次輪密鑰加
	vector<string> texts = group_key(plain_text);
	for (int i = 0; i < 4; ++i)
	{
		texts[i] = string_xor(texts[i], keys[i]);
	}
	index += 4;
	// 然后十次迭代
	for (int k = 0; k < 10; ++k)
	{
		for (int j = 0; j < 4; ++j)
		{
			// 先是字節(jié)代換
			texts[j] = wordbyte_sub(texts[j]);
		}
		// 然后是行移位
		texts = move_row(texts);

		if (k < 9)
		{
			// 再來列混淆
			texts = col_confuse(texts);
		}

		// 輪密鑰加
		for (int i = 0; i < 4; ++i)
		{
			texts[i] = string_xor(texts[i], keys[i + index]);
		}

		index += 4;
	}
	string ans = "";
	for (int i = 0; i < 4; ++i)
	{
		ans += texts[i];
	}
	cout << ans << endl;
}

// 行移位的逆操作函數(shù)
vector<string> in_move_row(vector<string>& s)
{
	vector<string> ans = s;
	// 現(xiàn)在變成了逆操作
	for (int i = 0; i < 4; ++i)
	{
		int k = i * 2;
		// 就原本矩陣對應的行移位,對于字符串數(shù)組就是列移位
		for (int j = 0; j < 4; ++j)
		{
			ans[j][k] = s[(j - i + 4) % 4][k];
			ans[j][k + 1] = s[(j - i + 4) % 4][k + 1];
		}
	}
	return ans;
}

// 逆字節(jié)代換
string in_wordbyte_sub(string& wi_1)
{
	int len = wi_1.length();
	string ans = "";
	for (int i = 0; i < len; i += 2)
	{
		// 先獲取當前的下標
		int x = ch_to_int(wi_1[i]), y = ch_to_int(wi_1[i + 1]);
		// 然后獲取當前的數(shù)字
		int num = S1[x][y];
		// 先將數(shù)值轉化為字符串
		string s = int_to_chs(num);
		// 然后不足的話補0
		while (s.length() < 2)
		{
			s = "0" + s;
		}

		// 加起來
		ans += s;
	}
	return ans;
}


// 列混淆的逆變換
vector<string> in_col_confuse(vector<string>& s)
{
	// 逆變換其實原來的變換矩陣的逆矩陣,對應0xe, 0xb, 0xd, 0x9
	// 4 列

	vector<string> ans = s;
	for (int i = 0; i < 4; ++i)
	{
		// 先分割成4個兩位數(shù)字
		auto temp = split_s(s[i]);
		// 轉換成數(shù)字
		vector<int> nums(4);
		for (int j = 0; j < 4; ++j)
		{
			nums[j] = str_long(temp[j]);
		}
		vector<int> t4(4, 0);
		for (int j = 0; j < 4; ++j)
		{
			for (int t = 0; t < 4; ++t)
			{
				int k = (t - j + 4) % 4;
				t4[j] ^= power(power(power(nums[t])));		// 表示8
				switch (k)
				{
				case 0:		// 0xe = 8 + 4 + 2
				{
					t4[j] ^= power(power(nums[t])) ^ power(nums[t]);
					break;
				}
				case 1:		// 0xb = 8 + 2 + 1
				{
					t4[j] ^= power(nums[t]) ^ nums[t];
					break;
				}
				case 2:		// 0xd = 8 + 4 + 1
				{
					t4[j] ^= power(power(nums[t])) ^ nums[t];
					break;
				}
				default:	// 0x9 = 8 + 1
					t4[j] ^= nums[t];
					break;
				}

			}
		}
		// 將數(shù)字轉換成字符串存儲
		ans[i] = int_ch2(t4[0]) + int_ch2(t4[1]) + int_ch2(t4[2]) + int_ch2(t4[3]);
	}

	return ans;
}

// 現(xiàn)在寫一個 aes 解密函數(shù)
void in_aes(string& text, string& key)
{
	// 先拓展密鑰
	auto keys = extend_key(key);

	// 初始下標
	int index = 40;

	// 對密文分組
	vector<string> texts = group_key(text);
	
	// 一開始先進行依次輪密鑰加
	for (int i = 0; i < 4; ++i)
	{
		texts[i] = string_xor(texts[i], keys[index + i]);
	}
	index -= 4;

	// 然后十次迭代
	for (int i = 0; i < 10; ++i)
	{
		// 先逆行移位
		texts = in_move_row(texts);

		// 然后是字節(jié)代換逆操作
		for (int j = 0; j < 4; ++j)
		{
			texts[j] = in_wordbyte_sub(texts[j]);
		}

		// 輪密鑰加
		for (int j = 0; j < 4; ++j)
		{
			texts[j] = string_xor(texts[j], keys[index + j]);
		}

		// 除了最后一輪,都要列混淆逆變換
		if (i < 9)
		{
			texts = in_col_confuse(texts);
		}
		index -= 4;
	}

	show(texts);
}

int main(int argc, char** argv)
{
	int op;
	cin >> op;			// 輸入標識符
	string text, key;
	cin >> text >> key;		// 輸入明文或者密文, 以及初始密鑰
	// 根據(jù)標識符,決定加密還是解密
	if (op == 0)
	{
		aes(text, key);
	}
	else
	{
		in_aes(text, key);
	}

	return 0;
}

優(yōu)化

對于這份代碼我深知其實存在不少可以優(yōu)化的地方。

比如:

  1. 字符串數(shù)組的存儲并不方便,需要頻繁切換,可以直接采用整數(shù)存儲,最終輸出時再用字符串輸出。
  2. 用于采用矩陣存儲,其實可以將輪常量只選取前兩位即可。
  3. 可以在迭代時,完成對密鑰的拓展,這樣可以節(jié)省空間,當然只是對于加密,解密還是要先拓展。

后話

學會了嗎?沒學會就碼起來,別老是當cv戰(zhàn)神。文章來源地址http://www.zghlxwxcb.cn/news/detail-442970.html

到了這里,關于AES-128算法實現(xiàn)(附C++源碼)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 【Python】AES 128加密和解密

    【Python】AES 128加密和解密

    AES加密標準又稱為高級加密標準Rijndael加密法,是美國國家標準技術研究所NIST旨在取代DES的21世紀的加密標準。AES的基本要求是,采用對稱分組密碼體制,密鑰長度可以為128、192或256位,分組長度128位,算法應易在各種硬件和軟件上實現(xiàn)。1998年NIST開始AES第一輪分析、測試和征

    2024年02月13日
    瀏覽(23)
  • Python 基于pycryptodome,實現(xiàn)對AES、DES、3DES、RSA等常用加密算法的使用,文末附各種加密的源碼示例

    (中文名:加密圓頂)pycryptodome是一個基于c實現(xiàn)的Python庫,它在2.x中支持2.7以上版本,或3.x中支持3.5以上版本的Python。 可以使用以下命令安裝它: 該庫支持以下特性 認證加密模式 Authenticated encryption modes (GCM, CCM, EAX, SIV, OCB) AES加密在英特爾上的加速 Accelerated AES on Intel platf

    2023年04月09日
    瀏覽(37)
  • AES-128-ECB php兼容高低版本

    2024年02月09日
    瀏覽(20)
  • php 調用python解密 AES-128-GCM

    因工作需要,要解密Java AES-128-GCM iv=16 模式的加密密文,找了php的很多方法,都無法解密成功,最后找了一個使用python3進行解密的方法,下面是解密方法: 主要是運用php的函數(shù)exec()執(zhí)行Linux命令調用python運行python文件,獲得返回結果。 注:此AES解密要用到python 3的 庫?Crypto

    2024年01月18日
    瀏覽(21)
  • 前端CryptoJS-AES加解密 對應php的AES-128-CBC加解密踩坑(java也相同加解密)

    ?前端部分注意看填充是pkcs7 有個前提,要看前端有沒有轉成hex格式,如果沒轉,php那邊就不需要調用特定函數(shù)轉hex格式的 后端php代碼

    2024年02月15日
    瀏覽(23)
  • ssh命令報錯no matching cipher found. Their offer: aes128-cbc,aes192-cbc,aes256-cbc,3des-cbc

    執(zhí)行 ssh user@host 報錯,信息如下: 協(xié)議不匹配 可以使用如下命令 ssh -c aes128-cbc,aes192-cbc,aes256-cbc,3des-cbc user@host 也可以修改 ~/.ssh/config文件 vi ~/.ssh/config 增加配置 Ciphers +aes128-cbc,aes192-cbc,aes256-cbc

    2024年02月13日
    瀏覽(21)
  • 20230721在WIN10下安裝openssl并解密AES-128加密的ts視頻切片

    20230721在WIN10下安裝openssl并解密AES-128加密的ts視頻切片

    20230721在WIN10下安裝openssl并解密AES-128加密的ts視頻切片 2023/7/21 22:58 1、前言: AES-128加密的ts視頻切片【第一個】,打開有時間限制的! https://app1ce7glfm1187.h5.xiaoeknow.com/v2/course/alive/l_64af6130e4b03e4b54da1681?type=2app_id=app1cE7gLFM1187pro_id=term_645c69388953e_Nhew9Aavailable=trueshare_user_id=u_5e591188

    2024年02月16日
    瀏覽(23)
  • AES算法基于FPGA的硬件實現(xiàn)(3)AES算法的Verilog實現(xiàn)(完結)

    AES算法基于FPGA的硬件實現(xiàn)(3)AES算法的Verilog實現(xiàn)(完結)

    本設計實現(xiàn)AES加密算法為ecb模式,填充模式未設置,同時支持AES-128/192/256三種密鑰長度。 代碼完全開源,開源鏈接在文章末尾。 下圖為GitHub倉庫中上傳的文件第一級結構,第一級為matlab和user,matlab中存儲的是在進行列混淆運算時查表所用的coe文件,這些文件用來初始化viv

    2024年01月18日
    瀏覽(22)
  • 小程序,h5,移動端處理md5加密接口,請求數(shù)據(jù)加密方式AES-128-ECB

    小程序,h5,移動端處理md5加密接口,請求數(shù)據(jù)加密方式AES-128-ECB

    1.AES-128-ECB 表示使用AES(Advanced Encryption Standard)算法,密鑰長度為128位,工作模式為ECB(Electronic Codebook)的一種對稱加密方式。 其中: AES是一種常用的對稱加密算法,被廣泛地應用于各種信息安全場景中。 128表示密鑰長度為128位(16字節(jié))。AES支持的密鑰長度還有192位和256位。 ECB代表電

    2024年03月28日
    瀏覽(24)
  • C++實現(xiàn)冒泡排序算法(含源碼)

    C++實現(xiàn)冒泡排序算法(含源碼) 冒泡排序是一種簡單的排序算法,它通過不斷交換相鄰的元素,將較大的元素逐步\\\"浮\\\"到待排序列的尾部,從而實現(xiàn)排序。下面是C++的冒泡排序實現(xiàn)代碼: 該函數(shù)接受一個整型數(shù)組和數(shù)組長度作為參數(shù),在每次遍歷中,它比較相鄰的兩個元素,將

    2024年02月07日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包