2007年4月19日 星期四

更好用的AES加密,4096 bit 安全性

最近在翻箱倒櫃整理以前寫過的一些程式,突然找到以前用Java寫的AES對稱式加密實作,而且我還把它寫成可以支援到4096 bit的加密強度,記得之前自己寫AES加密實作時,Java還沒有內建AES實作,所以這個Library用起來還是挺Happy的。(好吧…我承認我在自爽....Orz)

後來Java在1.4的時候已經提供了AES的實作,不過因為美國規定的加密技術輸出規則中所述,有些國家是不允許輸出高強度的加密技術的,所以Java預設只支援128 bit的加密強度,如果要用到192 bit或是256 bit時,還得去Sun原廠網站下載「JCE Unlimited Strength Jurisdiction Policy Files」。

不過沒有內含在JDK中用起來就是不方便,增加了Deploy的困擾,所以如果你有需要的話,可以到下列網址去下載Policy File:
http://java.sun.com/products/jce/index-14.html#UnlimitedDownload
注:到了JDK6預設仍然只有128bit的AES喔

什麼是AES?
寫到這突然發現我忘了介紹一下AES了,Advanced Encryption Standard (AES)-二十一世紀的一種加密演算法,美國國家技術標準局(NIST)在1998年所招攬的DES演算法繼承人,NIST希望在二十世紀結束之前,能夠預備好一個新的加密標準,要求加密區塊的明文長度為128位元,可接受的密鑰長度為128位元、192位元和256位元(含以上)。判定的標準為安全性、效率與適應性三方面。

於是在1998年8月20日第一次AES候選者的研討會中,出現了十五個候選的演算法。
列示如下:
CAST-256, CRYPTON, DEAL, DFC, E2, FROG, Hasty Pudding Cipher(HPC) , LOKI97, MARS, Magenta, RC6, RIJNDAEL, SAFER+, SERPENT, TWOFISH。

1999/3/22-23 NIST在義大利羅馬的奎爾諾飯店召開第二次AES候選者的研討會,NIST發出問卷調查,由參加者選出五種較有可能的演算法。

最後留下來參加決賽的有: MARS、RC6、Rijndael、Serpent、Twofish。

1999/4/15 Rijndael最後勝出,就是大家目前所使用的AES演算法,Rijndael是演算法作者的名字,盡管它很難唸…盡管大家都只知道AES而沒聽過Rijndael,我們還是別忘了他是作者。

Rijndael的理論基礎是將每個byte看成一個多項式:
例如:
有一個Byte的資料是01001010
則可將此Byte寫成多項式 0*X^7 + 1*X^6 + 0*X^5 + 0*X^4 + 1*X^3 + 0*X^0 + 1*X^1 + 0*X^0

然後利用迦羅瓦域定理經過一段運算而得,我並不打算在此說明理論細節,如果你有興趣的話,可以參考FIPS PUB 197,這篇Paper是AES演算法的詳細內容(在看之前惡補一下離散數學裡的迦羅瓦域定理有助於了解原理)

如何使用
我的AES Class很簡單使用,你可以參考以下範例:



// 指定加密強度,最高可到4096 bit
AESAlgorithm alg = new AESAlgorithm(AESAlgorithm.KEY_SIZE_4096);

// 產生Key
byte[] bytesKey = alg.createKey();
int[] wordsKeyExpansion = alg.createKeyExpansion(bytesKey);

String strMessage = "This is just an AES範例!!";

byte[] bytesMessage = strMessage.getBytes(); // 將字串轉成Byte Array
byte[] bytesEncrypted = alg.cipher(bytesMessage, wordsKeyExpansion); // 加密
byte[] bytesDecrypted = alg.invCipher(bytesEncrypted, wordsKeyExpansion); // 解密

System.out.println("decrypted= " + new String(bytesDecrypted) );


那裡可以下載?
最後,我的AES Library原始碼在這,供您參考!

18 則留言:

匿名 提到...

我看了你写的这个方法,我想请教一个问题
我现在如果想得到加密后的内容了,如何获取>??请指教!

我是一隻Coding Monkey 提到...

在sample code中是這樣加密的

byte[] bytesEncrypted = alg.cipher(bytesMessage, wordsKeyExpansion);

那個bytesEncrypted就是加密後的byte array.

FYR

匿名 提到...

我的意思是如何保存这个加密后的byte array,我试了几种方法,都是乱码,比如说我要保存到数据库,还请指教!
谢谢!!

匿名 提到...

不好意思ˇˇ我把妳的程式整個COPY下來了..請問那是怎樣執行呢
我怎找不到主程式名稱?
可以教一下嗎

我是一隻Coding Monkey 提到...

>>如何保存这个加密后的byte array
加密後的資料是binary data
不是字串後,不管用什麼加密演算法都一樣

如果要存到DB的話你可以使用BLOB格式存入,或是將binary data編碼成Base 64的字串

Unknown 提到...

Hi 你好,最近在找aes加密的一些資料,找到了您的網站。(多年前寫的程式現在有些問題)不知道您是否有在linux系統上實作過aes呢?我遇到的問題有張貼在討論區中了,有點想不通:http://www.javaworld.com.tw/jute/post/view?bid=5&id=218684&sty=3

不好意思打擾了~ 希望能指點我的迷津…sorry哦

匿名 提到...

AES Library原始碼 下载不了,能不能用邮件传给我一份,我的邮箱:enjoyjava@163.com。谢谢了!

我是一隻Coding Monkey 提到...

已回信

匿名 提到...

請教
private AESAlgorithm() {
}
這行的用意是?

我是一隻Coding Monkey 提到...

這行是要禁用Default Constructor,避免漏傳參數

Apple 提到...

謝謝,我嘗試將輸出的密文byte array轉成16進制用下面方法轉換,請指教
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2*buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private final static String HEX = "0123456789ABCDEF";
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}

匿名 提到...

抱歉,用了上面的方法,但加密字串輸出長度有問題,EX:明文:Email
密文長度為64.
主要轉換是這樣寫:
String bytesEncrypted = alg.toHex(strMessage)

我是一隻Coding Monkey 提到...

感謝Apple提供輸出密文的函式

至於樓上說的密文輸出長度問題,
由於AES是以Block的方式加密,
所以不管你加密前的明文長度多短,
加密後都會補滿一個Block,

所以在我的程式中有在加密前記錄明文長度為何,
以便解密後能回到原本的長度,

所以你明文很短,但密文卻很長是正常的

匿名 提到...

請問AddRoundKey 中 int l 指的是什麼?getByte(w[l + c], 3)是取對應位元嗎?

請教 finiteMultiplication 可以解釋 v1 v2 在Mixcolumns中的作用?非常感謝!!

延續樓上問題 AES中是否小於16Bite
輸出密文是32Bite?樓上的密文很長如何
判斷是否正確?

我是一隻Coding Monkey 提到...

回樓上,
http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf

AddRoundKey參考5.1.4

finiteMultiplication 參考 4.2,即迦羅瓦域的乘法,這會運用在MixColumn (參考5.1.3)

這些都是演算法的細節,實際運用上不需了解。

至於如何判定密文是否正確,
只須用同樣的key將密文解碼為明文,看看明文是否與原來一樣即可。

原則上明文愈長,加密後的密文愈長,比較特殊的是AES是以Block為單位,當明文不足一個block時,會在後方的空格補上0x00,

而在我的實作中:
我在明文前方加了Header,記錄明文的長度,所以加密前雖然不足一個block的部份會補零,但解密後我會讀取Header,將補零的部份刪除

匿名 提到...

請問AES是否密文輸出都是16byte?
Fips197中驗證步驟最後輸出都是16byte。
麻煩您了請指教。

Unknown 提到...
作者已經移除這則留言。
匿名 提到...

RCON 0x01000000 出現了兩次請問是否有特殊用意嗎?