摘要:系列密碼學(xué)二傳送門密碼學(xué)一基礎(chǔ)密碼學(xué)算法分類消息編碼消息摘要類,類,對(duì)稱密碼非對(duì)稱密碼數(shù)字簽名五元組明文原始信息。非對(duì)稱密碼包提供給,,等非對(duì)稱加密算法。對(duì)稱加密算法在分布式網(wǎng)絡(luò)系統(tǒng)上使用較為困難,主要是因?yàn)槊荑€管理困難,使用成本較高。
前言
最近一場(chǎng)面試,面試官問了我
對(duì)稱加密與非對(duì)稱加密的問題,雖然曾經(jīng)看過一些內(nèi)容,但是沒有系統(tǒng)的整理,所以當(dāng)被問的時(shí)候,腦子里一片空白,沒有回答上來。因此,在這里重新梳理一下密碼學(xué)的知識(shí)點(diǎn),夯實(shí)一下基礎(chǔ)。
killBase系列 -- 密碼學(xué)(二) 傳送門
密碼學(xué) 一、基礎(chǔ)
密碼學(xué)算法分類:
消息編碼:Base64
消息摘要:MD類, SHA類,MAC
對(duì)稱密碼:DES,3DES,AES
非對(duì)稱密碼:RSA,DH
數(shù)字簽名:RSASignature,DSASignature
五元組
1)明文:原始信息。
2)加密算法:以密鑰為參數(shù),對(duì)明文進(jìn)行多種置換和轉(zhuǎn)換的規(guī)則和步驟,變換結(jié)果為密文。
3)解密算法:加密算法的逆變換,以密文為輸入、密鑰為參數(shù),變換結(jié)果為明文。:
4)密鑰:加密與解密算法的參數(shù),直接影響對(duì)明文進(jìn)行變換的結(jié)果。
5)密文:對(duì)明文進(jìn)行變換的結(jié)果。
Java編程中常用類 -- java.security 包
消息編碼:BASE64Encoder,BASE64Decoder -- java.util
消息摘要:MessageDigest
對(duì)稱密碼:KeyGenerator,SeretkeyFactory -- javax.crypto 包(提供給AES,DES,3DES,MD5,SHA1等 對(duì)稱 和 單向加密算法。),Cipher
非對(duì)稱密碼:KeyPairGenerator,KeyFactory -- java.security 包(提供給DSA,RSA, EC等 非對(duì)稱加密算法。),KeyPair,PublicKey,PrivateKey,Cipher
數(shù)字重命名:Signature
常用開源工具
Commons.Codec
Bouncy.Castle
二、Base64 算法Base64 基于64個(gè)字符編碼算法,以任意 8 位字節(jié)序列組合描述形式 , BASE加密后產(chǎn)生的字節(jié)位數(shù)是8的倍數(shù),如果不夠位數(shù)以=符號(hào)填充。對(duì)此 Base64 算法有一套字符映射表。
使用方法:
// 獲取 Base64.Encoder encoder = Base64.getEncoder(); Base64.Decoder decoder = Base64.getDecoder(); // 加密 public byte[] encode(byte[] src); * @param src * the byte array to encode * @param dst * the output byte array * @return The number of bytes written to the output byte array public int encode(byte[] src,byte[] dst); public String encodeToString(byte[] src); public ByteBuffer encode(ButeBuffer buffer); // 解密 public byte[] decode(byte[] src); * @param src * the byte array to encode * @param dst * the output byte array * @return The number of bytes written to the output byte array public int decode(byte[] src,byte[] dst); public byte[] decode(String src); public ByteBuffer decode(ButeBuffer buffer);三、消息摘要
介紹:又稱為 哈希算法。唯一對(duì)應(yīng)一個(gè)消息或文體固定長度值,由一個(gè)單向的Hash加密函數(shù)對(duì)消息進(jìn)行作用而產(chǎn)生。
分類: MD(Message Digest) 消息摘要算法,SHA(Secure Hash Algorithm) 安全散列算法, MAC(Message Authentication Code):消息認(rèn)證算法
主要方法:
// xxx 可以為 md5,sha MessageDigest.getInstance("xxx")1. MD5算法
原理:
首先需要對(duì)信息進(jìn)行填充,使其位長對(duì)512求余的結(jié)果等于448。
因此,信息的位長(Bits Length)將被擴(kuò)展至N*512+448,N為一個(gè)非負(fù)整數(shù),N可以是零。
填充的方法如下,在信息的后面填充一個(gè)1和無數(shù)個(gè)0,直到滿足上面的條件時(shí)才停止用0對(duì)信息的填充。
然后,在這個(gè)結(jié)果后面附加一個(gè)以64位二進(jìn)制表示的填充前信息長度。
經(jīng)過這兩步的處理,信息的位長=N512+448+64=(N+1)512,即長度恰好是512的整數(shù)倍
MD5以512位分組來處理輸入的信息,且每一分組又被劃分為16個(gè)32位子分組,經(jīng)過了一系列的處理后,算法的輸出由四個(gè)32位分組組成,將這四個(gè)32位分組級(jí)聯(lián)后將生成一個(gè)128位散列值。
代碼實(shí)現(xiàn)
public class MD5Util { /*** * MD5加密 生成32位md5碼 * @param 待加密字符串 * @return 返回32位md5碼 */ public static String md5Encode(String inStr) throws Exception { MessageDigest md5 = null; try { md5 = MessageDigest.getInstance("MD5"); } catch (Exception e) { System.out.println(e.toString()); e.printStackTrace(); return ""; } byte[] byteArray = inStr.getBytes("UTF-8"); byte[] md5Bytes = md5.digest(byteArray); StringBuffer hexValue = new StringBuffer(); // 轉(zhuǎn)化為 16 進(jìn)制 // 原理 : byte 為 8 字節(jié)。 0xff --> 11111111 // byte&0xff 如果小于16 則小于00010000 // 所以由 toHexString() 只能轉(zhuǎn)化為 1 位,所以要在前面加上 ‘0’。再加上實(shí)際的值。 for (int i = 0; i < md5Bytes.length; i++) { int val = ((int) md5Bytes[i]) & 0xff; if (val < 16) { hexValue.append("0"); } hexValue.append(Integer.toHexString(val)); } return hexValue.toString(); } }2. SHA 算法
原理:接收一段明文,然后以一種不可逆的方式將它轉(zhuǎn)換成一段(通常更小)密文,也可以簡(jiǎn)單的理解為取一串輸入碼(稱為預(yù)映射或信息),并把它們轉(zhuǎn)化為長度較短、位數(shù)固定的輸出序列即散列值(也稱為信息摘要或信息認(rèn)證代碼)的過程。
特點(diǎn):該算法輸入報(bào)文的長度不限,產(chǎn)生的輸出是一個(gè)160位的報(bào)文摘要。輸入是按 512 位的分組進(jìn)行處理的。
作用:通過散列算法可實(shí)現(xiàn)數(shù)字簽名實(shí)現(xiàn),數(shù)字簽名的原理是將要傳送的明文通過一種函數(shù)運(yùn)算(Hash)轉(zhuǎn)換成報(bào)文摘要(不同的明文對(duì)應(yīng)不同的報(bào)文摘要),報(bào)文摘要加密后與明文一起傳送給接受方,接受方將接受的明文產(chǎn)生新的報(bào)文摘要與發(fā)送方的發(fā)來報(bào)文摘要解密比較,比較結(jié)果一致表示明文未被改動(dòng),如果不一致表示明文已被篡改。
代碼實(shí)現(xiàn)
public class SHAUtil { /*** * SHA加密 生成40位SHA碼 * @param 待加密字符串 * @return 返回40位SHA碼 */ public static String shaEncode(String inStr) throws Exception { MessageDigest sha = null; try { sha = MessageDigest.getInstance("SHA"); } catch (Exception e) { System.out.println(e.toString()); e.printStackTrace(); return ""; } byte[] byteArray = inStr.getBytes("UTF-8"); byte[] md5Bytes = sha.digest(byteArray); StringBuffer hexValue = new StringBuffer(); for (int i = 0; i < md5Bytes.length; i++) { int val = ((int) md5Bytes[i]) & 0xff; if (val < 16) { hexValue.append("0"); } hexValue.append(Integer.toHexString(val)); } return hexValue.toString(); }3. HMAC 算法
原理:用公開函數(shù)和密鑰產(chǎn)生一個(gè)固定長度的值作為認(rèn)證標(biāo)識(shí),用這個(gè) 標(biāo)識(shí)鑒別消息的完整性。使用一個(gè)密鑰生成一個(gè)固定大小的小數(shù)據(jù)塊,即MAC,并將其加入到消息中,然后傳輸。接收方利用與發(fā)送方共享的密鑰進(jìn)行鑒別認(rèn)證 等。
代碼實(shí)現(xiàn)
// 構(gòu)建密鑰 public static byte[] getSecretKey(){ // 初始化 KeyGenerator keyGen = null; try { keyGen = KeyGenerator.getInstance("HmacMD5"); } catch (NoSuchAlgorithmException e1) { e1.printStackTrace(); } // 產(chǎn)生密鑰 SecretKey secretKey1 = keyGen.generateKey(); // 得到密鑰字節(jié)數(shù)組 byte[] key = secretKey1.getEncoded(); return key; } // 執(zhí)行消息摘要 public static void doHMAC(byte[] data,String key){ // 從字節(jié)數(shù)組還原 SecretKey secretKey2 = new SecretKeySpec(key,"HmacMD5"); try { // 實(shí)例化 Mac Mac mac = Mac.getInstance("HmacMD5"); // 密鑰初始化 Mac mac.init(secretKey2); // 執(zhí)行消息摘要 byte[] result = mac.doFinal(data); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } }4. SHA 與 MD5比較
1)對(duì)強(qiáng)行攻擊的安全性:最顯著和最重要的區(qū)別是SHA-1摘要比MD5摘要長32 位。使用強(qiáng)行技術(shù),產(chǎn)生任何一個(gè)報(bào)文使其摘要等于給定報(bào)摘要的難度對(duì)MD5是2^128數(shù)量級(jí)的操作,而對(duì)SHA-1則是2^160數(shù)量級(jí)的操作。這樣,SHA-1對(duì)強(qiáng)行攻擊有更大的強(qiáng)度。
2)對(duì)密碼分析的安全性:由于MD5的設(shè)計(jì),易受密碼分析的攻擊,SHA-1顯得不易受這樣的攻擊。
3)速度:在相同的硬件上,SHA-1的運(yùn)行速度比MD5慢。
定義:在對(duì)稱加密算法中,數(shù)據(jù)發(fā)信方將明文(原始數(shù)據(jù))和加密密鑰(mi yue)一起經(jīng)過特殊加密算法處理后,使其變成復(fù)雜的加密密文發(fā)送出去。
收信方收到密文后,若想解讀原文,則需要使用加密用過的密鑰及相同算法的逆算法對(duì)密文進(jìn)行解密,才能使其恢復(fù)成可讀明文。
在對(duì)稱加密算法中,使用的密鑰只有一個(gè),發(fā)收信雙方都使用這個(gè)密鑰對(duì)數(shù)據(jù)進(jìn)行加密和解密,這就要求解密方事先必須知道加密密鑰。
優(yōu)缺點(diǎn)
優(yōu)點(diǎn):算法公開、計(jì)算量小、加密速度快、加密效率高。
缺點(diǎn):
(1)交易雙方都使用同樣鑰匙,安全性得不到保證。
(2)每對(duì)用戶每次使用對(duì)稱加密算法時(shí),都需要使用其他人不知道的惟一鑰匙,這會(huì)使得發(fā)收信雙方所擁有的鑰匙數(shù)量呈幾何級(jí)數(shù)增長,
密鑰管理成為用戶的負(fù)擔(dān)。對(duì)稱加密算法在分布式網(wǎng)絡(luò)系統(tǒng)上使用較為困難,主要是因?yàn)槊荑€管理困難,使用成本較高。
常用的對(duì)稱加密算法。
DES(Data Encryption Standard):數(shù)據(jù)加密標(biāo)準(zhǔn),速度較快,適用于加密大量數(shù)據(jù)的場(chǎng)合。
3DES(Triple DES):是基于DES,對(duì)一塊數(shù)據(jù)用三個(gè)不同的密鑰進(jìn)行三次加密,強(qiáng)度更高。
AES(Advanced Encryption Standard):高級(jí)加密標(biāo)準(zhǔn),是下一代的加密算法標(biāo)準(zhǔn),速度快,安全級(jí)別最高
對(duì)稱密碼常用的數(shù)學(xué)運(yùn)算
移位和循環(huán)移位
移位就是將一段數(shù)碼按照規(guī)定的位數(shù)整體性地左移或右移。循環(huán)右移就是當(dāng)右移時(shí),把數(shù)碼的最后的位移到數(shù)碼的最前頭,循環(huán)左移正相反。例如,對(duì)十進(jìn)制數(shù)碼12345678循環(huán)右移1位(十進(jìn)制位)的結(jié)果為81234567,而循環(huán)左移1位的結(jié)果則為23456781。
置換
就是將數(shù)碼中的某一位的值根據(jù)置換表的規(guī)定,用另一位代替。它不像移位操作那樣整齊有序,看上去雜亂無章。這正是加密所需,被經(jīng)常應(yīng)用。
擴(kuò)展
就是將一段數(shù)碼擴(kuò)展成比原來位數(shù)更長的數(shù)碼。擴(kuò)展方法有多種,例如,可以用置換的方法,以擴(kuò)展置換表來規(guī)定擴(kuò)展后的數(shù)碼每一位的替代值。
壓縮
就是將一段數(shù)碼壓縮成比原來位數(shù)更短的數(shù)碼。壓縮方法有多種,例如,也可以用置換的方法,以表來規(guī)定壓縮后的數(shù)碼每一位的替代值。
異或
這是一種二進(jìn)制布爾代數(shù)運(yùn)算。異或的數(shù)學(xué)符號(hào)為⊕ ,它的運(yùn)算法則如下:
1⊕ 1 = 0 0⊕ 0 = 0 1⊕ 0 = 1 0⊕ 1 = 1
也可以簡(jiǎn)單地理解為,參與異或運(yùn)算的兩數(shù)位如相等,則結(jié)果為0,不等則為1。
迭代
迭代就是多次重復(fù)相同的運(yùn)算,這在密碼算法中經(jīng)常使用,以使得形成的密文更加難以破解。
分組加密
參考 分組加密的四種模式
ECB模式 -- 電子密碼本模式
CBC模式 -- 密碼分組鏈接模式
CFB模式 -- 密文反饋模式
OFB模式 -- 輸出反饋模式
CTR模式 -- 計(jì)數(shù)器模式
常用的填充方式
在Java進(jìn)行DES、3DES和AES三種對(duì)稱加密算法時(shí),常采用的是NoPadding(不填充)、Zeros填充(0填充)、PKCS5Padding填充。
ZerosPadding
全部填充為0的字節(jié),結(jié)果如下:
F1 F2 F3 F4 F5 F6 F7 F8 //第一塊
F9 00 00 00 00 00 00 00 //第二塊
PKCS5Padding
每個(gè)填充的字節(jié)都記錄了填充的總字節(jié)數(shù),結(jié)果如下:
F1 F2 F3 F4 F5 F6 F7 F8 //第一塊
F9 07 07 07 07 07 07 07 //第二塊
注: 如果
1. DES(Data Encryption Standard)DES算法的入口參數(shù)有三個(gè):Key、Data、Mode。
Key為8個(gè)字節(jié)共64位,其中密鑰 56 位,校驗(yàn)位 8 位(每組的 第8位都被用作奇偶校驗(yàn)),是DES算法的工作密鑰;
Data也為8個(gè)字節(jié)64位,是要被加密或被解密的數(shù)據(jù);
Mode為DES的工作方式,有兩種:加密或解密。
簡(jiǎn)略版:
首先要生成一套加密密鑰,從用戶處取得一個(gè)64位長的密碼口令,然后通過等分、移位、選取和迭代形成一套16個(gè)加密密鑰,分別供每一輪運(yùn)算中使用。
過程 1,2
DES對(duì)64位(bit)的明文分組M進(jìn)行操作,M經(jīng)過一個(gè)初始置換IP,置換成m0。將m0明文分成左半部分和右半部分m0 = (L0,R0),各32位長。然后進(jìn)行16輪完全相同的運(yùn)算(迭代),這些運(yùn)算被稱為函數(shù)f,在每一輪運(yùn)算過程中數(shù)據(jù)與相應(yīng)的密鑰結(jié)合。
過程 4
在每一輪中,密鑰位移位,然后再從密鑰的56位中選出48位。通過一個(gè)擴(kuò)展置換將數(shù)據(jù)的右半部分擴(kuò)展成48位,并通過一個(gè)異或操作替代成新的48位數(shù)據(jù),再將其壓縮置換成32位。這四步運(yùn)算構(gòu)成了函數(shù)f。然后,通過另一個(gè)異或運(yùn)算,函數(shù)f的輸出與左半部分結(jié)合,其結(jié)果成為新的右半部分,原來的右半部分成為新的左半部分。將該操作重復(fù)16次。
過程 3 ,5 ,6 ,7 , 8 , 9
經(jīng)過16輪迭代后,左,右半部分合在一起經(jīng)過一個(gè)逆置換(數(shù)據(jù)整理),恢復(fù)原先的順序,這樣就完成了加密過程。
過程 10.
詳細(xì)版請(qǐng)見 附錄
加密和解密使用相同的算法!
DES加密和解密唯一的不同是密鑰的次序相反。如果各輪加密密鑰分別是K1,K2,K3…K16,那么解密密鑰就是K16,K15,K14…K1。這也就是DES被稱為對(duì)稱算法的理由吧。
DES算法中只用到64位密鑰中的其中56位,而第8、16、24、......64位8個(gè)位并未參與DES運(yùn)算
3DES(或稱為Triple DES)
原理:
使用3條56位的密鑰對(duì) 數(shù)據(jù)進(jìn)行三次加密。
相關(guān)的類:
// 生成密鑰 KeyGenerator,SecretKeyFactory // 密鑰 SecretKey , SecretKeySpec // 密碼 Cipher
這里重點(diǎn)講一下 Cipher 類
首先要設(shè)置參數(shù)
Cipher.getInstance(加解密算法,加解密模式,填充模式)
初始化
Cipher.init(加解密模式 -- Cypher.ENCRIPT/DECRYPT,密鑰)
完成加解密
Cipher.doFinal(bytes) -- 將bytes 內(nèi)容 加密/解密 然后返回。
這里使用 SecretKeyFactory的密鑰 選擇CBC模式 進(jìn)行加解密。
public class DESCryptography { public static void main(String[] args) { // TODO Auto-generated method stub String content="aaaaaaaabbbbbbbbaaaaaaaa"; String key="01234567"; System.out.println("加密前:"+byteToHexString(content.getBytes())); byte[] encrypted=DES_CBC_Encrypt(content.getBytes(), key.getBytes()); System.out.println("加密后:"+byteToHexString(encrypted)); byte[] decrypted=DES_CBC_Decrypt(encrypted, key.getBytes()); System.out.println("解密后:"+byteToHexString(decrypted)); } public static byte[] DES_CBC_Encrypt(byte[] content, byte[] keyBytes){ try { DESKeySpec keySpec=new DESKeySpec(keyBytes); SecretKeyFactory keyFactory=SecretKeyFactory.getInstance("DES"); SecretKey key=keyFactory.generateSecret(keySpec); Cipher cipher=Cipher.getInstance("DES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(keySpec.getKey())); byte[] result=cipher.doFinal(content); return result; } catch (Exception e) { // TODO Auto-generated catch block System.out.println("exception:"+e.toString()); } return null; } public static byte[] DES_CBC_Decrypt(byte[] content, byte[] keyBytes){ try { DESKeySpec keySpec=new DESKeySpec(keyBytes); SecretKeyFactory keyFactory=SecretKeyFactory.getInstance("DES"); SecretKey key=keyFactory.generateSecret(keySpec); Cipher cipher=Cipher.getInstance("DES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(keyBytes)); byte[] result=cipher.doFinal(content); return result; } catch (Exception e) { // TODO Auto-generated catch block System.out.println("exception:"+e.toString()); } return null; } public static String byteToHexString(byte[] bytes) { StringBuffer sb = new StringBuffer(bytes.length); String sTemp; for (int i = 0; i < bytes.length; i++) { sTemp = Integer.toHexString(0xFF & bytes[i]); if (sTemp.length() < 2) sb.append(0); sb.append(sTemp.toUpperCase()); } return sb.toString(); } private static byte toByte(char c) { byte b = (byte) "0123456789ABCDEF".indexOf(c); return b; } }2. AES(Advanced Encryption Standard)
有時(shí)間 再寫。。。 看了一天的 加密 ,累死。。。
五、非對(duì)稱加密 1. 基礎(chǔ)定義:需要兩個(gè)密鑰,一個(gè)是公開密鑰,另一個(gè)是私有密鑰;一個(gè)用作加密的時(shí)候,另一個(gè)則用作解密。
使用其中一個(gè)密鑰把明文加密后所得的密文,只能用相對(duì)應(yīng)的另一個(gè)密鑰才能解密得到原本的明文;甚至連最初用來加密的密鑰也不能用作解密。
由于加密和解密需要兩個(gè)不同的密鑰,故被稱為非對(duì)稱加密
數(shù)論知識(shí):
非對(duì)稱加密運(yùn)用了一部分?jǐn)?shù)論知識(shí),有興趣的自己去看下。。。 這里提供一下鏈接。
阮一峰大神寫了一部分,可以幫助理解
一、互質(zhì)關(guān)系:
2. RSA 算法如果兩個(gè)正整數(shù),除了1以外,沒有其他公因子,我們就稱這兩個(gè)數(shù)是互質(zhì)關(guān)系(coprime)。比如,15和32沒有公因子,所以它們是互質(zhì)關(guān)系。這說明,不是質(zhì)數(shù)也可以構(gòu)成互質(zhì)關(guān)系。
二、歐拉函數(shù)
三、歐拉定理)
四、模反元素(模逆元)
五、擴(kuò)展歐幾里得算法
隨機(jī)選擇兩個(gè)不相等的質(zhì)數(shù) p 和 q
= 61, q = 53
計(jì)算 p 和 q 的乘積 n
= 61*53 = 3233
計(jì)算 n 的歐拉函數(shù) φ(n)
φ(n) = (p-1)(q-1) = 60 * 52 = 3120
隨機(jī)選擇一個(gè)整數(shù) e , 條件是 1 < e < φ(n) , 且 e 與 φ(n) 互質(zhì)
= 17 ( 實(shí)際應(yīng)用中,常常選擇 65537 )
計(jì)算 e 對(duì)于 φ(n) 的模反元素 d
所謂"模反元素"就是指有一個(gè)整數(shù)d,可以使得ed被φ(n)除的余數(shù)為1。 ed ≡ 1 (mod φ(n))
ed - 1 = kφ(n)
于是,找到模反元素d,實(shí)質(zhì)上就是對(duì)下面這個(gè)二元一次方程求解。 ex + φ(n)y = 1 已知 e=17, φ(n)=3120, 17x + 3120y = 1 這個(gè)方程可以用"擴(kuò)展歐幾里得算法"求解,此處省略具體過程。總之,愛麗絲算出一組整數(shù)解為 (x,y)=(2753,-15),即 d=2753。 至此所有計(jì)算完成。
6. 將 n 和 e 封裝成公鑰, n 和 d 封裝成私鑰 公鑰 (3233,17), 私鑰 (3233,2753) 7. 加密與解密 - 加密用 (n , e) 加密信息 -- **明文**為 m , **m 小于 n** $m^e$ ≡ c (mod n) 公鑰是 (3233,17), m 假設(shè)為 65 $65^{17}$ ≡ 2790(mod 3233) 所以 c = 2790 - 解密用 (n , d) **密文** 為 c $c^d$ ≡ m(mod n) $2790^{2753}$ ≡ 65 (mod 3233) 所以 m = 65 8. 私鑰解密的證明 -- 有興趣的同學(xué)自己去找資料看下,也是數(shù)論的知識(shí)。 ##### 2.2 RSA 算法的可靠性 與 破解 以上密鑰的生成步驟,出現(xiàn)了六個(gè)數(shù)字 > p, q, n, φ(n), e, d 公鑰為 n, e 如果想要得到 d,需要進(jìn)行以下逆推
(1)ed≡1 (mod φ(n))。只有知道e和φ(n),才能算出d。
(2)φ(n)=(p-1)(q-1)。只有知道p和q,才能算出φ(n)。
(3)n=pq。只有將n因數(shù)分解,才能算出p和q。
所以 如果將 n 進(jìn)行 **因數(shù)分解**,就意味著私鑰被破解。 可是,大整數(shù)的因數(shù)分解,是一件非常困難的事情。目前,除了暴力破解,還沒有發(fā)現(xiàn)別的有效方法。 ** 注意:**這里說大整數(shù),不是 像上文 3233 這樣的數(shù)字,歷史上最大的已經(jīng)進(jìn)行因數(shù)分解的整數(shù)為
12301866845301177551304949
58384962720772853569595334
79219732245215172640050726
36575187452021997864693899
56474942774063845925192557
32630345373154826850791702
61221429134616704292143116
02221240479274737794080665
351419597459856902143413
它等于這樣兩個(gè)質(zhì)數(shù)的乘積
33478071698956898786044169
84821269081770479498371376
85689124313889828837938780
02287614711652531743087737
814467999489
×
36746043666799590428244633
79962795263227915816434308
76426760322838157396665112
79233373417143396810270092
798736308917
**破解:** 這里有一篇關(guān)于 RSA 破解的文章,有興趣的同學(xué)可以看一下。 [RSA計(jì)時(shí)攻擊](https://juejin.im/post/5937e8252f301e006b2c4e84) ##### 2.3 Java 實(shí)現(xiàn) **使用到的類**: java.security
// 生成 公鑰,密鑰
KeyPairGenerator --> KeyPair , KeyFactory --> RSA XXX Spec
// 公鑰 密鑰
KeyPair
RSAPublicKeySpec --> RSAPublicKey
RSAPrivateKeySpec --> RSAPrivateKey
// 密碼
Cipher -- 1.Cipher.getInstance("RSA")
2.init(mode, key) 3.cipher.doFinal()
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub HashMapmap = RSAUtils.getKeys(); //生成公鑰和私鑰 RSAPublicKey publicKey = (RSAPublicKey) map.get("public"); RSAPrivateKey privateKey = (RSAPrivateKey) map.get("private"); //模 String modulus = publicKey.getModulus().toString(); //公鑰指數(shù) String public_exponent = publicKey.getPublicExponent().toString(); //私鑰指數(shù) String private_exponent = privateKey.getPrivateExponent().toString(); //明文 String ming = "123456789"; //使用模和指數(shù)生成公鑰和私鑰 RSAPublicKey pubKey = RSAUtils.getPublicKey(modulus, public_exponent); RSAPrivateKey priKey = RSAUtils.getPrivateKey(modulus, private_exponent); //加密后的密文 String mi = RSAUtils.encryptByPublicKey(ming, pubKey); System.err.println(mi); //解密后的明文 ming = RSAUtils.decryptByPrivateKey(mi, priKey); System.err.println(ming); }
**RSAUtils.java**
public class RSAUtils {
/** * 生成公鑰和私鑰 * @throws NoSuchAlgorithmException * */ public static HashMapgetKeys() throws NoSuchAlgorithmException{ HashMap map = new HashMap (); KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); keyPairGen.initialize(1024); KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); map.put("public", publicKey); map.put("private", privateKey); return map; } /** * 使用模和指數(shù)生成RSA公鑰 * 注意:【此代碼用了默認(rèn)補(bǔ)位方式,為RSA/None/PKCS1Padding,不同JDK默認(rèn)的補(bǔ)位方式可能不同,如Android默認(rèn)是RSA * /None/NoPadding】 * * @param modulus * 模 * @param exponent * 指數(shù) * @return */ public static RSAPublicKey getPublicKey(String modulus, String exponent) { try { BigInteger b1 = new BigInteger(modulus); BigInteger b2 = new BigInteger(exponent); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2); return (RSAPublicKey) keyFactory.generatePublic(keySpec); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 使用模和指數(shù)生成RSA私鑰 * 注意:【此代碼用了默認(rèn)補(bǔ)位方式,為RSA/None/PKCS1Padding,不同JDK默認(rèn)的補(bǔ)位方式可能不同,如Android默認(rèn)是RSA * /None/NoPadding】 * * @param modulus * 模 * @param exponent * 指數(shù) * @return */ public static RSAPrivateKey getPrivateKey(String modulus, String exponent) { try { BigInteger b1 = new BigInteger(modulus); BigInteger b2 = new BigInteger(exponent); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2); return (RSAPrivateKey) keyFactory.generatePrivate(keySpec); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 公鑰加密 * * @param data * @param publicKey * @return * @throws Exception */ public static String encryptByPublicKey(String data, RSAPublicKey publicKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); // 模長 int key_len = publicKey.getModulus().bitLength() / 8; // 加密數(shù)據(jù)長度 <= 模長-11 String[] datas = splitString(data, key_len - 11); String mi = ""; //如果明文長度大于模長-11則要分組加密 for (String s : datas) { mi += bcd2Str(cipher.doFinal(s.getBytes())); } return mi; } /** * 私鑰解密 * * @param data * @param privateKey * @return * @throws Exception */ public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); //模長 int key_len = privateKey.getModulus().bitLength() / 8; byte[] bytes = data.getBytes(); byte[] bcd = ASCII_To_BCD(bytes, bytes.length); System.err.println(bcd.length); //如果密文長度大于模長則要分組解密 String ming = ""; byte[][] arrays = splitArray(bcd, key_len); for(byte[] arr : arrays){ ming += new String(cipher.doFinal(arr)); } return ming; } /** * ASCII碼轉(zhuǎn)BCD碼 * */ public static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) { byte[] bcd = new byte[asc_len / 2]; int j = 0; for (int i = 0; i < (asc_len + 1) / 2; i++) { bcd[i] = asc_to_bcd(ascii[j++]); bcd[i] = (byte) (((j >= asc_len) ? 0x00 : asc_to_bcd(ascii[j++])) + (bcd[i] << 4)); } return bcd; } public static byte asc_to_bcd(byte asc) { byte bcd; if ((asc >= "0") && (asc <= "9")) bcd = (byte) (asc - "0"); else if ((asc >= "A") && (asc <= "F")) bcd = (byte) (asc - "A" + 10); else if ((asc >= "a") && (asc <= "f")) bcd = (byte) (asc - "a" + 10); else bcd = (byte) (asc - 48); return bcd; } /** * BCD轉(zhuǎn)字符串 */ public static String bcd2Str(byte[] bytes) { char temp[] = new char[bytes.length * 2], val; for (int i = 0; i < bytes.length; i++) { val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f); temp[i * 2] = (char) (val > 9 ? val + "A" - 10 : val + "0"); val = (char) (bytes[i] & 0x0f); temp[i * 2 + 1] = (char) (val > 9 ? val + "A" - 10 : val + "0"); } return new String(temp); } /** * 拆分字符串 */ public static String[] splitString(String string, int len) { int x = string.length() / len; int y = string.length() % len; int z = 0; if (y != 0) { z = 1; } String[] strings = new String[x + z]; String str = ""; for (int i=0; i }
##### 2.4 問題 > 公鑰(n,e) 只能 加密小于 n 的整數(shù) m ,那么如果要加密大于 n 的整數(shù),怎么辦? > 在 Java 中 進(jìn)行 RSA 加密時(shí),有 一個(gè) 錯(cuò)誤為 ArrayIndexOutOfBoundsException: too much data for RSA block > 該錯(cuò)誤就是加密數(shù)據(jù)過長導(dǎo)致的。 這里涉及到幾個(gè)知識(shí)點(diǎn) -- **密鑰長度/密文長度/明文長度** 1. 明文長度 明文長度(bytes) **<**= 密鑰長度(bytes)-11. 如果 明文長度 大于 規(guī)定,則出現(xiàn)上述的問題,可以按照下文中的解決方法處理 2. 密鑰長度 下限是96bits(12bytes) 上限未知。不過目前為止,被破解的最長的密鑰長度 為 768位,所以 1024 位基本安全, 2048 位絕對(duì)安全 3. 密文長度 - 不分片加密 -- 密文長度 == 密鑰長度 - 分片加密-- 密文長度 == 密鑰長度*分片數(shù) 例如 明文 8 bytes , 密鑰 128 bits 每片明文長度 = 128/8 - 11 = 5 bytes 分片數(shù) = 8/5 +1 = 2 密文長度 = 128/8 * 2 = 32 bytes **解決方法** 1. 分片加密 -- 是把長信息分割成若干段短消息,每段分別加密; 2. 先選擇一種"對(duì)稱性加密算法"(比如DES),用這種算法的密鑰加密信息,再用RSA公鑰加密DES密鑰。 未完待續(xù)。。。 ## 結(jié)語 發(fā)現(xiàn)排版,好像是有問題的,閱讀效果不理想,可以去我的[個(gè)人博客](https://3dot141.cn)中。 都看到這里了,點(diǎn)個(gè)**關(guān)注**,點(diǎn)波**贊**再走,QAQ。 你的小手**輕點(diǎn)**,是我最大的動(dòng)力哦。 > 一只想當(dāng)程序員的1米88**處女座**大可愛如此說道。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/67991.html
摘要:的加密算法由于之前看過是由實(shí)現(xiàn)的。基于協(xié)議使用作為密鑰交換算法加密算法密鑰與初始向量的長度為算法總結(jié)端密鑰算法套件端密鑰算法套件,則,,將被優(yōu)先返回的使用問題問題第一次使用的時(shí)候,不顯示接口。 前言 因?yàn)榕虐娌焕硐耄灾苯佑脙蓚€(gè)文檔承載,有什么不便,還請(qǐng)擔(dān)待。killBase -- 密碼學(xué)(一) 傳送門 附錄 1. DES 詳細(xì)加密過程 1. **對(duì)輸入的密鑰進(jìn)行變換**。 ...
摘要:以太坊的錢包在以太坊中,所有轉(zhuǎn)賬等交易操作都需要用賬戶來完成,一個(gè)合法的交易需要有發(fā)起賬戶和接收賬戶。比如常見的以太坊錢包有等。 一、錢包的說明 1. 現(xiàn)實(shí)中的錢包 大部分人錢包里都會(huì)有幾張銀行卡,每一張銀行卡都對(duì)應(yīng)著一個(gè)賬戶,我們可以用這些賬戶進(jìn)行支付、轉(zhuǎn)賬等操作。那么錢包的作用就是存放和管理這些銀行卡(賬戶)。 2. 以太坊的錢包 在以太坊中,所有轉(zhuǎn)賬等交易操作都需要用賬戶來完成,...
摘要:內(nèi)容提示阿里云服務(wù)器入門教程步驟遠(yuǎn)程連接實(shí)例根據(jù)您本地的操作系統(tǒng),您可以從等操作系統(tǒng)連接實(shí)例。根據(jù)提示,分別輸入您的云服務(wù)器實(shí)例的用戶名和密碼。內(nèi)容提示:阿里云ECS服務(wù)器入門教程:步驟 3 遠(yuǎn)程連接 Linux 實(shí)例 根據(jù)您本地的操作系統(tǒng),您可以從 Windows、Linux、Mac OS X 等操作系統(tǒng)連接 Linux 實(shí)例。本文介紹常用的連接服務(wù)器方式。更全面詳細(xì)的連接實(shí)例方式介紹,請(qǐng)...
摘要:文件如何生成的以太坊是使用對(duì)稱加密算法來加密私鑰生成文件,因此對(duì)稱加密秘鑰注意它其實(shí)也是發(fā)起交易時(shí)需要的解密秘鑰的選擇就非常關(guān)鍵,這個(gè)秘鑰是使用算法推導(dǎo)派生而出。加密推倒的相關(guān)配置是用于加密以太坊私鑰的對(duì)稱加密算法。 本文首發(fā)于深入淺出區(qū)塊鏈社區(qū)原文鏈接:[使用 ethers.js 開發(fā)以太坊 Web 錢包 2 - 賬號(hào) Keystore 文件導(dǎo)入導(dǎo)出)](https://learnb...
閱讀 1707·2021-11-12 10:36
閱讀 1623·2021-11-12 10:36
閱讀 3448·2021-11-02 14:46
閱讀 3813·2019-08-30 15:56
閱讀 3565·2019-08-30 15:55
閱讀 1468·2019-08-30 15:44
閱讀 1051·2019-08-30 14:00
閱讀 2744·2019-08-29 18:41