aes key长度_AES加密(1): 基本AES算法
簡(jiǎn)介
AES原本指的是一套標(biāo)準(zhǔn)FIPS 197,而AES算法一般指分組大小為128bits的Rijndeal算法,由比利時(shí)學(xué)者Joan Daemen和Vincent Rijmen提出。
AES與Rijndeal的區(qū)別
AES僅指分段為128位的Rijndeal算法,兩種算法對(duì)比如下:
(Nr表示循環(huán)輪數(shù),Nb表示分組大小,Nk表示密鑰長(zhǎng)度,Nb和Nk單位都是32bits)
加密
總體流程
圖片來(lái)自鏈接,這張圖是AES-128的流程,AES-192和AES-256除了加密輪數(shù)和密鑰長(zhǎng)度以外都是一樣的
AES加密的整個(gè)過(guò)程是在一個(gè)4×4的字節(jié)矩陣上運(yùn)作的,這個(gè)字節(jié)矩陣稱作state。這個(gè)字節(jié)矩陣是由當(dāng)前明文塊處理得到的,簡(jiǎn)而言之就是把當(dāng)前的16個(gè)字節(jié)按照4個(gè)字節(jié)一行排列成矩陣,比如說(shuō)
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
處理后得到的矩陣就是
0x00,0x01,0x02,0x03,
0x04,0x05,0x06,0x07,
0x08,0x09,0x0a,0x0b,
0x0c,0x0d,0x0e,0x0f
加密前要先進(jìn)行KeyExpansion,將原始的密鑰擴(kuò)展得到擴(kuò)展密鑰,原始密鑰同樣要做與上面一樣的變換得到矩陣才能進(jìn)行運(yùn)算
然后是開(kāi)始加密,按照上圖中順序調(diào)用如下四個(gè)輪函數(shù):
AddRoundKey:輪密鑰加運(yùn)算,將當(dāng)前的ByteSub:字節(jié)變換 (S盒變換)ShiftRows:行變換MixColumns:列變換
4個(gè)輪函數(shù)都是在伽羅瓦域$GF(256)$上進(jìn)行的。伽羅瓦域 (Galois Field) 是一個(gè)滿足特定規(guī)則的集合,其中元素可以進(jìn)行加減乘除,且運(yùn)算結(jié)果也都是這個(gè)集合的元素,具體細(xì)節(jié)可以。
接下來(lái)分析四個(gè)輪函數(shù)
輪密鑰加 / AddRoundKey
這個(gè)就是簡(jiǎn)單的把當(dāng)前狀態(tài) (state) 與擴(kuò)展密鑰進(jìn)行按位異或,代碼如下:
void aes::AddRoundKey(word *ExpandedKey, int i) {toBytes(ExpandedKey[Nb * i + 0], RoundKey + 0 * Nb);toBytes(ExpandedKey[Nb * i + 1], RoundKey + 1 * Nb);toBytes(ExpandedKey[Nb * i + 2], RoundKey + 2 * Nb);toBytes(ExpandedKey[Nb * i + 3], RoundKey + 3 * Nb);for (int k = 0; k < Nb * 4; ++k) {state[k] = state[k] ^ RoundKey[k];}
}
注意:AddRoundKey所異或的擴(kuò)展密鑰與當(dāng)前加密輪數(shù)有關(guān)。擴(kuò)展密鑰是一個(gè)word數(shù)組,每個(gè)word有32bit,也就是說(shuō)每個(gè)word能分解為4個(gè)byte,而異或輪密鑰的時(shí)候需要把當(dāng)前要異或的一組輪密鑰(共4個(gè)word)分解為16個(gè)byte再進(jìn)行異或。擴(kuò)展密鑰的長(zhǎng)度是Nb*(Nr+1),每次AddRoundKey需要使用當(dāng)前輪數(shù)乘上Nb開(kāi)始的4個(gè)word長(zhǎng)的輪密鑰。
字節(jié)變換 / ByteSub
這一步就是將state中每一個(gè)字節(jié)替換為S_box中的對(duì)應(yīng)字節(jié)。S_box是一個(gè)有256個(gè)元素的一維數(shù)組,直接查找當(dāng)前字節(jié)所對(duì)應(yīng)的新的字節(jié)并替換即可。
那肯定有人會(huì)問(wèn):S_box是怎么來(lái)的?
很顯然這個(gè)S_box不是隨隨便便來(lái)的一個(gè)數(shù)組。這是通過(guò)計(jì)算得來(lái)的,當(dāng)然我們直接把他看作一個(gè)常量數(shù)組即可。
S_box是怎么來(lái)的?
本段數(shù)學(xué)內(nèi)容較多,可以直接跳到下一條分割線繼續(xù)閱讀。
首先我們要知道什么是GF(256)域,具體可以參考我的這篇文章:
AI1379:GF(256)域?zhuanlan.zhihu.com
(接下來(lái)默認(rèn)你已經(jīng)明白GF(256)和它上面的運(yùn)算了)
首先我們求出當(dāng)前字節(jié)在GF(256)上的乘法逆元 (相當(dāng)于實(shí)數(shù)域上倒數(shù)的概念) ,如果當(dāng)前字節(jié)是0x00則不變。我們把得到的這個(gè)數(shù)設(shè)為 $x$ 并把它以多項(xiàng)式的形式表示成如下形式:
接著我們有一個(gè)8位二進(jìn)制數(shù) $y$ ,同樣以上面的方式表示,并且滿足:
這個(gè)y就是這個(gè)字節(jié)在S_box中所對(duì)應(yīng)的值。
注意這里順序是反的,高位在下低位在上,并且都是以2進(jìn)制形式表示的
附上S_box數(shù)組:
const byte S_Box[256] = {
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
};
行變換 / ShiftRow
這個(gè)就比較好理解了,就是把每行左環(huán)移,第一行不變,第二行環(huán)移1位,第三行環(huán)移2位,第三行環(huán)移3位,代碼如下:
void aes::ShiftRow() {for (int i = 1; i < Nb; ++i) {for (int j = 0; j < i; ++j) {byte tmp = state[i];state[i + 0 * 4] = state[i + (0 + 1) * 4];state[i + 1 * 4] = state[i + (1 + 1) * 4];state[i + 2 * 4] = state[i + (2 + 1) * 4];state[i + 3 * 4] = tmp;}}
}
列混合 / MixColumn
這是整個(gè)AES加密流程中最復(fù)雜的一步,同時(shí)要應(yīng)用到之前在S盒變換里提到過(guò)的GF(256)域,如果真的想要理解這一步的話建議先去仔細(xì)了解一下GF(256)再來(lái)繼續(xù)閱讀
我們定義一個(gè)多項(xiàng)式
,帶單引號(hào)的數(shù)表示16進(jìn)制數(shù)。
然后我們定義:
或者說(shuō)
得到了一個(gè)新的列。
但是實(shí)際上我們很少會(huì)直接用GF(256)上的乘法來(lái)計(jì)算這個(gè)。由于AES的整個(gè)加密和解密過(guò)程只需要用到256*6個(gè)GFMul的值,因此我們可以直接用查表的方式加速計(jì)算。
代碼:
void aes::MixColumn() {const byte y[16] = {0x02, 0x03, 0x01, 0x01,0x01, 0x02, 0x03, 0x01,0x01, 0x01, 0x02, 0x03,0x03, 0x01, 0x01, 0x02};byte arr[4];for (int i = 0; i < 4; ++i) {for (int k = 0; k < 4; ++k) {arr[k] = 0;for (int j = 0; j < 4; ++j) {arr[k] = arr[k] ^ GFMul(y[k * 4 + j], state[i * 4 + j]);}}for (int k = 0; k < 4; ++k) {state[i * 4 + k] = arr[k];}}
}
密鑰擴(kuò)展 / KeyExpansion
萬(wàn)事俱備,只欠東風(fēng)。4個(gè)輪函數(shù)已經(jīng)全部齊了,現(xiàn)在只差一步——密鑰擴(kuò)展。
擴(kuò)展密鑰是一個(gè)長(zhǎng)為Nb*(Nr+1)的word數(shù)組,一個(gè)word相當(dāng)于8個(gè)byte。對(duì)于AES-128和AES-192,代碼如下:
void aes128::KeyExpansion() {for (int i = 0; i < Nk; ++i) {w[i] = toWord(key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]);}for (int i = Nk; i < Nb * (Nr + 1); ++i) {auto temp = w[i - 1];if (i % Nk == 0) {temp = SubByte(RotByte(temp)) ^ Rcon[i / Nk];}w[i] = w[i - Nk] ^ temp;}
}
而對(duì)于AES-256則多了一步:
void aes256::KeyExpansion() {for (int i = 0; i < Nk; ++i) {w[i] = toWord(key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]);}for (int i = Nk; i < Nb * (Nr + 1); ++i) {auto temp = w[i - 1];if (i % Nk == 0) {temp = SubByte(RotByte(temp)) ^ Rcon[i / Nk];} else if (i % Nk == 4) {temp = SubByte(temp);}w[i] = w[i - Nk] ^ temp;}
}
其中出現(xiàn)了幾個(gè)東西:RotByte,SubByte和Rcon。
RotByte
RotByte函數(shù)是將這個(gè)word中的四個(gè)byte左環(huán)移一位,代碼如下:
word aes::RotByte(crypto::word in) {word res;byte arr[4];toBytes(in, arr);res = toWord(arr[1], arr[2], arr[3], arr[0]);return res;
}
這個(gè)比較好理解,就不多說(shuō)了。
SubByte
SubByte是對(duì)這個(gè)word里的每一個(gè)byte進(jìn)行S盒變換,代碼也很簡(jiǎn)單:
word aes::SubByte(crypto::word in) {word res;byte arr[4];toBytes(in, arr);res = toWord(S_Box[arr[0]], S_Box[arr[1]], S_Box[arr[2]], S_Box[arr[3]]);return res;
}
Rcon
這個(gè)就比較復(fù)雜了,仍然要用到$GF(256)$相關(guān)內(nèi)容(當(dāng)然我們也可以把它看作常數(shù)數(shù)組)
首先我們有一個(gè)數(shù)組RC,其中:
這里的所有運(yùn)算都是在GF(256)上進(jìn)行的。
而Rcon[i]=toWord(Rc[i],0x00,0x00,0x00)。
整個(gè)數(shù)組如下:
const word Rcon[16] = {0x00000000, 0x01000000, 0x02000000, 0x04000000,0x08000000, 0x10000000, 0x20000000, 0x40000000,0x80000000, 0x1b000000, 0x36000000, 0x6c000000,0xd8000000, 0xab000000, 0xed000000, 0x9a000000};
解密
解密過(guò)程與加密過(guò)程剛好相反。這里只放幾個(gè)關(guān)鍵數(shù)據(jù):
逆S盒
const byte Inv_S_Box[256] = {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
};
逆列變換
void aes::InvMixColumn() {const byte y[16] = {0x0e, 0x0b, 0x0d, 0x09,0x09, 0x0e, 0x0b, 0x0d,0x0d, 0x09, 0x0e, 0x0b,0x0b, 0x0d, 0x09, 0x0e};byte arr[4];for (int i = 0; i < Nb; ++i) {for (int k = 0; k < 4; ++k) {arr[k] = 0;for (int j = 0; j < 4; ++j) {arr[k] = arr[k] ^ GFMul(y[k * 4 + j], state[i * 4 + j]);}}for (int k = 0; k < 4; ++k) {state[i * 4 + k] = arr[k];}}
}
逆行變換
void aes::InvShiftRow() {for (int i = 1; i < Nb; i++) {for (int j = 0; j < Nb - i; ++j) {byte tmp = state[i];state[i + 0 * 4] = state[i + (0 + 1) * 4];state[i + 1 * 4] = state[i + (1 + 1) * 4];state[i + 2 * 4] = state[i + (2 + 1) * 4];state[i + 3 * 4] = tmp;}}
}
輪密鑰加和密鑰擴(kuò)展
加密和解密過(guò)程中輪密鑰加和密鑰擴(kuò)展是完全一樣的,不需要另外寫新的代碼。
完整的代碼
aes.h:
#include <cstdint>
#include <cstring>namespace crypto {typedef uint8_t byte;typedef uint32_t word;class aes {protected:static constexpr int Nb = 4;static constexpr byte S_Box[256] = {/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */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};static constexpr byte Inv_S_Box[256] = {/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */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};static constexpr byte Mul_01[256] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff};static constexpr byte Mul_02[256] = {0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25,0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45,0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85,0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5,0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5};static constexpr byte Mul_03[256] = {0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41,0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1,0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1,0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81,0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba,0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea,0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a,0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a,0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a};static constexpr byte Mul_09[256] = {0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc,0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01,0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91,0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a,0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa,0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b,0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b,0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0,0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30,0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed,0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d,0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6,0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46};static constexpr byte Mul_0b[256] = {0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12,0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2,0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f,0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f,0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4,0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54,0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e,0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e,0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5,0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55,0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68,0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8,0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13,0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3};static constexpr byte Mul_0d[256] = {0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0,0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20,0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26,0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6,0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d,0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d,0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91,0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41,0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a,0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa,0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc,0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c,0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47,0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97};static constexpr byte Mul_0e[256] = {0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81,0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61,0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7,0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17,0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c,0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc,0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b,0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb,0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0,0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20,0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6,0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56,0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d,0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d};static constexpr word Rcon[16] = {0x00000000, 0x01000000, 0x02000000, 0x04000000,0x08000000, 0x10000000, 0x20000000, 0x40000000,0x80000000, 0x1b000000, 0x36000000, 0x6c000000,0xd8000000, 0xab000000, 0xed000000, 0x9a000000};void ByteSub();void ShiftRow();void MixColumn();void InvByteSub();void InvShiftRow();void InvMixColumn();void AddRoundKey(word *ExpandedKey, int i);byte GFMul(byte a, byte b);word SubByte(word in);word RotByte(word in);word toWord(byte k1, byte k2, byte k3, byte k4);void toBytes(word in, byte res[4]);virtual void KeyExpansion() = 0;virtual void clear() = 0;public:byte plain[4 * Nb]{};byte cipher[4 * Nb]{};byte state[4 * Nb]{};byte RoundKey[16]{};virtual void Encrypt() = 0;virtual void Decrypt() = 0;virtual void init(byte in[16], byte in_key[16], bool type) = 0;};class aes128 : public aes {private:static constexpr int Nr = 10;static constexpr int Nk = 4;word w[Nb * (Nr + 1)];void KeyExpansion() override;void clear() override;public:void Encrypt() override;void Decrypt() override;void init(byte in[4 * Nb], byte in_key[4 * Nk], bool type) override;byte key[4 * Nk];};class aes192 : public aes {private:static constexpr int Nr = 12;static constexpr int Nk = 6;word w[Nb * (Nr + 1)];void KeyExpansion() override;void clear() override;public:void Encrypt() override;void Decrypt() override;void init(byte in[4 * Nb], byte in_key[4 * Nk], bool type) override;byte key[4 * Nk];};class aes256 : public aes {private:static constexpr int Nr = 14;static constexpr int Nk = 8;word w[Nb * (Nr + 1)];void KeyExpansion() override;void clear() override;public:void Encrypt() override;void Decrypt() override;void init(byte in[4 * Nb], byte in_key[4 * Nk], bool type) override;byte key[4 * Nk];};
}
aes.cpp:
#include "aes.h"namespace crypto {void aes128::clear() {memset(w, 0, sizeof(w));memset(state, 0, sizeof(state));}void aes128::init(crypto::byte *in, crypto::byte *in_key, bool type) {memset(key, 0, sizeof(key));memset(plain, 0, sizeof(plain));memset(cipher, 0, sizeof(cipher));clear();if (type) {for (int i = 0; i < 4 * Nb; ++i) {plain[i] = in[i];}} else {for (int i = 0; i < 4 * Nb; ++i) {cipher[i] = in[i];}}for (int i = 0; i < 4 * Nk; ++i) {key[i] = in_key[i];}}void aes192::clear() {memset(w, 0, sizeof(w));memset(state, 0, sizeof(state));}void aes192::init(crypto::byte *in, crypto::byte *in_key, bool type) {memset(key, 0, sizeof(key));memset(plain, 0, sizeof(plain));memset(cipher, 0, sizeof(cipher));clear();if (type) {for (int i = 0; i < 4 * Nb; ++i) {plain[i] = in[i];}} else {for (int i = 0; i < 4 * Nb; ++i) {cipher[i] = in[i];}}for (int i = 0; i < 4 * Nk; ++i) {key[i] = in_key[i];}}void aes256::clear() {memset(w, 0, sizeof(w));memset(state, 0, sizeof(state));}void aes256::init(crypto::byte *in, crypto::byte *in_key, bool type) {memset(key, 0, sizeof(key));memset(plain, 0, sizeof(plain));memset(cipher, 0, sizeof(cipher));clear();if (type) {for (int i = 0; i < 4 * Nb; ++i) {plain[i] = in[i];}} else {for (int i = 0; i < 4 * Nb; ++i) {cipher[i] = in[i];}}for (int i = 0; i < 4 * Nk; ++i) {key[i] = in_key[i];}}word aes::toWord(crypto::byte k1, crypto::byte k2, crypto::byte k3, crypto::byte k4) {word res;res = (k1 << 24) | (k2 << 16) | (k3 << 8) | (k4);return res;}void aes::toBytes(crypto::word in, crypto::byte *res) {word tmp = in;for (int i = 3; i >= 0; --i) {res[i] = tmp % 256;tmp /= 256;}}byte aes::GFMul(crypto::byte a, crypto::byte b) {switch (a) {case 0x01:return Mul_01[b];case 0x02:return Mul_02[b];case 0x03:return Mul_03[b];case 0x09:return Mul_09[b];case 0x0b:return Mul_0b[b];case 0x0d:return Mul_0d[b];case 0x0e:return Mul_0e[b];}}void aes::ByteSub() {for (auto &i:state) {i = S_Box[i];}}void aes::ShiftRow() {for (int i = 1; i < Nb; ++i) {for (int j = 0; j < i; ++j) {byte tmp = state[i];state[i + 0 * 4] = state[i + (0 + 1) * 4];state[i + 1 * 4] = state[i + (1 + 1) * 4];state[i + 2 * 4] = state[i + (2 + 1) * 4];state[i + 3 * 4] = tmp;}}}void aes::MixColumn() {const byte y[16] = {0x02, 0x03, 0x01, 0x01,0x01, 0x02, 0x03, 0x01,0x01, 0x01, 0x02, 0x03,0x03, 0x01, 0x01, 0x02};byte arr[4];for (int i = 0; i < 4; ++i) {for (int k = 0; k < 4; ++k) {arr[k] = 0;for (int j = 0; j < 4; ++j) {arr[k] = arr[k] ^ GFMul(y[k * 4 + j], state[i * 4 + j]);}}for (int k = 0; k < 4; ++k) {state[i * 4 + k] = arr[k];}}}void aes::AddRoundKey(word *ExpandedKey, int i) {toBytes(ExpandedKey[Nb * i + 0], RoundKey + 0 * Nb);toBytes(ExpandedKey[Nb * i + 1], RoundKey + 1 * Nb);toBytes(ExpandedKey[Nb * i + 2], RoundKey + 2 * Nb);toBytes(ExpandedKey[Nb * i + 3], RoundKey + 3 * Nb);for (int k = 0; k < Nb * 4; ++k) {state[k] = state[k] ^ RoundKey[k];}}void aes::InvByteSub() {for (auto &i:state) {i = Inv_S_Box[i];}}void aes::InvShiftRow() {for (int i = 1; i < Nb; i++) {for (int j = 0; j < Nb - i; ++j) {byte tmp = state[i];state[i + 0 * 4] = state[i + (0 + 1) * 4];state[i + 1 * 4] = state[i + (1 + 1) * 4];state[i + 2 * 4] = state[i + (2 + 1) * 4];state[i + 3 * 4] = tmp;}}}void aes::InvMixColumn() {const byte y[16] = {0x0e, 0x0b, 0x0d, 0x09,0x09, 0x0e, 0x0b, 0x0d,0x0d, 0x09, 0x0e, 0x0b,0x0b, 0x0d, 0x09, 0x0e};byte arr[4];for (int i = 0; i < Nb; ++i) {for (int k = 0; k < 4; ++k) {arr[k] = 0;for (int j = 0; j < 4; ++j) {arr[k] = arr[k] ^ GFMul(y[k * 4 + j], state[i * 4 + j]);}}for (int k = 0; k < 4; ++k) {state[i * 4 + k] = arr[k];}}}word aes::SubByte(crypto::word in) {word res;byte arr[4];toBytes(in, arr);res = toWord(S_Box[arr[0]], S_Box[arr[1]], S_Box[arr[2]], S_Box[arr[3]]);return res;}word aes::RotByte(crypto::word in) {word res;byte arr[4];toBytes(in, arr);res = toWord(arr[1], arr[2], arr[3], arr[0]);return res;}void aes128::KeyExpansion() {for (int i = 0; i < Nk; ++i) {w[i] = toWord(key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]);}for (int i = Nk; i < Nb * (Nr + 1); ++i) {auto temp = w[i - 1];if (i % Nk == 0) {temp = SubByte(RotByte(temp)) ^ Rcon[i / Nk];}w[i] = w[i - Nk] ^ temp;}}void aes128::Encrypt() {clear();for (int i = 0; i < 4 * Nb; ++i) {state[i] = plain[i];}KeyExpansion();for (int i = 0; i <= Nr; ++i) {if (i > 0) {ByteSub();ShiftRow();if (i < Nr) {MixColumn();}}AddRoundKey(w, i);}for (int i = 0; i < 4 * Nb; ++i) {cipher[i] = state[i];}}void aes128::Decrypt() {clear();for (int i = 0; i < 4 * Nb; ++i) {state[i] = cipher[i];}KeyExpansion();for (int i = Nr; i >= 0; --i) {AddRoundKey(w, i);if (i > 0) {if (i < Nr) {InvMixColumn();}InvShiftRow();InvByteSub();}}for (int i = 0; i < 4 * Nb; ++i) {plain[i] = state[i];}}void aes192::KeyExpansion() {for (int i = 0; i < Nk; ++i) {w[i] = toWord(key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]);}for (int i = Nk; i < Nb * (Nr + 1); ++i) {auto temp = w[i - 1];if (i % Nk == 0) {temp = SubByte(RotByte(temp)) ^ Rcon[i / Nk];}w[i] = w[i - Nk] ^ temp;}}void aes192::Encrypt() {clear();for (int i = 0; i < 4 * Nb; ++i) {state[i] = plain[i];}KeyExpansion();for (int i = 0; i <= Nr; ++i) {if (i > 0) {ByteSub();ShiftRow();if (i < Nr) {MixColumn();}}AddRoundKey(w, i);}for (int i = 0; i < 4 * Nb; ++i) {cipher[i] = state[i];}}void aes192::Decrypt() {clear();for (int i = 0; i < 4 * Nb; ++i) {state[i] = cipher[i];}KeyExpansion();for (int i = Nr; i >= 0; --i) {AddRoundKey(w, i);if (i > 0) {if (i < Nr) {InvMixColumn();}InvShiftRow();InvByteSub();}}for (int i = 0; i < 4 * Nb; ++i) {plain[i] = state[i];}}void aes256::KeyExpansion() {for (int i = 0; i < Nk; ++i) {w[i] = toWord(key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]);}for (int i = Nk; i < Nb * (Nr + 1); ++i) {auto temp = w[i - 1];if (i % Nk == 0) {temp = SubByte(RotByte(temp)) ^ Rcon[i / Nk];} else if (i % Nk == 4) {temp = SubByte(temp);}w[i] = w[i - Nk] ^ temp;}}void aes256::Encrypt() {clear();for (int i = 0; i < 4 * Nb; ++i) {state[i] = plain[i];}KeyExpansion();for (int i = 0; i <= Nr; ++i) {if (i > 0) {ByteSub();ShiftRow();if (i < Nr) {MixColumn();}}AddRoundKey(w, i);}for (int i = 0; i < 4 * Nb; ++i) {cipher[i] = state[i];}}void aes256::Decrypt() {clear();for (int i = 0; i < 4 * Nb; ++i) {state[i] = cipher[i];}KeyExpansion();for (int i = Nr; i >= 0; --i) {AddRoundKey(w, i);if (i > 0) {if (i < Nr) {InvMixColumn();}InvShiftRow();InvByteSub();}}for (int i = 0; i < 4 * Nb; ++i) {plain[i] = state[i];}}
}
test.cpp
#include <iostream>
#include <cstdio>
#include <cstddef>
#include "aes.h"int main(int argc, char **argv) {crypto::aes256 test;crypto::byte key[] = {0x00, 0x01, 0x02, 0x03,0x04, 0x05, 0x06, 0x07,0x08, 0x09, 0x0a, 0x0b,0x0c, 0x0d, 0x0e, 0x0f,0x10, 0x11, 0x12, 0x13,0x14, 0x15, 0x16, 0x17,0x18, 0x19, 0x1a, 0x1b,0x1c, 0x1d, 0x1e, 0x1f};crypto::byte plain[16] = {0x00, 0x11, 0x22, 0x33,0x44, 0x55, 0x66, 0x77,0x88, 0x99, 0xaa, 0xbb,0xcc, 0xdd, 0xee, 0xff};test.init(plain, key, true);printf("Key:n");for (auto &i:test.key) {printf("%02x ", i);}printf("n");printf("Plain Text:n");for (auto &i:test.plain) {printf("%02x ", i);}printf("n");test.Encrypt();printf("Cipher Text:n");for (auto &i:test.cipher) {printf("%02x ", i);}printf("n");test.Decrypt();printf("Decrypt Plain Text:n");for (auto &i:test.plain) {printf("%02x ", i);}printf("n");return 0;
}
編譯指令:gcc -o test.exe test.cpp aes.cpp
輸出:
Key:
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
Plain Text:
00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff
Cipher Text:
8e a2 b7 ca 51 67 45 bf ea fc 49 90 4b 49 60 89
Decrypt Plain Text:
00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff
參考資料:
matt-wu: AES
The Rijndeal Block Cipher
文章首發(fā)于:
http://www.listener1379.top/Algorithm/Encryption/aes-encryption/?www.listener1379.top
總結(jié)
以上是生活随笔為你收集整理的aes key长度_AES加密(1): 基本AES算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: NC107617 poj3020 Ant
- 下一篇: 第1节 连通性强连通、割点和桥(一)