久久r热视频,国产午夜精品一区二区三区视频,亚洲精品自拍偷拍,欧美日韩精品二区

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

詳細(xì)分析JAVA加解密算法

瀏覽:2日期:2022-08-30 09:47:27

加解密算法分析

日常開(kāi)發(fā)中,無(wú)論你是使用什么語(yǔ)言,都應(yīng)該遇到過(guò)使用加解密的使用場(chǎng)景,比如接口數(shù)據(jù)需要加密傳給前端保證數(shù)據(jù)傳輸?shù)陌踩?;HTTPS使用證書的方式首先進(jìn)行非對(duì)稱加密,將客戶端的私匙傳遞給服務(wù)端,然后雙方后面的通信都使用該私匙進(jìn)行對(duì)稱加密傳輸;使用MD5進(jìn)行文件一致性校驗(yàn),等等很多的場(chǎng)景都使用到了加解密技術(shù)。

很多時(shí)候我們對(duì)于什么時(shí)候要使用什么樣的加解密方式是很懵的。因?yàn)榭捎玫募咏饷芊桨笇?shí)在是太多,大家對(duì)加解密技術(shù)的類型可能不是很清楚,今天這篇文章就來(lái)梳理一下目前主流的加解密技術(shù),本篇文檔只針對(duì)算法做科普性說(shuō)明,不涉及具體算法分析。日常使用的加解密大致可以分為以下四類:

散列函數(shù)(也稱信息摘要)算法 對(duì)稱加密算法 非對(duì)稱加密算法 組合加密技術(shù)

1. 散列函數(shù)算法

聽(tīng)名字似乎不是一種加密算法,類似于給一個(gè)對(duì)象計(jì)算出hash值。所以這種算法一般用于數(shù)據(jù)特征提取。常用的散列函數(shù)包括:MD5、SHA1、SHA2(包括SHA128、SHA256等)散列函數(shù)的應(yīng)用很廣,散列函數(shù)有個(gè)特點(diǎn),它是一種單向加密算法,只能加密、無(wú)法解密。

1.1 MD5

先來(lái)看MD5算法,MD5算法是廣為使用的數(shù)據(jù)特征提取算法,最常見(jiàn)的就是我們?cè)谙螺d一些軟件,網(wǎng)站都會(huì)提供MD5值給你進(jìn)行校驗(yàn),你可以通過(guò)MD5值是否一致來(lái)檢查當(dāng)前文件是否被別人篡改。MD5算法具有以下特點(diǎn):

任意長(zhǎng)度的數(shù)據(jù)得到的MD5值長(zhǎng)度都是相等的; 對(duì)原數(shù)據(jù)進(jìn)行任一點(diǎn)修改,得到的MD5值就會(huì)有很大的變化; 散列函數(shù)的不可逆性,即已知原數(shù)據(jù),無(wú)法通過(guò)特征值反向獲取原數(shù)據(jù)。(需要說(shuō)明的是2004年的國(guó)際密碼討論年會(huì)(CRYPTO)尾聲,王小云及其研究同事展示了MD5、SHA-0及其他相關(guān)雜湊函數(shù)的雜湊沖撞。也就是說(shuō),她找出了第一個(gè) 兩個(gè)值不同,但 MD5 值相同的碰撞的例子。這個(gè)應(yīng)該不能稱之為破解)

1.2 MD5用途:

防篡改。上面說(shuō)過(guò)用于文件完整性校驗(yàn)。 用于不想讓別人看到明文的地方。比如用戶密碼入庫(kù),可以將用戶密碼使用MD5加密存儲(chǔ),下次用戶輸入密碼登錄只用將他的輸入進(jìn)行MD5加密與數(shù)據(jù)庫(kù)的值判斷是否一致即可,這樣就有效防止密碼泄露的風(fēng)險(xiǎn)。 用于文件秒傳。比如百度云的文件秒傳功能可以用這種方式來(lái)實(shí)現(xiàn)。在你點(diǎn)擊上傳的時(shí)候,前端同學(xué)會(huì)先計(jì)算文件的MD5值然后與服務(wù)端比對(duì)是否存在,如果有就會(huì)告訴你文件上傳成功,即完成所謂的秒傳。

在JDK中提供了MD5的實(shí)現(xiàn):java.security包中有個(gè)類MessageDigest,MessageDigest 類為應(yīng)用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的單向哈希函數(shù),它接收任意大小的數(shù)據(jù),輸出固定長(zhǎng)度的哈希值。

MessageDigest 對(duì)象使用getInstance函數(shù)初始化,該對(duì)象通過(guò)使用 update 方法處理數(shù)據(jù)。任何時(shí)候都可以調(diào)用 reset 方法重置摘要。一旦所有需要更新的數(shù)據(jù)都已經(jīng)被更新了,應(yīng)該調(diào)用 digest 方法之一完成哈希計(jì)算。

對(duì)于給定數(shù)量的更新數(shù)據(jù),digest 方法只能被調(diào)用一次。digest 被調(diào)用后,MessageDigest 對(duì)象被重新設(shè)置成其初始狀態(tài)。

下面的例子展示了使用JDK自帶的MessageDigest類使用MD5算法。同時(shí)也展示了如果使用了update方法后沒(méi)有調(diào)用digest方法,則會(huì)累計(jì)當(dāng)前所有的update中的值在下一次調(diào)用digest方法的時(shí)候一并輸出:

package other;import java.security.MessageDigest;/** * @author: rickiyang * @date: 2019/9/13 * @description: */public class MD5Test { static char[] hex = {’0’, ’1’, ’2’, ’3’, ’4’, ’5’, ’6’, ’7’, ’8’, ’9’, ’A’, ’B’, ’C’, ’D’, ’E’, ’F’}; public static void main(String[] args) { try { //申明使用MD5算法 MessageDigest md5 = MessageDigest.getInstance('MD5'); md5.update('a'.getBytes());// System.out.println('md5(a)=' + byte2str(md5.digest())); md5.update('a'.getBytes()); md5.update('bc'.getBytes()); System.out.println('md5(abc)=' + byte2str(md5.digest())); //你會(huì)發(fā)現(xiàn)上面的md5值與下面的一樣 md5.update('abc'.getBytes()); System.out.println('md5(abc)=' + byte2str(md5.digest())); } catch (Exception e) { e.printStackTrace(); } } /** * 將字節(jié)數(shù)組轉(zhuǎn)換成十六進(jìn)制字符串 * * @param bytes * @return */ private static String byte2str(byte[] bytes) { int len = bytes.length; StringBuffer result = new StringBuffer(); for (int i = 0; i < len; i++) { byte byte0 = bytes[i]; result.append(hex[byte0 >>> 4 & 0xf]); result.append(hex[byte0 & 0xf]); } return result.toString(); }}

輸出:

md5(a)=0CC175B9C0F1B6A831C399E269772661md5(abc)=900150983CD24FB0D6963F7D28E17F72md5(abc)=900150983CD24FB0D6963F7D28E17F72

1.3 SHA系列算法

Secure Hash Algorithm,是一種與MD5同源的數(shù)據(jù)加密算法。SHA算法能計(jì)算出一個(gè)數(shù)位信息所對(duì)應(yīng)到的,長(zhǎng)度固定的字串,又稱信息摘要。而且如果輸入信息有任何的不同,輸出的對(duì)應(yīng)摘要不同的機(jī)率非常高。因此SHA算法也是FIPS所認(rèn)證的五種安全雜湊算法之一。原因有兩點(diǎn):一是由信息摘要反推原輸入信息,從計(jì)算理論上來(lái)說(shuō)是極為困難的;二是,想要找到兩組不同的輸入信息發(fā)生信息摘要碰撞的幾率,從計(jì)算理論上來(lái)說(shuō)是非常小的。任何對(duì)輸入信息的變動(dòng),都有很高的幾率導(dǎo)致的信息摘要大相徑庭。

SHA實(shí)際上是一系列算法的統(tǒng)稱,分別包括:SHA-1、SHA-224、SHA-256、SHA-384以及SHA-512。后面4中統(tǒng)稱為SHA-2,事實(shí)上SHA-224是SHA-256的縮減版,SHA-384是SHA-512的縮減版。各中SHA算法的數(shù)據(jù)比較如下表,其中的長(zhǎng)度單位均為位:

類別 sha-1 sha-224 sha-256 sha-384 sha-512 消息摘要長(zhǎng)度 160 224 256 384 512 消息長(zhǎng)度 小于264位 小于264位 小于264位 小于2128位 小于2128位 分組長(zhǎng)度 512 512 512 1024 1024 計(jì)算字長(zhǎng)度 32 32 32 64 64 計(jì)算步驟數(shù) 80 64 64 80 80

SHA-1算法輸入報(bào)文的最大長(zhǎng)度不超過(guò)264位,產(chǎn)生的輸出是一個(gè)160位的報(bào)文摘要。輸入是按512 位的分組進(jìn)行處理的。SHA-1是不可逆的、防沖突,并具有良好的雪崩效應(yīng)。

上面提到的MessageDigest類同時(shí)也支持SHA系列算法,使用方式與MD5一樣,注意SHA不同的類型:

MessageDigest md = MessageDigest.getInstance('SHA');MessageDigest md = MessageDigest.getInstance('SHA-224');MessageDigest md = MessageDigest.getInstance('SHA-384');

2. 對(duì)稱加密算法

所謂的對(duì)稱加密,意味著加密者和解密者需要同時(shí)持有一份相同的密匙,加密者用密匙加密,解密者用密匙解密即可。

常用的對(duì)稱加密算法包括DES算法、AES算法等。 由于對(duì)稱加密需要一個(gè)秘鑰,而秘鑰在加密者與解密者之間傳輸又很難保證安全性,所以目前用對(duì)稱加密算法的話主要是用在加密者解密者相同,或者加密者解密者相對(duì)固定的場(chǎng)景。

對(duì)稱算法又可分為兩類:

第一種是一次只對(duì)明文中的單個(gè)位(有時(shí)對(duì)字節(jié))運(yùn)算的算法稱為序列算法或序列密碼;

另一種算法是對(duì)明文的一組位進(jìn)行運(yùn)算,這些位組稱為分組,相應(yīng)的算法稱為分組算法或分組密碼?,F(xiàn)代計(jì)算機(jī)密碼算法的典型分組長(zhǎng)度為64位??這個(gè)長(zhǎng)度既考慮到分析破譯密碼的難度,又考慮到使用的方便性。

2.1 BASE64算法

我們很熟悉的BASE64算法就是一個(gè)沒(méi)有秘密的對(duì)稱加密算法。因?yàn)樗募用芙饷芩惴ǘ际枪_(kāi)的,所以加密數(shù)據(jù)是沒(méi)有任何秘密可言,典型的防菜鳥不防程序員的算法。

BASE64算法作用:

用于簡(jiǎn)單的數(shù)據(jù)加密傳輸;

用于數(shù)據(jù)傳輸過(guò)程中的轉(zhuǎn)碼,解決中文問(wèn)題和特殊符號(hào)在網(wǎng)絡(luò)傳輸中的亂碼現(xiàn)象。 網(wǎng)絡(luò)傳輸過(guò)程中如果雙方使用的編解碼字符集方式不一致,對(duì)于中文可能會(huì)出現(xiàn)亂碼;與此類似,網(wǎng)絡(luò)上傳輸?shù)淖址⒉蝗强纱蛴〉淖址?,比如二進(jìn)制文件、圖片等。Base64的出現(xiàn)就是為了解決此問(wèn)題,它是基于64個(gè)可打印的字符來(lái)表示二進(jìn)制的數(shù)據(jù)的一種方法。

BASE64原理

BASE64的原理比較簡(jiǎn)單,每當(dāng)我們使用BASE64時(shí)都會(huì)先定義一個(gè)類似這樣的數(shù)組:

[’A’, ’B’, ’C’, ... ’a’, ’b’, ’c’, ... ’0’, ’1’, ... ’+’, ’/’]

上面就是BASE64的索引表,字符選用了'A-Z、a-z、0-9、+、/' 64個(gè)可打印字符,這是標(biāo)準(zhǔn)的BASE64協(xié)議規(guī)定。在日常使用中我們還會(huì)看到“=”或“==”號(hào)出現(xiàn)在BASE64的編碼結(jié)果中,“=”在此是作為填充字符出現(xiàn)。

JDK提供了BASE64的實(shí)現(xiàn):BASE64Encoder,我們可以直接使用:

//使用base64加密BASE64Encoder encoder = new BASE64Encoder(); String encrypt = encoder.encode(str.getBytes()); //使用base64解密BASE64Decoder decoder = new BASE64Decoder(); String decrypt = new String(decoder.decodeBuffer(encryptStr));

2.2 DES

DES (Data Encryption Standard),在很長(zhǎng)時(shí)間內(nèi),許多人心目中“密碼生成”與DES一直是個(gè)同義詞。

DES是一個(gè)分組加密算法,典型的DES以64位為分組對(duì)數(shù)據(jù)加密,加密和解密用的是同一個(gè)算法。它的密鑰長(zhǎng)度是56位(因?yàn)槊總€(gè)第8 位都用作奇偶校驗(yàn)),密鑰可以是任意的56位的數(shù),而且可以任意時(shí)候改變。

DES加密過(guò)程大致如下:

首先需要從用戶處獲取一個(gè)64位長(zhǎng)的密碼口令,然后通過(guò)等分、移位、選取和迭代形成一套16個(gè)加密密鑰,分別供每一輪運(yùn)算中使用; 然后將64位的明文分組M進(jìn)行操作,M經(jīng)過(guò)一個(gè)初始置換IP,置換成m0。將m0明文分成左半部分和右半部分m0 = (L0,R0),各32位長(zhǎng)。然后進(jìn)行16輪完全相同的運(yùn)算(迭代),這些運(yùn)算被稱為函數(shù)f,在每一輪運(yùn)算過(guò)程中數(shù)據(jù)與相應(yīng)的密鑰結(jié)合; 在每一輪迭代中密鑰位移位,然后再?gòu)拿荑€的56位中選出48位。通過(guò)一個(gè)擴(kuò)展置換將數(shù)據(jù)的右半部分?jǐn)U展成48位,并通過(guò)一個(gè)異或操作替代成新的48位數(shù)據(jù),再將其壓縮置換成32位。這四步運(yùn)算構(gòu)成了函數(shù)f。然后,通過(guò)另一個(gè)異或運(yùn)算,函數(shù)f的輸出與左半部分結(jié)合,其結(jié)果成為新的右半部分,原來(lái)的右半部分成為新的左半部分。將該操作重復(fù)16次; 經(jīng)過(guò)16輪迭代后,左,右半部分合在一起經(jīng)過(guò)一個(gè)末置換(數(shù)據(jù)整理),這樣就完成了加密過(guò)程。

對(duì)于DES解密的過(guò)程大家猛然一想應(yīng)該是使用跟加密過(guò)程相反的算法,事實(shí)上解密和加密使用的是一樣的算法,有區(qū)別的地方在于加密和解密在使用密匙的時(shí)候次序是相反的。比如加密的時(shí)候是K0,K1,K2......K15,那么解密使用密匙的次序就是倒過(guò)來(lái)的。之所以能用相同的算法去解密,這跟DES特意設(shè)計(jì)的加密算法有關(guān),感興趣的同學(xué)可以深入分析。

2.3 AES

高級(jí)加密標(biāo)準(zhǔn)(AES,Advanced Encryption Standard),與DES一樣,使用AES加密函數(shù)和密匙來(lái)對(duì)明文進(jìn)行加密,區(qū)別就是使用的加密函數(shù)不同。

上面說(shuō)過(guò)DES的密鑰長(zhǎng)度是56比特,因此算法的理論安全強(qiáng)度是2^56。但以目前計(jì)算機(jī)硬件的制作水準(zhǔn)和升級(jí)情況,破解DES可能只是山脈問(wèn)題,最終NIST(美國(guó)國(guó)家標(biāo)準(zhǔn)技術(shù)研究所(National Institute of Standards and Technology))選擇了分組長(zhǎng)度為128位的Rijndael算法作為AES算法。

AES為分組密碼,分組密碼也就是把明文分成一組一組的,每組長(zhǎng)度相等,每次加密一組數(shù)據(jù),直到加密完整個(gè)明文。在AES標(biāo)準(zhǔn)規(guī)范中,分組長(zhǎng)度只能是128位,也就是說(shuō),每個(gè)分組為16個(gè)字節(jié)(每個(gè)字節(jié)8位)。密鑰的長(zhǎng)度可以使用128位、192位或256位。密鑰的長(zhǎng)度不同,推薦加密輪數(shù)也不同,如下表所示:

AES 密鑰長(zhǎng)度(32位比特字) 分組長(zhǎng)度(32位比特字) 加密輪數(shù) AES-128 4 4 10 AES-192 6 4 12 AES-256 8 4 14

3. 非對(duì)稱加密

非對(duì)稱加密算法的特點(diǎn)是,秘鑰一次會(huì)生成一對(duì),其中一份秘鑰由自己保存,不能公開(kāi)出去,稱為“私鑰”,另外一份是可以公開(kāi)出去的,稱為“公鑰”。

將原文用公鑰進(jìn)行加密,得到的密文只有用對(duì)應(yīng)私鑰才可以解密得到原文;

將原文用私鑰加密得到的密文,也只有用對(duì)應(yīng)的公鑰才能解密得到原文;

因?yàn)榧用芎徒饷苁褂玫氖莾蓚€(gè)不同的密鑰,所以這種算法叫作非對(duì)稱加密算法。

詳細(xì)分析JAVA加解密算法

與對(duì)稱加密算法的對(duì)比

優(yōu)點(diǎn):其安全性更好,對(duì)稱加密的通信雙方使用相同的秘鑰,如果一方的秘鑰遭泄露,那么整個(gè)通信就會(huì)被破解。而非對(duì)稱加密使用一對(duì)秘鑰,一個(gè)用來(lái)加密,一個(gè)用來(lái)解密,而且公鑰是公開(kāi)的,秘鑰是自己保存的,不需要像對(duì)稱加密那樣在通信之前要先同步秘鑰。 缺點(diǎn):非對(duì)稱加密的缺點(diǎn)是加密和解密花費(fèi)時(shí)間長(zhǎng)、速度慢,只適合對(duì)少量數(shù)據(jù)進(jìn)行加密。

在非對(duì)稱加密中使用的主要算法有:RSA、Elgamal、ESA、背包算法、Rabin、D-H、ECC(橢圓曲線加密算法)等。不同算法的實(shí)現(xiàn)機(jī)制不同。

非對(duì)稱加密工作原理

下面我們就看一下非對(duì)稱加密的工作原理。

乙方生成一對(duì)密鑰(公鑰和私鑰)并將公鑰向其它方公開(kāi)。 得到該公鑰的甲方使用該密鑰對(duì)機(jī)密信息進(jìn)行加密后再發(fā)送給乙方。 乙方再用自己保存的另一把專用密鑰(私鑰)對(duì)加密后的信息進(jìn)行解密。乙方只能用其專用密鑰(私鑰)解密由對(duì)應(yīng)的公鑰加密后的信息。 在傳輸過(guò)程中,即使攻擊者截獲了傳輸?shù)拿芪模⒌玫搅艘业墓€,也無(wú)法破解密文,因?yàn)橹挥幸业乃借€才能解密密文。同樣,如果乙要回復(fù)加密信息給甲,那么需要甲先公布甲的公鑰給乙用于加密,甲自己保存甲的私鑰用于解密。

非對(duì)稱加密鼻祖:RSA

RSA算法基于一個(gè)十分簡(jiǎn)單的數(shù)論事實(shí):將兩個(gè)大質(zhì)數(shù)(素?cái)?shù))相乘十分容易,但是想要對(duì)其乘積進(jìn)行因式分解卻極其困難,因此可以將乘積公開(kāi)作為加密密鑰。比如:取兩個(gè)簡(jiǎn)單的質(zhì)數(shù):67,73,得到兩者乘積很簡(jiǎn)單4891;但是要想對(duì)4891進(jìn)行因式分解,其工作量成幾何增加。

應(yīng)用場(chǎng)景:

HTTPS請(qǐng)求的SSL層。

詳細(xì)分析JAVA加解密算法

在JDK中也提供了RSA的實(shí)現(xiàn),下面給出示例:

/** * 創(chuàng)建密匙對(duì) * * @return */ private KeyPair genKeyPair() { //創(chuàng)建 RSA Key 的生產(chǎn)者。 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance('RSA'); //利用用戶密碼作為隨機(jī)數(shù)初始化出 1024 比特 Key 的生產(chǎn)者。 //SecureRandom 是生成安全隨機(jī)數(shù)序列,password.getBytes() 是種子,只要種子相同,序列就一樣。 keyPairGen.initialize(1024, new SecureRandom('password'.getBytes())); //創(chuàng)建密鑰對(duì) return keyPairGen.generateKeyPair(); } /** * 生成公匙 * * @return */ public PublicKey genPublicKey() { try { //創(chuàng)建密鑰對(duì) KeyPair keyPair = genKeyPair(); //生成公鑰 PublicKey publicKey = keyPair.getPublic(); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey.getEncoded()); KeyFactory keyFactory = KeyFactory.getInstance('RSA'); publicKey = keyFactory.generatePublic(keySpec); return publicKey; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 生成私匙 * * @return */ public PrivateKey genPrivateKey() { try { //創(chuàng)建密鑰對(duì) KeyPair keyPair = genKeyPair(); //生成私匙 PrivateKey privateKey = keyPair.getPrivate(); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(privateKey.getEncoded()); KeyFactory keyFactory = KeyFactory.getInstance('RSA'); return keyFactory.generatePrivate(keySpec); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 公鑰加密 * * @param data * @param publicKey * @return * @throws Exception */ public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception { X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey.getBytes()); KeyFactory keyFactory = KeyFactory.getInstance('RSA'); Key publicK = keyFactory.generatePublic(x509KeySpec); // 對(duì)數(shù)據(jù)加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicK); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 對(duì)數(shù)據(jù)分段加密 while (inputLen - offSet > 0) { if (inputLen - offSet > 117) { cache = cipher.doFinal(data, offSet, 117); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * 117; } byte[] encryptedData = out.toByteArray(); out.close(); return encryptedData; } /** * 私鑰解密 * * @param encryptedData * @param privateKey * @return * @throws Exception */ public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception { PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey.getBytes()); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateK); int inputLen = encryptedData.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 對(duì)數(shù)據(jù)分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > 118) { cache = cipher.doFinal(encryptedData, offSet, 118); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * 118; } byte[] decryptedData = out.toByteArray(); out.close(); return decryptedData; } /** * 私鑰加密 * * @param data * @param privateKey * @return * @throws Exception */ public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception { PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(publicKey.getBytes()); KeyFactory keyFactory = KeyFactory.getInstance('RSA'); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateK); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 對(duì)數(shù)據(jù)分段加密 while (inputLen - offSet > 0) { if (inputLen - offSet > 117) { cache = cipher.doFinal(data, offSet, 117); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * 117; } byte[] encryptedData = out.toByteArray(); out.close(); return encryptedData; }/** * 公鑰解密 * * @param encryptedData * @param publicKey * @return * @throws Exception */ public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception { X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey.getBytes()); KeyFactory keyFactory = KeyFactory.getInstance('RSA'); Key publicK = keyFactory.generatePublic(x509KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicK); int inputLen = encryptedData.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 對(duì)數(shù)據(jù)分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > 118) { cache = cipher.doFinal(encryptedData, offSet, 118); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * 118; } byte[] decryptedData = out.toByteArray(); out.close(); return decryptedData; }

4. 組合加密

上面介紹的3種加密技術(shù),每一種都有自己的特點(diǎn),比如散列技術(shù)用于特征值提取,對(duì)稱加密速度雖快但是有私匙泄露的危險(xiǎn),非對(duì)稱加密雖然安全但是速度卻慢?;谶@些情況,現(xiàn)在的加密技術(shù)更加趨向于將這些加密的方案組合起來(lái)使用,基于此來(lái)研發(fā)新的加密算法。

MAC(Message Authentication Code,消息認(rèn)證碼算法)是含有密鑰散列函數(shù)算法,兼容了MD和SHA算法的特性,并在此基礎(chǔ)上加上了密鑰。因此MAC算法也經(jīng)常被稱作HMAC算法。MAC(Message Authentication Code,消息認(rèn)證碼算法)是含有密鑰散列函數(shù)算法,HMAC加密可以理解為加鹽的散列算法,此處的“鹽”就相當(dāng)于HMAC算法的秘鑰。

HMAC算法的實(shí)現(xiàn)過(guò)程需要一個(gè)加密用的散列函數(shù)(表示為H)和一個(gè)密鑰。

經(jīng)過(guò)MAC算法得到的摘要值也可以使用十六進(jìn)制編碼表示,其摘要值得長(zhǎng)度與實(shí)現(xiàn)算法的摘要值長(zhǎng)度相同。例如 HmacSHA算法得到的摘要長(zhǎng)度就是SHA1算法得到的摘要長(zhǎng)度,都是160位二進(jìn)制數(shù),換算成十六進(jìn)制的編碼為40位。

MAC算法的實(shí)現(xiàn):

算法 摘要長(zhǎng)度 備注 HmacMD5 128 JAVA6實(shí)現(xiàn) HmacSHA1 160 JAVA6實(shí)現(xiàn) HmacSHA256 256 JAVA6實(shí)現(xiàn) HmacSHA384 384 JAVA6實(shí)現(xiàn) HmacSHA512 512 JAVA6實(shí)現(xiàn) HmacMD2 128 BouncyCastle實(shí)現(xiàn) HmacMD4 128 BouncyCastle實(shí)現(xiàn) HmacSHA224 224 BouncyCastle實(shí)現(xiàn)

過(guò)程如下:

在密鑰key后面添加0來(lái)創(chuàng)建一個(gè)長(zhǎng)為B(64字節(jié))的字符串(str); 將上一步生成的字符串(str) 與ipad(0x36)做異或運(yùn)算,形成結(jié)果字符串(istr); 將數(shù)據(jù)流data附加到第二步的結(jié)果字符串(istr)的末尾; 做md5運(yùn)算于第三步生成的數(shù)據(jù)流(istr); 將第一步生成的字符串(str) 與opad(0x5c)做異或運(yùn)算,形成結(jié)果字符串(ostr),再將第四步的結(jié)果(istr) 附加到第五步的結(jié)果字符串(ostr)的末尾做md5運(yùn)算于第6步生成的數(shù)據(jù)流(ostr),最終輸出結(jié)果(out)

注意:如果第一步中,key的長(zhǎng)度klen大于64字節(jié),則先進(jìn)行md5運(yùn)算,使其長(zhǎng)度klen = 16字節(jié)。

JDK中的實(shí)現(xiàn):

public static void jdkHmacMD5() { try { // 初始化KeyGenerator KeyGenerator keyGenerator = KeyGenerator.getInstance('HmacMD5'); // 產(chǎn)生密鑰 SecretKey secretKey = keyGenerator.generateKey(); // 獲取密鑰 byte[] key = secretKey.getEncoded(); // byte[] key = Hex.decodeHex(new char[]{’1’, ’2’, ’3’, ’4’, ’5’, ’6’, ’7’, ’8’, ’9’, ’a’, ’b’, ’c’, ’d’, ’e’}); // 還原密鑰 SecretKey restoreSecretKey = new SecretKeySpec(key, 'HmacMD5'); // 實(shí)例化MAC Mac mac = Mac.getInstance(restoreSecretKey.getAlgorithm()); // 初始化MAC mac.init(restoreSecretKey); // 執(zhí)行摘要 byte[] hmacMD5Bytes = mac.doFinal('data'.getBytes()); System.out.println('jdk hmacMD5:' + new String(hmacMD5Bytes)); } catch (Exception e) { e.printStackTrace(); }}

以上就是詳細(xì)分析JAVA加解密算法的詳細(xì)內(nèi)容,更多關(guān)于JAVA加解密算法的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 都匀市| 顺平县| 白河县| 金塔县| 日喀则市| 兴安盟| 读书| 旺苍县| 仙居县| 九台市| 罗城| 平远县| 济源市| 安国市| 中卫市| 诸城市| 延安市| 惠安县| 满城县| 肥东县| 肇庆市| 卢湾区| 武陟县| 甘德县| 扎鲁特旗| 鹿邑县| 乐安县| 三都| 罗城| 色达县| 墨脱县| 新化县| 申扎县| 泾源县| 珠海市| 长兴县| 杨浦区| 马龙县| 蒲江县| 开鲁县| 攀枝花市|