欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
AES對稱(chēng)加密算法原理
AES對稱(chēng)加密算法原理
2011-12-08 15:59:23     我來(lái)說(shuō)兩句      
收藏   
我要投稿

加密它:用新的高級加密標準(AES)保持你的數據安全


原著(zhù):James McCaffrey 

翻譯:小刀人
 

 

原文出處:MSDN Magazine November 2003 (Encrypt It)

本文的代碼下載:msdnmag200311AES.exe (143KB)

本文假設你熟悉 C# 和 位(bit)操作。

 摘要 

  AES(The Advanced Encryption Standard)是美國國家標準與技術(shù)研究所用于加密電子數據的規范。它被預期能成為人們公認的加密包括金融、電信和政府數字信息的方法。本文展示了AES的概貌并解析了它使用的算法。包括一個(gè)完整的C#實(shí)現和加密.NET數據的舉例。在讀完本文后你將能用AES加密、測試 基于A(yíng)ES的軟件并能在你的系統中使用AES加密。
 


  美國國家標準與技術(shù)研究所(NIST)在2002年5月26日建立了新的高級數據加密標準(AES)規范。本文中我將提供一個(gè)用C#編寫(xiě)的的能運行的 AES 實(shí)現,并詳細解釋到底什么是 AES 以及編碼是如何工作的。我將向您展示如何用 AES 加密數據并擴展本文給出的代碼來(lái)開(kāi)發(fā)一個(gè)商業(yè)級質(zhì)量的 AES 類(lèi)。我 還將解釋怎樣把 AES 結合到你的軟件系統中去和為什么要這么做,以及如何測試基于 AES 的軟件。
  注意本文提供的代碼和基于本文的任何其它的實(shí)現都在聯(lián)邦加密模塊出口控制的適用范圍之內(詳情請參看 Commercial Encryption Export Controls )。
  AES 是一個(gè)新的可以用于保護電子數據的加密算法。明確地說(shuō),AES 是一個(gè)迭代的、對稱(chēng)密鑰分組的密碼,它可以使用128、192 和 256 位密鑰,并且用 128 位(16字節)分組加密和解密數據。與公共密鑰密碼使用密鑰對不同,對稱(chēng)密鑰密碼使用相同的密鑰加密和解密數據。通過(guò)分組密碼返回的加密數據 的位數與輸入數據相同。迭代加密使用一個(gè)循環(huán)結構,在該循環(huán)中重復置換(permutations )和替換(substitutions)輸入數據。Figure 1 顯示了 AES 用192位密鑰對一個(gè)16位字節數據塊進(jìn)行加密和解密的情形。


Figure 1 部分數據

 AES算法概述

  AES 算法是基于置換和代替的。置換是數據的重新排列,而代替是用一個(gè)單元數據替換另一個(gè)。AES 使用了幾種不同的技術(shù)來(lái)實(shí)現置換和替換。為了闡明這些技術(shù),讓我們用 Figure 1 所示的數據討論一個(gè)具體的 AES 加密例子。下面是你要加密的128位值以及它們對應的索引數組:

00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

192位密鑰的值是:

00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 0 1 2 3 4 5 6 7 8 9 10 1112 13 14 15 16 17 18 19 20 21 22 23


Figure 2 S-盒( Sbox )

當 AES 的構造函數(constructor)被調用時(shí),用于加密方法的兩個(gè)表被初始化。第一個(gè)表是代替盒稱(chēng)為S-盒。它是一個(gè)16×16的矩陣。S-盒的前五行和前五列如 Figure 2 所示。在幕后,加密例程獲取該密鑰數組并用它來(lái)生成一個(gè)名為w[]的密鑰調度表,Figure 3 所示。 


Figure 3 密鑰調度表(Key Sched)

w[] 最初的 Nk (6) 行被作為種子,用原始密鑰值(0x00 到0x17)。剩余行從種子密鑰來(lái)產(chǎn)生。變量 Nk 代表以 32 位字為單位的種子密鑰長(cháng)度。稍后我分析 AES 實(shí)現時(shí)你將清楚地看到 w[] 是怎樣產(chǎn)生的。 關(guān)鍵是這里現在有許多密鑰使用而不只是一個(gè)。這些新的密鑰被稱(chēng)為輪密鑰(round keys)以將它們與原始種子密鑰區別開(kāi)來(lái)。


Figure 4 State (態(tài))數組

  AES 加密例程開(kāi)始是拷貝 16 字節的輸入數組到一個(gè)名為  State (態(tài))的 4×4 字節矩陣中。(參見(jiàn) Figure 4)。AES 加密算法 取名為 Cipher,它操作 State[],其過(guò)程描述的偽代碼參見(jiàn) Figure 5 。
  在規范中,加密算法實(shí)現的一個(gè)預備的處理步驟被稱(chēng)為 AddRoundKey(輪密鑰加)。AddRoundKey 用密鑰調度表中的前四行對 State 矩陣實(shí)行一個(gè)字節一個(gè)字節的異或(XOR)操作,并用輪密鑰表 w[c,r] 異或 輸入 State[r,c]。
  舉個(gè)例子,如果 State 矩陣的第一行保存的字節是{ 00, 44, 88, cc },第一列密鑰調度表是{ 00, 04, 08, 0c },那么新的 State[0,2] 值是用 w[2,0]( 0x08 或 0x80 )異或 State[0,2](0x88)的結果:

1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 XOR 1 0 0 0 0 0 0 0

AES 算法的主循環(huán)對 State 矩陣執行四個(gè)不同的操作,在規范中被稱(chēng)為 SubBytes(字節替換)、ShiftRows(行位移變換)、MixColumns(列混合變換) 和 AddRoundKey。除了每次循環(huán) AddRoundKey 都被調用并使用密鑰調度表的下面四行外,AddRoundKey 與預備處理步驟中的 AddRoundKey 相同。SubBytes 例程是一個(gè)代替操作,它將 State 矩陣中的每個(gè)字節替換成一個(gè)由 Sbox 決定的新字節。比如,如果 State[0,1]的值是 0x40 如果你想找到它的代替者,你取 State[0,1] 的值 (0x40) 并讓 x 等于左邊的數字(4)并讓 y 等于右邊的數字(0)。然后你用 x 和 y 作為索引 進(jìn)到 Sbox 表中尋找代替值,如 Figure 2 所示。
  ShiftRows 是一個(gè)置換操作,它將 State 矩陣中的字節向左旋轉。Figure 6 示范了 ShiftRows 如何操作 State[]。State 的第0行被向左旋轉0個(gè)位置,State 的第1行被向左旋轉1個(gè)位置,State 的第2行被向左旋轉2個(gè)位置,而 State 的第3行被向左旋轉3個(gè) 位置。


Figure 6 對 State 進(jìn)行 ShiftRows 操作

MixColumns 是一個(gè)代替操作,它是理解 AES 算法時(shí)最具技巧(或者說(shuō)是最需要動(dòng)腦筋的部分)的部分。它用 State 字節列的值進(jìn)行數學(xué)域加和域乘的結果代替每個(gè)字節。我將在下一節中 詳細解釋專(zhuān)門(mén)的域加和域乘細節。
  假設 State[0,1] 的值是0x09,并且列1上的其它值分別為 0x60,0xe1 和 0x04,那么State[0,1]的新值計算如下:

State[0,1] = (State[0,1] * 0x01) + (State[1,1] * 0x02) +(State[2,1] * 0x03) +(State[3,1] * 0x01) = (0x09 * 0x01) + (0x60 * 0x02) + (0xe1 * 0x03) +(0x04 * 0x01) = 0x57

此處加法和乘法是專(zhuān)門(mén)的數學(xué)域操作,而不是平常整數的加法和乘法。
  SubBytes、ShiftRows、MixColumns 和 AddRoundKey 四個(gè)操作在一個(gè)執行 Nr 次的循環(huán)里被調用,Nr 為給定密鑰大小的輪數減 1。加密算法使用的輪數要么是10,12,要么是14,這依賴(lài)于種子密鑰長(cháng)度是128位、192 位還是 256 位。在這個(gè)例子中,因為 Nr 等于12, 則這四個(gè)操作被調用11次。該迭代完成后,在拷貝 State 矩陣到輸出參數前,加密算法調用 SubBytes、ShiftRows 和 AddRoundKey 后結束。
  大致說(shuō)來(lái),AES 加密算法的核心有四個(gè)操作。AddRoundKey 使用從種子密鑰值中生成的輪密鑰代替 4 組字節。SubBytes 替換用一個(gè)代替表 替換單個(gè)字節。ShiftRows 通過(guò)旋轉 4字節行 的 4 組字節進(jìn)行序列置換。MixColumns 用域加和域乘的組合來(lái)替換字節。

 有限域GF(28)的加法和乘法

  正如你所看到的,AES 加密算法使用相當簡(jiǎn)單明了的技術(shù)來(lái)代替和置換,除 MixColumns 例程以外。MixColumns 使用特殊的加法和乘法。AES 所用的加法和乘法是基于數學(xué)(譯者注:近世代數)的域論。尤其是 AES 基于有限域GF(28)。
  GF(28)由一組從 0x00 到 0xff 的256個(gè)值組成,加上加法和乘法,因此是(28)。GF代表伽羅瓦域,以發(fā)明這一理論的數學(xué)家的名字命名。GF(28) 的一個(gè)特性是一個(gè)加法或乘法的操作的結果必須是在{0x00 ... 0xff}這組數中。雖然域論是相當深奧的,但GF(28)加法的最終結果卻很簡(jiǎn)單。GF(28) 加法就是異或(XOR)操作。
  然而,GF(28)的乘法有點(diǎn)繁難。正如你稍后將在 C# 實(shí)現中所看到的,AES的加密和解密例程需要知道怎樣只用七個(gè)常量 0x01、0x02、0x03、0x09、0x0b、0x0d 和 0x0e 來(lái)相乘。所以我不全面介紹GF(28)的乘法,而只是針對這七種特殊情況進(jìn)行說(shuō)明。
  在GF(28)中用0x01的乘法是特殊的;它相當于普通算術(shù)中用1做乘法并且結果也同樣—任何值乘0x01等于其自身。
  現在讓我們看看用0x02做乘法。和加法的情況相同,理論是深奧的,但最終結果十分簡(jiǎn)單。只要被乘的值小于0x80,這時(shí)乘法的結果就是該值左移1比特位。如果被乘的值大于或等于0x80,這時(shí)乘法的結果就是左移1比特位再用值0x1b異或。它防止了“域溢出”并保持乘法的乘積在范圍以?xún)取?br> 一旦你在GF(28)中用0x02建立了加法和乘法,你就可以用任何常量去定義乘法。用0x03做乘法時(shí),你可以將 0x03 分解為2的冪之和。為了用 0x03 乘以任意字節b, 因為 0x03 = 0x02 + 0x01,因此: 

b * 0x03 = b * (0x02 + 0x01) = (b * 0x02) + (b * 0x01)

這是可以行得通的,因為你知道如何用 0x02 和 0x01 相乘和相加,同哩,用0x0d去乘以任意字節b可以這樣做:

b * 0x0d = b * (0x08 + 0x04 + 0x01) = (b * 0x08) + (b * 0x04) + (b * 0x01) = (b * 0x02 * 0x02 * 0x02) + (b * 0x02 * 0x02) + (b * 0x01)

在加解密算法中,AES MixColumns 例程的其它乘法遵循大體相同的模式,如下所示:

b * 0x09 = b * (0x08 + 0x01) = (b * 0x02 * 0x02 * 0x02) + (b * 0x01) b * 0x0b = b * (0x08 + 0x02 + 0x01) = (b * 0x02 * 0x02 * 0x02) + (b * 0x02) + (b * 0x01) b * 0x0e = b * (0x08 + 0x04 + 0x02) = (b * 0x02 * 0x02 * 0x02) + (b * 0x02 * 0x02) + (b * 0x02)

  總之,在GF(28)中,加法是異或操作。其乘法將分解成加法和用0x02做的乘法,而用0x02做的乘法是一個(gè)有條件的左移1比特位。AES規范中包括大量 有關(guān)GF(28)操作的附加信息。

 密鑰擴展

  AES加密和解密算法使用了一個(gè)由種子密鑰字節數組生成的密鑰調度表。AES規范中稱(chēng)之為密鑰擴展例程(KeyExpansion)。從本質(zhì)上講,從一個(gè)原始密鑰中生成多重密鑰以代替使用單個(gè)密鑰大大增加了比特位的擴散。雖然不是無(wú)法抵御的困難,但理解 KeyExpansion 仍是 AES 算法中的一個(gè)難點(diǎn)。KeyExpansion 例程高級偽代碼如下所示:

KeyExpansion(byte[] key, byte[][4] w) { copy the seed key into the first rows of w for each remaining row of w { use two of the previous rows to create a new row } }

“用前面兩行來(lái)產(chǎn)生一個(gè)新行”(“use two of the previous rows to create a new row”)的例程用到了兩個(gè)子 例程,RotWord 和 SubWord 以及一個(gè)名為“Rcon”的常數表(作為“輪常數”)。讓我們先來(lái)逐個(gè)看一下這三東西,然后再回到整個(gè) KeyExpansion 的討論中來(lái)。
  RotWord 例程很簡(jiǎn)單。它接受一個(gè)4個(gè)字節的數組并將它們向左旋轉一個(gè)位置。因為輪調度表 w[] 有四列,RotWord 將 w[]的1行左旋。注意 KeyExpansion 使用的這個(gè) RotWord 函數與加密算法使用的  ShiftRows (行位移變換)例程非常相似,只是它 處理的是單行密鑰調度 w[],而不是整個(gè)加密狀態(tài)表 State[]。
  SubWord 例程使用替換表 Sbox 對一給定的一行密鑰調度表 w[] 進(jìn)行逐字節替換。KeyExpansion 操作中的替換實(shí)際上就像在加密算法中的 替換一樣。被代替的輸入字節被分成 (x,y) 對,它被當作進(jìn)入替換表 Sbox 的索引。舉例來(lái)說(shuō),0x27的代替結果是 x=2 和 y=7,并且 Sbox[2,7] 返回 0xcc。
  KeyExpansion 例程使用一個(gè)被稱(chēng)為輪常數表的數組 Rcon[]。這些常數都是4個(gè)字節,每一個(gè)與密鑰調度表的某一行相匹配。AES 的 KeyExpansion 例程需要11個(gè)輪常數。你可以在 Figure 7 中看到這些常數清單。
  每個(gè)輪常數的最左邊的字節是GF(28)域中2的冪次方。它的另一個(gè)表示方法是其每個(gè)值是前一個(gè)值乘上0x02,正如前一部分討論 GF(28) 乘法 時(shí)所描述的那樣。注意 0x80 × 0x02 = 0x1b 是 0x80 左移1個(gè)比特位后緊接著(zhù)與 0x1b 進(jìn)行異或,如前所述。
  現在讓我們更進(jìn)一步看看 KeyExpansion 內幕中的循環(huán)。這里所用的偽碼比以前更為詳細,這個(gè)循環(huán)是:

for (row = Nk; row < (4 * Nr+1); ++row) { temp = w[row-1] if (row % Nk == 0) temp = SubWord(RotWord(temp)) xor Rcon[row/Nk] else if (Nk == 8 and row % Nk == 4) temp = SubWord(temp) w[row] = w[row-Nk] xor temp }

先不要去看if子句,你將看到密鑰調度表 w[] 的每一行都是前面一行與行 Nk 異或的結果(4, 6, 或 8 取決于密鑰的長(cháng)度)。if條件的第一部分用 SubWord、RotWord 以及與輪常數的異或修改密鑰調度表的每個(gè)第4、第6或第8行,取決于是否密鑰的長(cháng)度是128、192或256位。這個(gè)條件的第二部分將修改行 12、20 和 28 等等——對于256位密鑰而言——每 一個(gè)第8行都將添加密鑰調度額外的可變性。
  讓我們用本文開(kāi)頭所舉的例子來(lái)考察 KeyExpansion 是如何開(kāi)始的。種子密鑰是192-bit / 6-word 值:

00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17

  密鑰調度字節表 w[] 的維數是 4 列并且 Nb × (Nr + 1) 等于 4 × (12 + 1),或 52 行。KeyExpansion 將種子密鑰的值拷貝到密鑰調度字節表 w[] 的第一行。因為我的種子密鑰是 192 位(24字節),并且 w[] 表總是 4 列,在這種情況下KeyExapansion 將種子密鑰拷貝到 w[] 的前面 6 行?,F在讓我們看看 KeyExapansion 例程是如何填充密鑰調度表其余部分的。在我的例子里,第一個(gè)被計算的行是第 6 行 ,因為第0-5行已被種子密鑰的值填上了:

temp = w[row-1] = 14 15 16 17

條件 (row % Nk == 0)為真,因此首先 RotWord 子程序被應用:

temp = 15 16 17 14

這時(shí) SubWord 被應用:

temp = 59 47 f0 fa

用 Rcon[row / Nk] = Rcon[6 / 6] = 01 00 00 00 進(jìn)行異或:

temp = 58 47 f0 fa

這時(shí)用 w[row-Nk] = w[6-6] = 00 01 02 03 異或,產(chǎn)生了下面結果:

w[6] = 58 46 f2 f9

密鑰調度表 w[] 中其余所有行來(lái)重復這個(gè)過(guò)程本身。
  總而言之,AES 加密和解密的一個(gè)重要部分就是從最初的種子密鑰中生成多重輪密鑰。這個(gè) KeyExapansion 算法生成一個(gè)密鑰調度并 以某種方式進(jìn)行替代和置換,在這種方式中,加密和解密算法極其相似。

 用 C# 編寫(xiě) AES 類(lèi)構造函數

  現在我已研究了構成 AES 加密算法的各個(gè)成分,我將用 C# 來(lái)實(shí)現它。官方的 AES 算法規范包含在聯(lián)邦信息處理標準出版物197 (Federal Information Processing Standards Publication 197)中。我決定盡可能貼切地以它作為我的實(shí)現的基礎,但是我很快發(fā)現這個(gè)規范更是一個(gè)理論文獻而非一個(gè)實(shí)現的向導。為了將這個(gè)官方規范作為資源來(lái)使用,我使用 的變量名與標準出版物中所用的相同。(即便它們是那么晦澀,如“Nr”和“W”)。

我的設計使用9個(gè)數據成員和一個(gè)枚舉類(lèi)型,如下所示:

public enum KeySize { Bits128, Bits192, Bits256 }; private int Nb; private int Nk; private int Nr; private byte[] key; private byte[,] Sbox; private byte[,] iSbox; private byte[,] w; private byte[,] Rcon; private byte[,] State;

因為密鑰長(cháng)度只能是128位、192位或256位比特,它是非常適于用枚舉類(lèi)型:

public enum KeySize { Bits128, Bits192, Bits256 };

  該規范文檔一般用字節作為基本儲存單元而不是用4字節的字作為兩個(gè)重要數據成員的長(cháng)度。這兩個(gè)成員 Nb 和 Nk 代表 以字為單位的塊長(cháng)以及以字為單位的密鑰長(cháng)度。Nr代表輪數。塊長(cháng)度總是16字節(或這說(shuō)是 128 位,即為 AES 的 4個(gè)字),因此它可以被聲明為一個(gè)常量。密鑰長(cháng)度 依照枚舉參數 KeySize 的值被賦值為 4、6 或 8。AES 算法強調通過(guò)大量輪數來(lái)增加加密數據的復雜性。輪數是10、12或14中的任意一個(gè)并且是基于密碼分析學(xué)理論的。它直接取決于密鑰長(cháng)度。
  當設計一個(gè)類(lèi)接口時(shí),我喜歡向后來(lái)做。我設想從應用程序中調用構造函數和方法。使用這個(gè)辦法,我決定象下面這樣來(lái)實(shí)例化一個(gè) AES 對象:

Aes a = new Aes(the key size, the seed key)

我調用的加密和解密例程如下:

a.Cipher(plainText, cipherText); a.InvCipher(cipherText, decipheredText);

我選擇少許笨拙的方法來(lái)命名 Cipher 和 InvCipher,因為它們是用在 AES 規范文檔中的。這里是 AES 類(lèi)構造函數的代碼為:

public Aes(KeySize keySize, byte[] keyBytes) { SetNbNkNr(keySize); this.key = new byte[this.Nk * 4]; keyBytes.CopyTo(this.key, 0); BuildSbox(); BuildInvSbox(); BuildRcon(); KeyExpansion(); }

  該構造函數首先調用一個(gè)輔助方法 SetNbNkNr 給 Nb、Nk 和 Nr 賦值,如 Figure 8 所示。如果考慮到效率,你可能將這些代碼直接放入構造函數 以避免方法調用的開(kāi)銷(xiāo)。
  接下來(lái),你必須將傳入構造函數的字節拷貝到類(lèi)域變量中。密鑰用其它的類(lèi)域聲明,并且用如下方法獲得它的值:

this.key = new byte[this.Nk * 4]; keyBytes.CopyTo(this.key, 0);

  我決定在構造函數中調用私有輔助方法 BuildSbox 和 BuildInvSbox 來(lái)初始化替換表 Sbox[] 和 iSbox[] ?,F在密鑰擴展例程 、Cipher 方法和 InvCipher 方法各自都需要 Sbox[] 和 iSbox[],因此我本來(lái)可以在 Cipher 和 InvCipher 兩個(gè)方法中初始化 Sbox[] 并調用 KeyExpansion 方法,但是將它們放入構造函數會(huì )代碼結構更加清晰。在 Figure 9 中 sBox[] 被填充。填充 iSbox[] 代碼 類(lèi)似。為了可讀性對代碼進(jìn)行了結構化處理。正如后面你將看到的,還有另外一個(gè)可供選擇的令人驚訝的方法為 Sbox 和 iSbox 表提供值。
  在構造函數中聲明密鑰調度表 w[]、輪常數表 Rcon[] 和狀態(tài)矩陣 State[],并用私有輔助方法來(lái)給 Rcon[] 和 w[] 賦值在我看來(lái)似乎是組織它們的最好辦法,但那主要還是個(gè)風(fēng)格問(wèn)題。置換輪常數表 Rcon 的賦值代碼參見(jiàn)Figure 7。
回想一下,GF(28)中,Rcon[] 每一行左邊的字節都 2 的冪,因此這個(gè)表可用下面的方法建立:

newVal = prevVal * 0x02;

  AES 構造函數在建立完密鑰調度表 w[] 后結束,而 w[] 是在 KeyExpansion 方法中完成的(參見(jiàn) Figure 10)。 其代碼相當簡(jiǎn)單。規范文檔使用一個(gè)假設的 4-字節的字數據類(lèi)型。因為 C# 沒(méi)有那樣的類(lèi)型,但可以用一個(gè)4個(gè)字節的數組來(lái)模擬。在用 new 操作符為密鑰調度 表 w[] 分配空間后,w[] 最初的 Nk(4, 6, 或 8) 行從被傳遞到構造函數的種子密鑰 key[] 數組中獲值。

this.w[row,0] = this.key[4*row]; this.w[row,1] = this.key[4*row+1]; this.w[row,2] = this.key[4*row+2]; this.w[row,3] = this.key[4*row+3];

  兩個(gè)字節相互的異或操作在這個(gè)代碼中頻頻發(fā)生。它需要一些從 byte 到 int 的強制類(lèi)型轉換并轉回到 byte,因為異或操作“^”是不能定義在 C# 的 byte 類(lèi)型上,例如:

temp[0] = (byte)( (int)temp[0] ^ (int)this.Rcon[row/Nk,0] );

用來(lái)替代:

temp[0] = temp[0] ^ this.Rcon[row/Nk,0];

  KeyExpansion 方法有條件地調用私有方法 SubWord 和 RotWord 以保持同規范命名的一致性。此外,因為在C#中沒(méi)有 word類(lèi)型,我用 4字節數組實(shí)現了一個(gè)字。SubWord 和 RotWord 的代碼是相當簡(jiǎn)單,參見(jiàn)本文附帶的 AesLib 源代碼,它應該很容易理解。
  稍微具備有些技巧的部分是在 SubWord 中查找替代值?;叵胍幌?,為了尋找代替值,你將輸入字節分成最左邊的4位比特和最右邊的4位比特。對于一個(gè)給定字節,用 >> 操作符右移 4 位將得到 x 索引,并且與 0000 1111 進(jìn)行邏輯與得到 y 值。雖然有些長(cháng),但比實(shí)際代碼更可讀,我可以象下面這樣:

int x = word[0] >> 4; int y = word[0] & 0x0f; byte substitute = this.Sbox[x,y]; result[0] = substitute;

代替我原來(lái)用的代碼:

result[0] = this.Sbox[ word[0] >> 4, word[0] & 0x0f ];

  總的來(lái)說(shuō),AES 構造函數接受一個(gè)密鑰的長(cháng)度為128,192 或 256 位和一個(gè)字節數組種子密鑰值。構造函數為輸入塊長(cháng)度,種子密鑰長(cháng)度 以及加密算法的輪數賦值,并將種子密鑰拷貝到一個(gè)名為 key 的數據成員中。構造函數還創(chuàng )建了四個(gè)表:兩個(gè)由加密和解密方法使用的替換表,一個(gè)輪常數表,和一個(gè)輪密鑰的密鑰調度表。

 用C#編寫(xiě)的 AES Cipher 方法 

  Cipher方法如 Figure 11 所示。它真的非常簡(jiǎn)單,因為它分出了大部分的工作給私有方法AddRoundKey, SubBytes, ShiftRows 和 MixColumns。
  Cipher 方法以拷貝明文輸入數組到狀態(tài)矩陣 State[] 為開(kāi)始。最初調用 AddRoundKey 之后,Cipher 方法比總輪數少迭代一次。在最后一輪時(shí),正如規范中所說(shuō)的那樣,MixColumns 調用被省略了。
  AddRoundKey 和 SubBytes 私有方法的代碼如 Figure 12 所示。AddRoundKey 方法需要知道它處在那一輪,以便它正確引用4行密鑰調度數組 w[]。請注意 State[r,c] 是用 w[c,r] 來(lái)異或并不是w[r,c]。SubBytes 方法從輸入字節中提取索引,與 KeyExpansion 方法中所用的右移4位和 0x0f 屏蔽技術(shù)相同。
  ShiftRows 方法的代碼如 Figure 13 所示?;叵胍幌?,ShiftRows(可能叫做 RotateRows 更好)將 row[0] 向左旋轉 0 個(gè)位置,將 row[1] 向左旋轉 1 位置等等。
把 State[] 拷貝到 temp[] 矩陣之后,然后用下面的這行代碼實(shí)現轉換:

this.State[r, (c + r) % Nb ] = temp[r,c];

這里利用%操作符的優(yōu)點(diǎn)抱合一行。
  MixColumns 方法(Figure 14)用GF(28)加和乘,以字節列中所有其它值的線(xiàn)性組合對每一個(gè)字節進(jìn)行替換。
乘法所用的常量系數基于域論的,并且是0x01, 0x02或 0x03中的任意一個(gè)值。給定某一列 c ,其替代式如下:

State[0,c] = 0x02 * State[0,c] + 0x03 * State[1,c] + 0x01 * State[2,c] + 0x01 * State[3,c] State[1,c] = 0x01 * State[0,c] + 0x02 * State[1,c] + 0x03 * State[2,c] + 0x01 * State[3,c] State[2,c] = 0x01 * State[0,c] + 0x01 * State[1,c] + 0x02 * State[2,c] + 0x03 * State[3,c] State[3,c] = 0x03 * State[0,c] + 0x01 * State[1,c] + 0x01 * State[2,c] + 0x02 * State[3,c]

  這些表達式稍微有些長(cháng),因此我決定編寫(xiě)返回 GF(28)與 0x01,0x02 和 0x03 之乘積的私有輔助函數。這些輔助函數非常短。例如,一個(gè)字節 b 被 0x03 域乘的代碼如下:

return (byte) ( (int)gfmultby02(b) ^ (int)b );

  正如我前面討論的,被 0x02 乘是所有 GF(28) 乘法的基本操作。我調用了我的 gfmultby02 方法,我改變了使用與規范相同的方法命名慣例,規范上稱(chēng)此例程為 xtime。
  Cipher 方法其輸入反復應用四個(gè)操作來(lái)產(chǎn)生加密的輸出。AddRoundKey 用源于單個(gè)原始種子密鑰的多重輪密鑰來(lái)替代字節。SubBytes 用某個(gè)替換表中的值替代字節。ShiftRows 用移動(dòng)字節行置換字節,而 MixColumns 用某一列的域加和乘法值來(lái)替代字節。 

 用C#編寫(xiě) AES InvCipher 方法

  AES 解密算法背后的基本原則很簡(jiǎn)單:解密一個(gè)加密塊,也就是以反向順序還原(Undo)每個(gè)操作。盡管這是基本概念,但仍有幾個(gè)細節要處理。
  AES規范稱(chēng)解密例程為 InvCipher,而不是 Decipher 或 Decrypt 中的一個(gè)。這是 AES 背后的數學(xué)基礎的反映,它基于可逆的數學(xué)操作。
  如果你將這個(gè)代碼和 Cipher 代碼比較的話(huà),你會(huì )看到它比你預期的漂亮很多,但是有兩點(diǎn)例外。首先,在 InvCipher 方法中逆方法調用(如 InvSubBytes)順序并不完全與在 Cipher 方法中相應調用(如 SubBytes)的逆向順序正好相同。其次,InvCipher 調用的是一個(gè) AddRoundKey 方法而不是 InvAddRoundKey 方法。值得注意的是 InvCipher 算法用密鑰調度表并不是從較高編號的索引處開(kāi)始向下處理至第0行。
  InvSubBytes,InvShiftRows 和 InvMixColumns 方法的代碼和與之有關(guān)的 SubBytes,ShiftRows和 MixColumns 方法的代碼非常接近。InvSubBytes 方法幾乎就是 SubBytes 方法,只是它用逆替換表 iSbox[] 而不是 Sbox[] 表。
  正如你可能猜測到的,iSbox[] 就是還原任何被 Sbox[] 處理的對應操作。比如,如果你有字節 b 等于 0x20,并在 Sbox[] 中找到其代替值,你得到 0xb7。如果你在 iSbox[] 中找到 0xb7的替代值,你便可得到 0x20。
  相似地,InvShiftRows 方法還原 ShiftRows 方法—— row[0] 被右移了 0 個(gè)位置,row[1] 被右移了 1個(gè)位置,row[2] 被右移了 2 個(gè)位置,而 row[3] 被右移了 3個(gè)位置。
  InvMixColumns 方法還原 MixColumns 的工作,但沒(méi)有用顯而易見(jiàn)的方法?;叵胍幌?,MixColumns 用原始字節列中的字節線(xiàn)性組合替換狀態(tài)矩陣中的每個(gè)字節,并且系數是 0x01,0x02,和 0x03,域論再一次得到應用。它證明逆運算是相似的,只是被 0x09,0x0b,0x0d 和 0x0e 乘,如下所示:

State[0,c] = 0x0e * State[0,c] + 0x0b * State[1,c] + 0x0d * State[2,c] + 0x09 * State[3,c] State[1,c] = 0x09 * State[0,c] + 0x0e * State[1,c] + 0x0b * State[2,c] + 0x0d * State[3,c] State[2,c] = 0x0d * State[0,c] + 0x09 * State[1,c] + 0x0e * State[2,c] + 0x0b * State[3,c] State[3,c] = 0x0b * State[0,c] + 0x0d * State[1,c] + 0x09 * State[2,c] + 0x0e * State[3,c]

  對于 MixColumns 方法,我決定專(zhuān)門(mén)寫(xiě)一個(gè)輔助函數,而不是內聯(lián)展開(kāi)已經(jīng)較長(cháng)的表達式或寫(xiě)一個(gè)普通的乘法輔助函數。讓我向你展示一下我示如何編寫(xiě)這個(gè)任何字節 b 被常數 0x0e (在10進(jìn)制中的14)乘的函數,像任何數字一樣,數字 14 可以被表示成 2 的冪的和,因此,14 等于 2 + 4 + 8。并且 4 等于 2 的平方,8 等于 2 的立方,你可以將14表示為 2 + 22 + 23。記住加法就是 GF(28)中上的異或(^),既然我已經(jīng)有了 gfmultby02 函數,我可以用它得到我的結果:

return (byte)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^ /* 23 + */ (int)gfmultby02(gfmultby02(b)) ^ /* 22 + */ (int)gfmultby02(b) ); /* 2 */

用于 AES 加密算法的所有的操作都是可逆的,因此解密算法本質(zhì)上是加密的所有操作的倒轉。

  使用 AES 類(lèi)

  用C#實(shí)現 AES 的特色之一就簡(jiǎn)單??纯?nbsp;Figure 15,它是我用來(lái)生成輸出 Figure 1 的代碼。聲明了 16 字節 明文輸入硬代碼值和 24 字節(192位)的種子密鑰后,一個(gè) AES 對象被初始化,加密 Cipher 方法 將明文加密成為密文,然后再用 InvCipher 將密文解密。非常清楚和簡(jiǎn)單。
  因為 AES 對象針對字節數組進(jìn)行處理,你可以輕松地用它處理.NET的其它數據類(lèi)型。我創(chuàng )建了一個(gè)基于 Windows 的小Demo程序,它接受一個(gè) 單純的字符串——有 8 個(gè)字符 (16-byte) ,對它進(jìn)行加密和解密處理。運行畫(huà)面如 Figure 16。


Figure 16 加密 Demo 程序
 

 

因為加密和解密例程都需要知道用戶(hù)定義的密鑰長(cháng)度,我把它當作一個(gè)類(lèi)范圍的變量來(lái)聲明,像這樣:

private Aes.KeySize keysize;

  注意種子密鑰并不是由用戶(hù)定義的。這個(gè)demo 程序用一個(gè)“空密鑰”(null key)作為種子密鑰,通過(guò)為構造函數提供一個(gè)啞參數new byte[16] 使得它全部由零字節組成。啞參數的長(cháng)度是不相關(guān)的,因為種子密鑰還是要被初始化為零??彰荑€加密和解密是一個(gè)容易和有效的辦法來(lái)阻止外界對數據偶然的檢查。在System.Text 中的Encoding.Unicode.GetBytes和Encoding.Unicode.GetString 方法使得將一個(gè).NET 字符串轉換成一個(gè)字節數組變得非常容易,反之亦然。

 

 

 實(shí)現選擇

 

  現在讓我們看看本文AES 實(shí)現中出現的一些重要的變量,本文提供的代碼可能出現的擴展,以及針對AES 的密碼分析學(xué)攻擊。

  和我曾經(jīng)處理的任何代碼一樣,AES 算法也可以用其它可選的途徑來(lái)實(shí)現。為什么這很重要呢?AES 被試圖廣泛應用于各種系統,從只有很少內存容量的智能卡(smart cards)到大型的多處理器主機系統。在許多情況下,性能是關(guān)鍵因素,并且有時(shí)內存或處理器資源是有限的。事實(shí)上,AES 的每個(gè)例程都能針對非常昂貴的內存資源進(jìn)行性能優(yōu)化,反之亦然。比如,為替換表Sbox[] 分配256 個(gè)值看起來(lái)好像很簡(jiǎn)單直白。但是,這些值是基于GF(28) 理論的,它們都可以用編程方式來(lái)生成。逆向替換表和輪常數表也是如此。

  可選實(shí)現另外一個(gè)有趣的可能性是Cipher 和InvCipher 方法所用的GF(28) 乘法。我的實(shí)現代碼是一個(gè)被0x02 乘的基本函數,而后是六個(gè)調用gfmultby02 的附加函數。另一個(gè)可能性應該是寫(xiě)一個(gè)一般的乘法函數,并用它代替我目前實(shí)現的七個(gè)單獨函數。另一個(gè)極端是你可以用被0x01, 0x02, 0x03, 0x09, 0x0b, 0x0d 和0x0e 乘好的所有256 個(gè)可能的字節值構成的一個(gè)完整乘積表。此外,實(shí)現GF(28) 乘法另一途徑是通過(guò)在兩個(gè)256 個(gè)字節的數組里查找,通常稱(chēng)為alog[] 和log[],因為它們在GF(28)中基于某些類(lèi)似對數的方法。

  雖然這里給出的AES 類(lèi)完全能用于加密任何形式的.NET數據,你可能考慮想用各種方法擴展它。首先,因為本文的重點(diǎn)在于清楚地解釋AES,所有 錯誤檢查被剝離掉,以我的經(jīng)驗,為某個(gè)象AES 這樣的類(lèi)添加合理數量的錯誤檢查將會(huì )產(chǎn)生三倍的代碼量膨脹。因為AES 使用了這么多的數組,需要做很多索引 邊界檢查。例如,所給出的構造函數甚至都不檢查種子密鑰參數的長(cháng)度。

  你可能還考慮通過(guò)添加更多的特性來(lái)擴展AES 類(lèi)。最明顯的一個(gè)地方是添加加密和解密.NET基本數據類(lèi)型的方法,比如:System.String 和System.Int32。更加雄心勃勃的擴展可能會(huì )是實(shí)現一個(gè) 流數據加密類(lèi)。

  AES 的安全性怎樣呢?這是一個(gè)很難回答的問(wèn)題,但是一般多數人的意見(jiàn)是:它是目前可獲得的最安全的加密算法。AES 已被列為比任何現今其它加密算法更 安全的一種算法。在理論和實(shí)踐基礎上,AES 被認為是“安全的”,因為要破解它的話(huà),唯一有效的方法是強行(brute-force)生成所有可能的密鑰。 如果密鑰長(cháng)度為256 位,還沒(méi)有已知的攻擊可以在一個(gè)可接受的時(shí)間內破解AES(即便在當今最快的系統上,它也要花費數年時(shí)間)。

  注意針對AES 密碼最可能成功的攻擊來(lái)自一個(gè)允許時(shí)間選擇攻擊的弱實(shí)現。攻擊者用不同的密鑰并精確地測量出加密例程所需的時(shí)間。如果加密例程被粗心編碼 ,因此執行時(shí)間便依賴(lài)于密鑰值,它就有可能推導出有關(guān)密鑰的信息。在A(yíng)ES 中,這種事情最可能發(fā)生在MixColumns 例程中,因為有域乘。 針對這種攻擊的兩個(gè)安全措施是加入虛指令,以便所以所有乘法都需要相同數量的指令,或者將域乘實(shí)現為一個(gè)查詢(xún)表,就象我前面描述的那樣。

  AES 有許多種可能的實(shí)現,尤其是是使用查詢(xún)表而不是計算。本文提供的AES 基本類(lèi)可以被用于加解密任何形式的.NET數據或 被擴展成一個(gè)具有更多功能的類(lèi)。

 

 結束語(yǔ)

 

  新的AES 將無(wú)疑成為加密所有形式電子信息的事實(shí)上的標準,取代DES。AES 加密的數據在某種意義上是牢不可破的,因為沒(méi)有已知的密碼分析攻擊可以解密AES 密文,除非強行遍歷搜索所有可能的256 位密鑰。

  我發(fā)現在Microsoft .NET Framework 上實(shí)現AES 類(lèi)的主要的障礙是官方文檔是以一個(gè)數學(xué)家的觀(guān)點(diǎn),而不是以一個(gè)軟件開(kāi)發(fā)者的觀(guān)點(diǎn)來(lái)寫(xiě)的。尤其是該規范假定讀者十分熟悉GF(28) 域,并省略了幾個(gè)正確實(shí)現AES 所必需的關(guān)于GF(28) 乘法的關(guān)鍵事實(shí)。我在本文中試圖努力去掉AES 的神秘面紗,特別是圍繞在GF(28) 域乘法部分的。

  以.NET Framework 庫的形式從Microsoft 以及第三方供應商處獲得對AES 的廣泛支持只是一個(gè)時(shí)間問(wèn)題。然而,處于種種理由,讓本文代碼作為你的技能儲備仍然是有價(jià)值的。這個(gè)實(shí)現尤其簡(jiǎn)單,并且是低資源開(kāi)銷(xiāo)。另外,閱讀并理解源代碼將使你能定制AES 類(lèi)且更有效地使用它的任何實(shí)現。

  在任何軟件設計過(guò)程中安全已不再是后顧之憂(yōu)。AES 是一個(gè)重大進(jìn)步,使用并理解它將大大增加軟件系統的可靠性和安全性。

 

 

 

Figure 5 Cipher Algorithm Pseudocode

 

Cipher(byte[] input, byte[] output) { byte[4,4] State; copy input[] into State[] AddRoundKey for (round = 1; round < Nr-1; ++round) { SubBytes ShiftRows MixColumns AddRoundKey } SubBytes ShiftRows AddRoundKey copy State[] to output[] }

Figure 7 Initializing Rcon

 

private void BuildRcon() { this.Rcon = new byte[11,4] { {0x00, 0x00, 0x00, 0x00}, {0x01, 0x00, 0x00, 0x00}, {0x02, 0x00, 0x00, 0x00}, {0x04, 0x00, 0x00, 0x00}, {0x08, 0x00, 0x00, 0x00}, {0x10, 0x00, 0x00, 0x00}, {0x20, 0x00, 0x00, 0x00}, {0x40, 0x00, 0x00, 0x00}, {0x80, 0x00, 0x00, 0x00}, {0x1b, 0x00, 0x00, 0x00}, {0x36, 0x00, 0x00, 0x00} }; } // BuildRcon()

Figure 8 SetNbNkNr Method

 

private void SetNbNkNr(KeySize keySize) { this.Nb = 4; if (keySize == KeySize.Bits128) { this.Nk = 4; this.Nr = 10; } else if (keySize == KeySize.Bits192) { this.Nk = 6; this.Nr = 12; } else if (keySize == KeySize.Bits256) { this.Nk = 8; this.Nr = 14; } } // SetNbNkNr()

Figure 9 Sbox Initialization

 

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

Figure 10 KeyExpansion Method

 

private void KeyExpansion() { this.w = new byte[Nb * (Nr+1), 4]; for (int row = 0; row < Nk; ++row) { this.w[row,0] = this.key[4*row]; this.w[row,1] = this.key[4*row+1]; this.w[row,2] = this.key[4*row+2]; this.w[row,3] = this.key[4*row+3]; } byte[] temp = new byte[4]; for (int row = Nk; row < Nb * (Nr+1); ++row) { temp[0] = this.w[row-1,0]; temp[1] = this.w[row-1,1]; temp[2] = this.w[row-1,2]; temp[3] = this.w[row-1,3]; if (row % Nk == 0) { temp = SubWord(RotWord(temp)); temp[0] = (byte)( (int)temp[0] ^ (int)this.Rcon[row/Nk,0] ); temp[1] = (byte)( (int)temp[1] ^ (int)this.Rcon[row/Nk,1] ); temp[2] = (byte)( (int)temp[2] ^ (int)this.Rcon[row/Nk,2] ); temp[3] = (byte)( (int)temp[3] ^ (int)this.Rcon[row/Nk,3] ); } else if ( Nk > 6 && (row % Nk == 4) ) { temp = SubWord(temp); } // w[row] = w[row-Nk] xor temp this.w[row,0] = (byte) ( (int)this.w[row-Nk,0] ^ (int)temp[0] ); this.w[row,1] = (byte) ( (int)this.w[row-Nk,1] ^ (int)temp[1] ); this.w[row,2] = (byte) ( (int)this.w[row-Nk,2] ^ (int)temp[2] ); this.w[row,3] = (byte) ( (int)this.w[row-Nk,3] ^ (int)temp[3] ); } // for loop } // KeyExpansion()

Figure 11 The Cipher Method

 

public void Cipher(byte[] input, byte[] output) { // state = input this.State = new byte[4,Nb]; for (int i = 0; i < (4 * Nb); ++i) { this.State[i % 4, i / 4] = input[i]; } AddRoundKey(0); for (int round = 1; round <= (Nr - 1); ++round) { SubBytes(); ShiftRows(); MixColumns(); AddRoundKey(round); } SubBytes(); ShiftRows(); AddRoundKey(Nr); // output = state for (int i = 0; i < (4 * Nb); ++i) { output[i] = this.State[i % 4, i / 4]; } } // Cipher()

Figure 12 AddRoundKey and SubBytes Methods

 

private void AddRoundKey(int round) { for (int r = 0; r < 4; ++r) { for (int c = 0; c < 4; ++c) { this.State[r,c] = (byte) ( (int)this.State[r,c] ^ (int)w[(round*4)+c,r] ); } } } // AddRoundKey() private void SubBytes() { for (int r = 0; r < 4; ++r) { for (int c = 0; c < 4; ++c) { this.State[r,c] = this.Sbox[ (this.State[r,c] >> 4), (this.State[r,c] & 0x0f) ]; } } } // SubBytes

Figure 13 ShiftRows Method

 

private void ShiftRows() { byte[,] temp = new byte[4,4]; for (int r = 0; r < 4; ++r) { for (int c = 0; c < 4; ++c) { temp[r,c] = this.State[r,c]; } } for (int r = 1; r < 4; ++r) // { for (int c = 0; c < 4; ++c) { this.State[r,c] = temp[ r, (c + r) % Nb ]; } } } // ShiftRows()

Figure 14 MixColumns Method

 

private void MixColumns() { byte[,] temp = new byte[4,4]; for (int r = 0; r < 4; ++r) { for (int c = 0; c < 4; ++c) { temp[r,c] = this.State[r,c]; } } for (int c = 0; c < 4; ++c) { this.State[0,c] = (byte) ( (int)gfmultby02(temp[0,c]) ^ (int)gfmultby03(temp[1,c]) ^ (int)gfmultby01(temp[2,c]) ^ (int)gfmultby01(temp[3,c]) ); this.State[1,c] = (byte) ( (int)gfmultby01(temp[0,c]) ^ (int)gfmultby02(temp[1,c]) ^ (int)gfmultby03(temp[2,c]) ^ (int)gfmultby01(temp[3,c]) ); this.State[2,c] = (byte) ( (int)gfmultby01(temp[0,c]) ^ (int)gfmultby01(temp[1,c]) ^ (int)gfmultby02(temp[2,c]) ^ (int)gfmultby03(temp[3,c]) ); this.State[3,c] = (byte) ( (int)gfmultby03(temp[0,c]) ^ (int)gfmultby01(temp[1,c]) ^ (int)gfmultby01(temp[2,c]) ^ (int)gfmultby02(temp[3,c]) ); } } // MixColumns

Figure 15 Using AES

 

static void Main(string[] args) { byte[] plainText = new byte[] {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; byte[] cipherText = new byte[16]; byte[] decipheredText = new byte[16]; byte[] keyBytes = new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17}; Aes a = new Aes(Aes.KeySize.Bits192, keyBytes); Console.WriteLine("/nAdvanced Encryption System Demo in .NET"); Console.WriteLine("/nThe plaintext is: "); DisplayAsBytes(plainText); Console.WriteLine("/nUsing a " + Aes.KeySize.Bits192.ToString() + "-key of: "); DisplayAsBytes(keyBytes); a.Cipher(plainText, cipherText); Console.WriteLine("/nThe resulting ciphertext is: "); DisplayAsBytes(cipherText); a.InvCipher(cipherText, decipheredText); Console.WriteLine("/nAfter deciphering the ciphertext, the result is: "); DisplayAsBytes(decipheredText); Console.WriteLine("/nDone"); Console.ReadLine(); } // Main() static void DisplayAsBytes(byte[] bytes) { for (int i = 0; i < bytes.Length; ++i) { Console.Write(bytes[i].ToString("x2") + " " ); if (i > 0 && i % 16 == 0) Console.Write("/n"); } Console.WriteLine(""); } // DisplayAsBytes()

 

 


 相關(guān)文章

 背景信息

  The Design of Rijndael: AES - The Advanced Encryption Standard by Joan Daemen and Vincent Rijmen. (Springer-Verlag, 2002)
  Announcing the Advanced Encryption Standard (AES): Federal Information Processing Standards Pub 197

 作者簡(jiǎn)介
  James McCaffrey 在Volt Information Sciences Inc公司工作,在那里他管理為 Microsoft 的軟件工程師技術(shù)培訓。他作為一些 Microsoft 產(chǎn)品的承包人工作包括 Internet Explorer 和 MSN Search??赏ㄟ^(guò) jmccaffrey@volt.com 或 
v-jammc@microsoft.com與他聯(lián)系。
  本文出自 MSDN Magazine 的 Novenber 2003 期刊,可通過(guò)當地報攤獲得,或者最好是 訂閱

本文由 VCKBASE MTT 翻譯

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
UC頭條:AES密碼的基本介紹
java實(shí)現AES加密和解密
AES加密算法的C++實(shí)現
AES算法實(shí)現分析
AES算法分析與實(shí)現
最強加密算法?AES加密算法的Matlab和Verilog實(shí)現
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久