Java中的安全加密
我了解了更多有關(guān)密碼的知識(shí),發(fā)現(xiàn)您需要了解更多信息。 我寫的內(nèi)容在一定程度上是正確的,但是除非您小心謹(jǐn)慎,否則敏感數(shù)據(jù)可能并非對(duì)所有攻擊者都是安全的。
開箱即用Shiro提供了Blowfish-CBC和AES-CBC加密方法,我建議使用它們。 兩者都旨在防止被動(dòng)竊聽攻擊者并且擅長(zhǎng)于此。 不幸的是,真正的攻擊者更加復(fù)雜,可能會(huì)破壞基于他們的系統(tǒng)。
注意“可能”。 攻擊者只有在被攻擊系統(tǒng)至少與他配合時(shí)才能成功。 如果要使用這些密碼,則必須知道如何安全地編寫系統(tǒng)。 當(dāng)然,另一種選擇是使用更強(qiáng)的密碼并完全避免該問題。
第一章中很少解釋所需的理論術(shù)語和概念 。 第二章介紹了如何以更安全的方式加密數(shù)據(jù)。 然后,我們描述了Blowfish-CBC和AES-CBC的工作方式,并展示了對(duì)它們的兩種可能的攻擊 。 最后,該帖子的末尾包含對(duì)其他資源的引用
理論
我們從一些理論概念開始。 如果您不想閱讀它,請(qǐng)直接轉(zhuǎn)到解決方案的章節(jié)。
首先要描述的重要事情是被動(dòng)攻擊者和主動(dòng)攻擊者之間的區(qū)別。 然后,我們解釋什么是分組密碼以及什么是經(jīng)過身份驗(yàn)證的加密。 最后兩個(gè)子章節(jié)列出了選定的易受攻擊的密碼和選定的安全密碼。
主動(dòng)與被動(dòng)攻擊者
僅竊聽攻擊者通常是被動(dòng)的。 他能夠讀取加密的通信,但無法對(duì)其進(jìn)行修改或?qū)⑿碌拿芪陌l(fā)送給通信應(yīng)用程序。 他無法影響交流,他只會(huì)聽。 他的被動(dòng)性只有一個(gè)例外:攻擊者能夠?qū)⑽醇用艿男畔⑻峁┙o通信方之一,并獲得具有該確切信息的密文。
現(xiàn)實(shí)世界中的攻擊者通常更活躍。 他們編寫自己的消息,并將其發(fā)送到通信應(yīng)用程序。 然后,該應(yīng)用程序假定這些消息已加密,因此它將嘗試對(duì)其進(jìn)行解密。 攻擊者觀察其反應(yīng)(返回的錯(cuò)誤代碼,需要的響應(yīng)時(shí)間等),并進(jìn)一步了解密碼。
如果幸運(yùn)的話,他可能會(huì)使用獲得的知識(shí)來破解密碼或植入虛假信息。
分組密碼
分組密碼只能加密短消息。 例如,AES只能加密16個(gè)字節(jié)長(zhǎng)的消息,而Blowfish只能加密8個(gè)字節(jié)長(zhǎng)的消息。
較長(zhǎng)的消息分為多個(gè)塊。 每個(gè)塊與先前加密的塊組合,然后傳遞到塊密碼。 塊組合被稱為操作模式,并且有多種安全方式來實(shí)現(xiàn)。
本文討論的兩種主動(dòng)攻擊是對(duì)CBC操作模式的攻擊。 分組密碼本身是安全的。
認(rèn)證加密
經(jīng)過身份驗(yàn)證的加密將任何修改后的密文視為無效。 無法獲取加密的數(shù)據(jù),對(duì)其進(jìn)行修改并以有效的密文結(jié)尾。 此屬性也稱為密文完整性。
密碼首先檢查完整性,然后以相同方式拒絕所有已修改的消息。 由于攻擊者無法通過完整性檢查,因此他從向應(yīng)用程序發(fā)送新消息中得不到任何好處。
身份驗(yàn)證和密文完整性通常(但不總是)由操作模式提供。
弱勢(shì)密碼
任何不提供密文完整性或未經(jīng)過身份驗(yàn)證的加密的密碼都可能會(huì)受到一些主動(dòng)攻擊。 使用哪個(gè)加密庫(kù)都沒有關(guān)系。 加密算法是在標(biāo)準(zhǔn)中定義的,并且與所使用的庫(kù)無關(guān),其含義相同。
換句話說,如果可以在不知道秘密密鑰的情況下創(chuàng)建有效的密文,那么即使不知道,也可能存在一些主動(dòng)攻擊。
這篇文章描述了兩種攻擊CBC的操作模式。 一旦了解了這些攻擊以及被動(dòng)和主動(dòng)攻擊者之間的區(qū)別,您就應(yīng)該能夠?qū)FB,CTR,OFB或其他未經(jīng)身份驗(yàn)證的密碼模式提出類似的攻擊。
安全密碼
經(jīng)過身份驗(yàn)證的加密可以防止主動(dòng)攻擊者的攻擊。 還提供身份驗(yàn)證的最常見操作模式是:
- GCM
- EAX
- CCM
用這些模式之一(例如AES-EAX)替換CBC,您將擁有一個(gè)針對(duì)活動(dòng)攻擊者的安全密碼。
當(dāng)然,針對(duì)主動(dòng)攻擊者的安全并不意味著該密碼沒有其他實(shí)際限制。 例如,大多數(shù)密碼只有在用戶加密了太多數(shù)據(jù)后才更改密鑰時(shí)才是安全的。 如果您認(rèn)真對(duì)待數(shù)據(jù)加密,則應(yīng)該研究并了解這些限制。
使用Shiro進(jìn)行身份驗(yàn)證的加密
本章介紹如何在Java中使用經(jīng)過身份驗(yàn)證的加密。 對(duì)于那些不了解該理論的人 ,認(rèn)證加密可以防止數(shù)據(jù)篡改。 沒有密鑰的任何人都不能修改加密的消息,并且不可能對(duì)這種密碼進(jìn)行主動(dòng)攻擊。
Apache Shiro沒有實(shí)現(xiàn)自己的加密算法。 它將所有工作委托給Java密碼學(xué)擴(kuò)展(JCE),每個(gè)Java運(yùn)行時(shí)中都可用。 Shiro“僅”提供易于使用的API和安全的默認(rèn)值。
因此,我們必須做兩件事:
- 將經(jīng)過身份驗(yàn)證的操作模式安裝到Java密碼擴(kuò)展中,
- 將Shiro與新的經(jīng)過驗(yàn)證的操作模式集成。
安裝經(jīng)過身份驗(yàn)證的操作模式
Java密碼術(shù)擴(kuò)展是一個(gè)可擴(kuò)展的API。 所有類和算法都是由提供程序創(chuàng)建的,新提供程序可以隨時(shí)安裝到系統(tǒng)中。 提供者可以是:
- 安裝到Java運(yùn)行時(shí)中,并且可用于所有Java應(yīng)用程序,
- 與應(yīng)用程序一起分發(fā)和初始化。
我們將展示如何將Bouncy Castle添加到項(xiàng)目中。 Bouncy Castle是根據(jù)MIT許可分發(fā)的提供商,并且包含EAX和GCM操作模式。
Bouncy Castle分發(fā)了多個(gè)jar文件,每個(gè)文件針對(duì)不同的Java版本進(jìn)行了優(yōu)化。 由于我們的演示項(xiàng)目使用Java 6,因此我們必須使用bcprov-jdk16庫(kù)。 將maven依賴項(xiàng)添加到pom.xml中:
<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk16</artifactId><version>1.46</version> </dependency>庫(kù)存在后,您必須將其提供程序安裝到j(luò)ava安全系統(tǒng)中。 在應(yīng)用程序啟動(dòng)時(shí)運(yùn)行以下方法:
private BouncyCastleProvider installBouncyCastle() {BouncyCastleProvider provider = new BouncyCastleProvider();Security.addProvider(provider);return provider; }現(xiàn)在已安裝Bouncy Castle,并且兩種驗(yàn)證操作模式都可用。
與Shiro集成
Shiro加密軟件包基本上是JCE上易于使用的外觀。 它將JCE對(duì)象配置為使用安全默認(rèn)值,并為其添加線程安全性。
擴(kuò)展DefaultBlockCipherService類以利用這些功能。 大多數(shù)配置都由該類完成,但是我們?nèi)匀槐仨氈付ㄈ?#xff1a;
- 分組密碼名稱和參數(shù),
- 操作模式,
- 填充。
塊密碼名稱在構(gòu)造函數(shù)參數(shù)中指定。 我們將使用AES,因?yàn)樗恍枰渌渲谩?GCM和CCM都不需要填充,因此我們必須指定填充NONE 。
新密碼服務(wù):
class GCMCipherService extends DefaultBlockCipherService {private static final String ALGORITHM_NAME = "AES";public GCMCipherService() {super(ALGORITHM_NAME);setMode(OperationMode.GCM);setPaddingScheme(PaddingScheme.NONE);}}這就對(duì)了。 您可以將新的身份驗(yàn)證密碼用作任何其他Shiro密碼服務(wù) 。
測(cè)試用例
我們創(chuàng)建了一個(gè)簡(jiǎn)單的測(cè)試用例,以證明完整性檢查有效。 它加密消息并更改其密文的第三個(gè)字節(jié)。 如果密碼提供了身份驗(yàn)證,則嘗試解密修改后的密文將導(dǎo)致運(yùn)行時(shí)異常:
@Test public void testGCMAuthentication() {String message = "secret message";GCMCipherService gcmCipher = new GCMCipherService();assertIngetrityCheck(message, gcmCipher); }private void assertIngetrityCheck(String message, DefaultBlockCipherService cipher) {byte[] key = cipher.generateNewKey().getEncoded();byte[] messageBytes = CodecSupport.toBytes(message);ByteSource encrypt = cipher.encrypt(messageBytes, key);// change the ciphertextencrypt.getBytes()[3] = 0;try {// it should be impossible to decrypt changed ciphertextcipher.decrypt(encrypt.getBytes(), key).getBytes();} catch (Exception ex) {return;}fail("It should not be possible to decrypt changed ciphertext."); }關(guān)于Java 7的注意事項(xiàng)
根據(jù)文檔 ,Java 7支持兩種經(jīng)過身份驗(yàn)證的操作模式:CCM和GCM。 從理論上講,您不需要第三方加密提供程序。
不幸的是,Oracle無法在第一個(gè)JDK 7版本中提供這些模式的完整實(shí)現(xiàn)。 他們希望將其添加到更新版本中,因此情況將來可能會(huì)發(fā)生變化。 Oracle錯(cuò)誤數(shù)據(jù)庫(kù)包含兩個(gè)相關(guān)的 錯(cuò)誤 。
Java 1.7.0_01仍然沒有它們。
密碼塊鏈接(CBC)
在描述承諾的攻擊之前,我們需要做的最后一件事是密碼塊鏈接(CBC)操作模式。 這種操作模式足以抵御被動(dòng)攻擊者,相當(dāng)快速且易于實(shí)施。
不幸的是,它也容易受到主動(dòng)攻擊。
基本
CBC用于使用分組密碼對(duì)長(zhǎng)消息進(jìn)行加密。 分組密碼只能加密短數(shù)據(jù)塊,因此它首先將消息拆分為短數(shù)據(jù)塊。
第一個(gè)和最后一個(gè)塊是特殊情況。 我們將在以下子章節(jié)中說明如何處理它們。 現(xiàn)在,假設(shè)消息開頭已被加密,并且其第i個(gè)塊m i與密文c i相對(duì)應(yīng)。
分兩個(gè)步驟對(duì)下一個(gè)消息塊進(jìn)行加密:
- 用上一個(gè)塊的密文對(duì)該塊進(jìn)行異或(例如, m i ?c i-1 ),
- 使用分組密碼(例如Blowfish(key, m i ?c i-1 ) )對(duì)結(jié)果進(jìn)行加密。
示例:假設(shè)該秘密消息有三個(gè)塊,我們正在嘗試使用Blowfish-CBC對(duì)其進(jìn)行加密。 第一塊已經(jīng)被加密,其密文為1, 2, 3, 4, 5, 6, 7, 8 。 第二個(gè)塊是字節(jié)數(shù)組1, 0, 1, 0, 1, 0, 1, 0 。
步驟1:將第一個(gè)塊密文與第二個(gè)塊異或:
1, 2, 3, 4, 5, 6, 7, 8 ? 1, 0, 1, 0, 1, 0, 1, 0 = 0, 2, 2, 4, 4, 6, 6, 8步驟2:使用河豚算法對(duì)結(jié)果進(jìn)行加密:
Blowfish(secret_key, {0, 2, 2, 4, 4, 6, 6, 8})第一塊–初始化向量
第一個(gè)塊沒有要合并的前一個(gè)塊。 因此,我們將生成一個(gè)稱為初始化向量的隨機(jī)數(shù)據(jù)塊。 初始化向量用作數(shù)據(jù)的第一塊。 它與第一個(gè)消息塊進(jìn)行異或運(yùn)算,并使用塊密碼對(duì)結(jié)果進(jìn)行加密。
初始化向量作為密文的第一個(gè)塊未經(jīng)加密地發(fā)送。 如果沒有密文,接收者將無法解密密文,也沒有理由對(duì)其保密。
示例:假設(shè)該秘密消息有三個(gè)塊,我們正在嘗試使用Blowfish-CBC對(duì)其進(jìn)行加密。 第一個(gè)塊是一個(gè)字節(jié)數(shù)組1, 1, 1, 1, 1, 1, 1, 1 。
步驟1:產(chǎn)生隨機(jī)初始化向量:
1, 8, 2, 7, 3, 6, 4, 5步驟2:將第一個(gè)塊與初始化向量進(jìn)行異或:
1, 8, 2, 7, 3, 6, 4, 5 ? 1, 1, 1, 1, 1, 1, 1, 1 = 0, 9, 3, 6, 2, 7, 5, 4步驟3:使用河豚算法對(duì)結(jié)果進(jìn)行加密:
Blowfish(secret_key, {0, 9, 3, 6, 2, 7, 5, 4})步驟4:結(jié)合初始化向量和密文。 如果上一步中的Blowfish函數(shù)結(jié)果為1, 2, 3, 4, 5, 6, 7, 8 ,則密文為:
1, 8, 2, 7, 3, 6, 4, 5, 1, 2, 3, 4, 5, 6, 7, 8
最后一塊–填充
分組密碼能夠加密固定長(zhǎng)度的消息,而最后一個(gè)分組通常比該分組短。 由于密碼無法加密,因此我們需要一種在消息末尾添加其他字節(jié)的方法。
Shiro默認(rèn)使用PKCS#5填充。 每個(gè)字節(jié)等于填充的長(zhǎng)度:
- 如果最后一塊太短,請(qǐng)計(jì)算丟失的字節(jié)數(shù),并用該數(shù)字填充丟失的字節(jié)。
- 如果最后一個(gè)塊的大小正確,則將其視為丟失整個(gè)塊的消息。 向其添加一個(gè)新的填充塊。 每個(gè)字節(jié)都等于塊大小。
示例1:假設(shè)秘密消息有三個(gè)塊,我們正在嘗試使用Blowfish-CBC對(duì)其進(jìn)行加密。 最后的塊是字節(jié)數(shù)組1, 1, 1, 1 。 填充塊:
1, 1, 1, 1, 4, 4, 4, 4示例2:假設(shè)該秘密消息有三個(gè)塊,我們正在嘗試使用Blowfish-CBC對(duì)其進(jìn)行加密。 最后一個(gè)塊是字節(jié)數(shù)組8, 7, 6, 5, 4, 3, 2, 1 。 最后一塊和填充:
8, 7, 6, 5, 4, 3, 2, 1, 8, 8, 8, 8, 8, 8, 8, 8進(jìn)攻
最后,我們準(zhǔn)備展示對(duì)基于CBC的密碼的兩種不同攻擊,并證明問題是真實(shí)的。 我們的樣本項(xiàng)目包含針對(duì)AES-CBC和Blowfish-CBC密碼的兩種攻擊的測(cè)試案例。
第一部分說明如何將加密文本的開頭更改為我們選擇的任何消息。 第二小節(jié)介紹了如何解密密文。
數(shù)據(jù)篡改
僅當(dāng)攻擊者已經(jīng)知道加密消息的內(nèi)容時(shí) ,才可能進(jìn)行數(shù)據(jù)篡改攻擊。 這樣的攻擊者可以將第一個(gè)消息塊更改為他希望的任何內(nèi)容。
特別是可以:
- 更改AES-CBC加密消息的前16個(gè)字節(jié),
- 更改Blowfish-CBC加密郵件的前8個(gè)字節(jié)。
潛在危險(xiǎn)
這種攻擊是否危險(xiǎn),在很大程度上取決于情況。
如果您使用密碼通過網(wǎng)絡(luò)發(fā)送密碼,那么數(shù)據(jù)篡改并不是那么危險(xiǎn)。 最壞的情況是,合法用戶的登錄將被拒絕。 同樣,如果加密的數(shù)據(jù)存儲(chǔ)在某些只讀存儲(chǔ)中,則不必?fù)?dān)心數(shù)據(jù)被篡改。
但是,如果要通過網(wǎng)絡(luò)發(fā)送銀行訂單,則數(shù)據(jù)篡改是真正的威脅。 如果有人將消息Pay Mark 100$更改為Pay Tom 9999$ ,Tom將獲得9999 $,而他不應(yīng)該得到。
攻擊
加密的消息分為三個(gè)部分:
- 隨機(jī)初始向量
- 第一組密文,
- 消息的其余部分。
接收者使用塊密文解密第一個(gè)密文塊。 這給他message block?initial vector 。 要獲取消息,他必須將此值與初始向量進(jìn)行異或運(yùn)算:
message block ? initial vector ? initial vector = message block初始向量與消息一起傳輸,主動(dòng)攻擊者可以更改它。 如果攻擊者用another iv替換了原始初始向量,則接收者將解密另一條消息:
message block ? initial vector ? another iv = another message重新排列前面的等式,您將得到:
another iv = message block ? initial vector ? another message如果攻擊者同時(shí)知道加密消息的初始向量和內(nèi)容,則可以將消息修改為所需的任何內(nèi)容。 他要做的就是將已知消息內(nèi)容和所需消息都與原始初始向量異或。
解密修改后的密文的任何人都將獲得修改后的消息,而不是原始消息。
測(cè)試用例
我們創(chuàng)建了一個(gè)簡(jiǎn)單的測(cè)試案例,演示了對(duì)使用AES-CBC加密的消息的這種攻擊。
想象一下,攻擊者捕獲了一封加密的電子郵件,并且以某種方式知道其中的內(nèi)容:
//original message private static final String EMAIL = "Hi,\n" +"send Martin all requested money please.\n\n" +"With Regards, \n" +"Accounting\n";攻擊者只能更改消息的前16個(gè)字節(jié),因此他決定將資金重定向到Andrea:
//changed message private static final String MODIFICATION = "Hi,\n" +"give Andrea all requested money please.\n\n" +"With Regards, \n" +"Accounting\n";以下測(cè)試用例對(duì)消息進(jìn)行加密并修改密文。 修改后的密文被解密并與預(yù)期消息進(jìn)行比較:
@Test public void testModifiedMessage_AES() {//create cipher and the secret key StringCipherService cipher = new StringCipherService(new AesCipherService());byte[] key = cipher.generateNewKey();//encrypt the messagebyte[] ciphertext = cipher.encrypt(EMAIL, key);//attack: modify the encrypted messagefor (int i = 0; i < 16; i++) {ciphertext[i] = (byte)(ciphertext[i] ^ MODIFICATION.getBytes()[i] ^ EMAIL.getBytes()[i]);}//decrypt and verifyString result = cipher.decrypt(ciphertext, key);assertEquals(MODIFICATION, result); }當(dāng)然,可以對(duì)河豚CBC進(jìn)行類似的攻擊。 這次我們只能更改前8個(gè)字節(jié):
@Test public void testModifiedMessage_Blowfish() {String email = "Pay 100 dollars to them, but nothing more. Accounting\n";StringCipherService cipher = new StringCipherService(new BlowfishCipherService());byte[] key = cipher.generateNewKey();byte[] ciphertext = cipher.encrypt(email, key);String modified = "Pay 900 dollars to them, but nothing more. Accounting\n";for (int i = 0; i < 8; i++) {ciphertext[i] = (byte)(ciphertext[i] ^ modified.getBytes()[i] ^ email.getBytes()[i]);}String result = cipher.decrypt(ciphertext, key);assertEquals(modified, result); }解密密碼
第二次攻擊使攻擊者可以解密該秘密消息。 僅當(dāng)解密機(jī)密消息的應(yīng)用程序與攻擊者合作時(shí),才有可能進(jìn)行攻擊。
填充Oracle
攻擊者會(huì)創(chuàng)建許多偽密文,并將其發(fā)送給收件人。 當(dāng)他嘗試解密這些消息時(shí),將發(fā)生以下情況之一:
- 密文解密為毫無意義的垃圾,
- 修改后的消息將根本不是有效的密文。
如果應(yīng)用程序在兩種情況下的行為均相同,則一切正常。 如果行為不同,則攻擊者能夠解密密文。 基于CBC的密文只有一種錯(cuò)誤的方法-如果填充錯(cuò)誤。
例如,如果密文包含加密的密碼,則當(dāng)解密的密碼錯(cuò)誤時(shí),易受攻擊的服務(wù)器可能會(huì)以“拒絕登錄”進(jìn)行響應(yīng),而在密文無效的情況下,則可能會(huì)出現(xiàn)運(yùn)行時(shí)異常。 在這種情況下,攻擊者可以恢復(fù)密碼。
大概的概念
每條虛假消息都有兩個(gè)部分:一個(gè)虛假的初始向量和一個(gè)消息塊。 兩者都發(fā)送到服務(wù)器。 如果它回答“正確填充”,那么我們知道:
message ? original iv ? fake iv = valid padding上述方程式中唯一未知的變量是消息。 original iv是先前的密文塊, fake iv是由我們創(chuàng)建的,有效填充是1或2, 2或3, 3, 3或...或8, 8, ..., 8等之一。
因此,我們可以將塊內(nèi)容計(jì)算為:
message = valid padding ? original iv ? fake iv算法
從恢復(fù)最后一個(gè)塊字節(jié)開始。 每個(gè)偽初始向量都以0開頭,以不同的最后字節(jié)結(jié)尾。 這樣,我們幾乎可以確定服務(wù)器僅在以1結(jié)尾的消息上回答“向右填充”。使用上一章公式計(jì)算最后一個(gè)塊字節(jié)。
獲取消息的倒數(shù)第二個(gè)字節(jié)非常相似。 唯一的區(qū)別是我們必須制作一個(gè)密文,該密文解密為第二個(gè)最短的填充2, 2 。 消息的最后一個(gè)字節(jié)是已知的,因此將2強(qiáng)制為最后一個(gè)值很容易。 初始向量的開頭并不重要,請(qǐng)將其設(shè)置為0。
然后,我們嘗試初始向量的倒數(shù)第二個(gè)字節(jié)的所有可能值。 服務(wù)器回答“正確填充”后,我們可以從與前面相同的公式中獲取倒數(shù)第二個(gè)消息字節(jié): original iv ? fake iv ? 2 original iv ? fake iv ? 2 original iv ? fake iv ? 2 。
我們計(jì)算倒數(shù)第三個(gè)消息字節(jié)出來的假消息與填充3, 3, 3 ; 用填充4、4、4、4填充消息中的第四4, 4, 4, 4 ; 以此類推,直到整個(gè)塊被解密為止。
測(cè)試用例
易受攻擊的服務(wù)器使用PaddingOraculum類進(jìn)行模擬。 此類的每個(gè)實(shí)例都會(huì)生成一個(gè)隨機(jī)密鑰,并將其保密。 它僅公開兩個(gè)公共方法:
- byte[] encrypt(String message) –用密鑰加密一個(gè)字符串,
- boolean verifyPadding(byte[] ciphertext) –返回填充是否正確。
填充oraculum攻擊是用decryptLastBlock方法實(shí)現(xiàn)的。 該方法解密加密消息的最后一塊:
private String decryptLastBlock(PaddingOraculum oraculum, byte[] ciphertext) {// extract relevant part of the ciphertextbyte[] ivAndBlock = getLastTwoBlocks(ciphertext, oraculum.getBlockSize());// modified initial vectorbyte[] ivMod = new byte[oraculum.getBlockSize()];Arrays.fill(ivMod, (byte) 0);// Start with last byte of the last block and // continue to the first byte.for (int i = oraculum.getBlockSize()-1; i >= 0; i--) {// add padding to the initial vector int expectedPadding = oraculum.getBlockSize() - i;xorPad(ivMod, expectedPadding);// loop through possible values of ivModification[i]for (ivMod[i] = -128; ivMod[i] < 127; ivMod[i]++) {// create fake message and verify its paddingbyte[] modifiedCiphertext = replaceBeginning(ivAndBlock, ivMod);if (oraculum.verifyPadding(modifiedCiphertext)) {// we can stop looping// the ivModification[i] =// = solution ^ expectedPadding ^ ivAndBlock[i]break;}}// remove the padding from the initial vectorxorPad(ivMod, expectedPadding);}// modified initial vector now contains the solution xor // original initial vectorString result = "";for (int i = 0; i < ivMod.length; i++) {ivMod[i] = (byte) (ivMod[i] ^ ivAndBlock[i]);result += (char) ivMod[i];}return result; }我們的示例項(xiàng)目包含兩個(gè)測(cè)試用例 。 一個(gè)人用AES-CBC加密消息,然后使用填充字眼到密文的最后一塊。 另一個(gè)對(duì)河豚-CBC也做同樣的事情。
解密Blowfish-CBC測(cè)試案例:
@Test public void testPaddingOracle_Blowfish() {String message = "secret message!";PaddingOraculum oraculum = new PaddingOraculum(new BlowfishCipherService());//Oraculum encrypts the message with a secret key.byte[] ciphertext = oraculum.encrypt(message);//use oraculum to decrypt the messageString result = decryptLastBlock(oraculum, ciphertext);//the original message had padding 1assertEquals("essage!"+(char)1, result); }資源資源
其他相關(guān)資源:
- 免費(fèi)在線斯坦福加密課程 。
- 從2002年開始用padding oracle攻擊的原始文件。
- 填充oracle攻擊的一個(gè)很好的替代解釋 。
- 解釋了對(duì)CBC的野獸襲擊 。 它基于padding oracle攻擊。
- 關(guān)于常見密碼錯(cuò)誤的堆棧交換線程 。
結(jié)束
沒有密碼可以絕對(duì)安全地防御所有可能的攻擊。 相反,它們僅提供針對(duì)定義明確的攻擊類別的保護(hù)。 只有對(duì)系統(tǒng)的潛在威脅與密碼強(qiáng)度匹配時(shí),密碼才是安全的。
可以通過兩種方式來防御主動(dòng)攻擊:
- 通過設(shè)計(jì)使主動(dòng)攻擊不可能。
- 使用經(jīng)過身份驗(yàn)證的加密。
使用經(jīng)過身份驗(yàn)證的加密可以說更容易,并且應(yīng)該是首選。 排除主動(dòng)攻擊者容易出錯(cuò),而且風(fēng)險(xiǎn)更大。
Github上提供了本文中使用的所有代碼示例。
參考: This is Stuff博客上的JCG合作伙伴 Maria Jurcovicova提供的Java安全加密 。
翻譯自: https://www.javacodegeeks.com/2012/05/secure-encryption-in-java.html
總結(jié)
以上是生活随笔為你收集整理的Java中的安全加密的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Apache Shiro第1部分–基础
- 下一篇: Java枚举益智游戏