摘要:系列密碼學二傳送門密碼學一基礎密碼學算法分類消息編碼消息摘要類,類,對稱密碼非對稱密碼數字簽名五元組明文原始信息。非對稱密碼包提供給,,等非對稱加密算法。對稱加密算法在分布式網絡系統上使用較為困難,主要是因為密鑰管理困難,使用成本較高。
前言
最近一場面試,面試官問了我
對稱加密與非對稱加密的問題,雖然曾經看過一些內容,但是沒有系統的整理,所以當被問的時候,腦子里一片空白,沒有回答上來。因此,在這里重新梳理一下密碼學的知識點,夯實一下基礎。
killBase系列 -- 密碼學(二) 傳送門
密碼學 一、基礎
密碼學算法分類:
消息編碼:Base64
消息摘要:MD類, SHA類,MAC
對稱密碼:DES,3DES,AES
非對稱密碼:RSA,DH
數字簽名:RSASignature,DSASignature
五元組
1)明文:原始信息。
2)加密算法:以密鑰為參數,對明文進行多種置換和轉換的規則和步驟,變換結果為密文。
3)解密算法:加密算法的逆變換,以密文為輸入、密鑰為參數,變換結果為明文。:
4)密鑰:加密與解密算法的參數,直接影響對明文進行變換的結果。
5)密文:對明文進行變換的結果。
Java編程中常用類 -- java.security 包
消息編碼:BASE64Encoder,BASE64Decoder -- java.util
消息摘要:MessageDigest
對稱密碼:KeyGenerator,SeretkeyFactory -- javax.crypto 包(提供給AES,DES,3DES,MD5,SHA1等 對稱 和 單向加密算法。),Cipher
非對稱密碼:KeyPairGenerator,KeyFactory -- java.security 包(提供給DSA,RSA, EC等 非對稱加密算法。),KeyPair,PublicKey,PrivateKey,Cipher
數字重命名:Signature
常用開源工具
Commons.Codec
Bouncy.Castle
二、Base64 算法Base64 基于64個字符編碼算法,以任意 8 位字節序列組合描述形式 , BASE加密后產生的字節位數是8的倍數,如果不夠位數以=符號填充。對此 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);三、消息摘要
介紹:又稱為 哈希算法。唯一對應一個消息或文體固定長度值,由一個單向的Hash加密函數對消息進行作用而產生。
分類: MD(Message Digest) 消息摘要算法,SHA(Secure Hash Algorithm) 安全散列算法, MAC(Message Authentication Code):消息認證算法
主要方法:
// xxx 可以為 md5,sha MessageDigest.getInstance("xxx")1. MD5算法
原理:
首先需要對信息進行填充,使其位長對512求余的結果等于448。
因此,信息的位長(Bits Length)將被擴展至N*512+448,N為一個非負整數,N可以是零。
填充的方法如下,在信息的后面填充一個1和無數個0,直到滿足上面的條件時才停止用0對信息的填充。
然后,在這個結果后面附加一個以64位二進制表示的填充前信息長度。
經過這兩步的處理,信息的位長=N512+448+64=(N+1)512,即長度恰好是512的整數倍
MD5以512位分組來處理輸入的信息,且每一分組又被劃分為16個32位子分組,經過了一系列的處理后,算法的輸出由四個32位分組組成,將這四個32位分組級聯后將生成一個128位散列值。
代碼實現
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(); // 轉化為 16 進制 // 原理 : byte 為 8 字節。 0xff --> 11111111 // byte&0xff 如果小于16 則小于00010000 // 所以由 toHexString() 只能轉化為 1 位,所以要在前面加上 ‘0’。再加上實際的值。 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 算法
原理:接收一段明文,然后以一種不可逆的方式將它轉換成一段(通常更小)密文,也可以簡單的理解為取一串輸入碼(稱為預映射或信息),并把它們轉化為長度較短、位數固定的輸出序列即散列值(也稱為信息摘要或信息認證代碼)的過程。
特點:該算法輸入報文的長度不限,產生的輸出是一個160位的報文摘要。輸入是按 512 位的分組進行處理的。
作用:通過散列算法可實現數字簽名實現,數字簽名的原理是將要傳送的明文通過一種函數運算(Hash)轉換成報文摘要(不同的明文對應不同的報文摘要),報文摘要加密后與明文一起傳送給接受方,接受方將接受的明文產生新的報文摘要與發送方的發來報文摘要解密比較,比較結果一致表示明文未被改動,如果不一致表示明文已被篡改。
代碼實現
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 算法
原理:用公開函數和密鑰產生一個固定長度的值作為認證標識,用這個 標識鑒別消息的完整性。使用一個密鑰生成一個固定大小的小數據塊,即MAC,并將其加入到消息中,然后傳輸。接收方利用與發送方共享的密鑰進行鑒別認證 等。
代碼實現
// 構建密鑰 public static byte[] getSecretKey(){ // 初始化 KeyGenerator keyGen = null; try { keyGen = KeyGenerator.getInstance("HmacMD5"); } catch (NoSuchAlgorithmException e1) { e1.printStackTrace(); } // 產生密鑰 SecretKey secretKey1 = keyGen.generateKey(); // 得到密鑰字節數組 byte[] key = secretKey1.getEncoded(); return key; } // 執行消息摘要 public static void doHMAC(byte[] data,String key){ // 從字節數組還原 SecretKey secretKey2 = new SecretKeySpec(key,"HmacMD5"); try { // 實例化 Mac Mac mac = Mac.getInstance("HmacMD5"); // 密鑰初始化 Mac mac.init(secretKey2); // 執行消息摘要 byte[] result = mac.doFinal(data); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } }4. SHA 與 MD5比較
1)對強行攻擊的安全性:最顯著和最重要的區別是SHA-1摘要比MD5摘要長32 位。使用強行技術,產生任何一個報文使其摘要等于給定報摘要的難度對MD5是2^128數量級的操作,而對SHA-1則是2^160數量級的操作。這樣,SHA-1對強行攻擊有更大的強度。
2)對密碼分析的安全性:由于MD5的設計,易受密碼分析的攻擊,SHA-1顯得不易受這樣的攻擊。
3)速度:在相同的硬件上,SHA-1的運行速度比MD5慢。
定義:在對稱加密算法中,數據發信方將明文(原始數據)和加密密鑰(mi yue)一起經過特殊加密算法處理后,使其變成復雜的加密密文發送出去。
收信方收到密文后,若想解讀原文,則需要使用加密用過的密鑰及相同算法的逆算法對密文進行解密,才能使其恢復成可讀明文。
在對稱加密算法中,使用的密鑰只有一個,發收信雙方都使用這個密鑰對數據進行加密和解密,這就要求解密方事先必須知道加密密鑰。
優缺點
優點:算法公開、計算量小、加密速度快、加密效率高。
缺點:
(1)交易雙方都使用同樣鑰匙,安全性得不到保證。
(2)每對用戶每次使用對稱加密算法時,都需要使用其他人不知道的惟一鑰匙,這會使得發收信雙方所擁有的鑰匙數量呈幾何級數增長,
密鑰管理成為用戶的負擔。對稱加密算法在分布式網絡系統上使用較為困難,主要是因為密鑰管理困難,使用成本較高。
常用的對稱加密算法。
DES(Data Encryption Standard):數據加密標準,速度較快,適用于加密大量數據的場合。
3DES(Triple DES):是基于DES,對一塊數據用三個不同的密鑰進行三次加密,強度更高。
AES(Advanced Encryption Standard):高級加密標準,是下一代的加密算法標準,速度快,安全級別最高
對稱密碼常用的數學運算
移位和循環移位
移位就是將一段數碼按照規定的位數整體性地左移或右移。循環右移就是當右移時,把數碼的最后的位移到數碼的最前頭,循環左移正相反。例如,對十進制數碼12345678循環右移1位(十進制位)的結果為81234567,而循環左移1位的結果則為23456781。
置換
就是將數碼中的某一位的值根據置換表的規定,用另一位代替。它不像移位操作那樣整齊有序,看上去雜亂無章。這正是加密所需,被經常應用。
擴展
就是將一段數碼擴展成比原來位數更長的數碼。擴展方法有多種,例如,可以用置換的方法,以擴展置換表來規定擴展后的數碼每一位的替代值。
壓縮
就是將一段數碼壓縮成比原來位數更短的數碼。壓縮方法有多種,例如,也可以用置換的方法,以表來規定壓縮后的數碼每一位的替代值。
異或
這是一種二進制布爾代數運算。異或的數學符號為⊕ ,它的運算法則如下:
1⊕ 1 = 0 0⊕ 0 = 0 1⊕ 0 = 1 0⊕ 1 = 1
也可以簡單地理解為,參與異或運算的兩數位如相等,則結果為0,不等則為1。
迭代
迭代就是多次重復相同的運算,這在密碼算法中經常使用,以使得形成的密文更加難以破解。
分組加密
參考 分組加密的四種模式
ECB模式 -- 電子密碼本模式
CBC模式 -- 密碼分組鏈接模式
CFB模式 -- 密文反饋模式
OFB模式 -- 輸出反饋模式
CTR模式 -- 計數器模式
常用的填充方式
在Java進行DES、3DES和AES三種對稱加密算法時,常采用的是NoPadding(不填充)、Zeros填充(0填充)、PKCS5Padding填充。
ZerosPadding
全部填充為0的字節,結果如下:
F1 F2 F3 F4 F5 F6 F7 F8 //第一塊
F9 00 00 00 00 00 00 00 //第二塊
PKCS5Padding
每個填充的字節都記錄了填充的總字節數,結果如下:
F1 F2 F3 F4 F5 F6 F7 F8 //第一塊
F9 07 07 07 07 07 07 07 //第二塊
注: 如果
1. DES(Data Encryption Standard)DES算法的入口參數有三個:Key、Data、Mode。
Key為8個字節共64位,其中密鑰 56 位,校驗位 8 位(每組的 第8位都被用作奇偶校驗),是DES算法的工作密鑰;
Data也為8個字節64位,是要被加密或被解密的數據;
Mode為DES的工作方式,有兩種:加密或解密。
簡略版:
首先要生成一套加密密鑰,從用戶處取得一個64位長的密碼口令,然后通過等分、移位、選取和迭代形成一套16個加密密鑰,分別供每一輪運算中使用。
過程 1,2
DES對64位(bit)的明文分組M進行操作,M經過一個初始置換IP,置換成m0。將m0明文分成左半部分和右半部分m0 = (L0,R0),各32位長。然后進行16輪完全相同的運算(迭代),這些運算被稱為函數f,在每一輪運算過程中數據與相應的密鑰結合。
過程 4
在每一輪中,密鑰位移位,然后再從密鑰的56位中選出48位。通過一個擴展置換將數據的右半部分擴展成48位,并通過一個異或操作替代成新的48位數據,再將其壓縮置換成32位。這四步運算構成了函數f。然后,通過另一個異或運算,函數f的輸出與左半部分結合,其結果成為新的右半部分,原來的右半部分成為新的左半部分。將該操作重復16次。
過程 3 ,5 ,6 ,7 , 8 , 9
經過16輪迭代后,左,右半部分合在一起經過一個逆置換(數據整理),恢復原先的順序,這樣就完成了加密過程。
過程 10.
詳細版請見 附錄
加密和解密使用相同的算法!
DES加密和解密唯一的不同是密鑰的次序相反。如果各輪加密密鑰分別是K1,K2,K3…K16,那么解密密鑰就是K16,K15,K14…K1。這也就是DES被稱為對稱算法的理由吧。
DES算法中只用到64位密鑰中的其中56位,而第8、16、24、......64位8個位并未參與DES運算
3DES(或稱為Triple DES)
原理:
使用3條56位的密鑰對 數據進行三次加密。
相關的類:
// 生成密鑰 KeyGenerator,SecretKeyFactory // 密鑰 SecretKey , SecretKeySpec // 密碼 Cipher
這里重點講一下 Cipher 類
首先要設置參數
Cipher.getInstance(加解密算法,加解密模式,填充模式)
初始化
Cipher.init(加解密模式 -- Cypher.ENCRIPT/DECRYPT,密鑰)
完成加解密
Cipher.doFinal(bytes) -- 將bytes 內容 加密/解密 然后返回。
這里使用 SecretKeyFactory的密鑰 選擇CBC模式 進行加解密。
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)
有時間 再寫。。。 看了一天的 加密 ,累死。。。
五、非對稱加密 1. 基礎定義:需要兩個密鑰,一個是公開密鑰,另一個是私有密鑰;一個用作加密的時候,另一個則用作解密。
使用其中一個密鑰把明文加密后所得的密文,只能用相對應的另一個密鑰才能解密得到原本的明文;甚至連最初用來加密的密鑰也不能用作解密。
由于加密和解密需要兩個不同的密鑰,故被稱為非對稱加密
數論知識:
非對稱加密運用了一部分數論知識,有興趣的自己去看下。。。 這里提供一下鏈接。
阮一峰大神寫了一部分,可以幫助理解
一、互質關系:
2. RSA 算法如果兩個正整數,除了1以外,沒有其他公因子,我們就稱這兩個數是互質關系(coprime)。比如,15和32沒有公因子,所以它們是互質關系。這說明,不是質數也可以構成互質關系。
二、歐拉函數
三、歐拉定理)
四、模反元素(模逆元)
五、擴展歐幾里得算法
隨機選擇兩個不相等的質數 p 和 q
= 61, q = 53
計算 p 和 q 的乘積 n
= 61*53 = 3233
計算 n 的歐拉函數 φ(n)
φ(n) = (p-1)(q-1) = 60 * 52 = 3120
隨機選擇一個整數 e , 條件是 1 < e < φ(n) , 且 e 與 φ(n) 互質
= 17 ( 實際應用中,常常選擇 65537 )
計算 e 對于 φ(n) 的模反元素 d
所謂"模反元素"就是指有一個整數d,可以使得ed被φ(n)除的余數為1。 ed ≡ 1 (mod φ(n))
ed - 1 = kφ(n)
于是,找到模反元素d,實質上就是對下面這個二元一次方程求解。 ex + φ(n)y = 1 已知 e=17, φ(n)=3120, 17x + 3120y = 1 這個方程可以用"擴展歐幾里得算法"求解,此處省略具體過程。總之,愛麗絲算出一組整數解為 (x,y)=(2753,-15),即 d=2753。 至此所有計算完成。
6. 將 n 和 e 封裝成公鑰, n 和 d 封裝成私鑰 公鑰 (3233,17), 私鑰 (3233,2753) 7. 加密與解密 - 加密用 (n , e) 加密信息 -- **明文**為 m , **m 小于 n** $m^e$ ≡ c (mod n) 公鑰是 (3233,17), m 假設為 65 $65^{17}$ ≡ 2790(mod 3233) 所以 c = 2790 - 解密用 (n , d) **密文** 為 c $c^d$ ≡ m(mod n) $2790^{2753}$ ≡ 65 (mod 3233) 所以 m = 65 8. 私鑰解密的證明 -- 有興趣的同學自己去找資料看下,也是數論的知識。 ##### 2.2 RSA 算法的可靠性 與 破解 以上密鑰的生成步驟,出現了六個數字 > p, q, n, φ(n), e, d 公鑰為 n, e 如果想要得到 d,需要進行以下逆推
(1)ed≡1 (mod φ(n))。只有知道e和φ(n),才能算出d。
(2)φ(n)=(p-1)(q-1)。只有知道p和q,才能算出φ(n)。
(3)n=pq。只有將n因數分解,才能算出p和q。
所以 如果將 n 進行 **因數分解**,就意味著私鑰被破解。 可是,大整數的因數分解,是一件非常困難的事情。目前,除了暴力破解,還沒有發現別的有效方法。 ** 注意:**這里說大整數,不是 像上文 3233 這樣的數字,歷史上最大的已經進行因數分解的整數為
12301866845301177551304949
58384962720772853569595334
79219732245215172640050726
36575187452021997864693899
56474942774063845925192557
32630345373154826850791702
61221429134616704292143116
02221240479274737794080665
351419597459856902143413
它等于這樣兩個質數的乘積
33478071698956898786044169
84821269081770479498371376
85689124313889828837938780
02287614711652531743087737
814467999489
×
36746043666799590428244633
79962795263227915816434308
76426760322838157396665112
79233373417143396810270092
798736308917
**破解:** 這里有一篇關于 RSA 破解的文章,有興趣的同學可以看一下。 [RSA計時攻擊](https://juejin.im/post/5937e8252f301e006b2c4e84) ##### 2.3 Java 實現 **使用到的類**: 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(); //公鑰指數 String public_exponent = publicKey.getPublicExponent().toString(); //私鑰指數 String private_exponent = privateKey.getPrivateExponent().toString(); //明文 String ming = "123456789"; //使用模和指數生成公鑰和私鑰 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; } /** * 使用模和指數生成RSA公鑰 * 注意:【此代碼用了默認補位方式,為RSA/None/PKCS1Padding,不同JDK默認的補位方式可能不同,如Android默認是RSA * /None/NoPadding】 * * @param modulus * 模 * @param exponent * 指數 * @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; } } /** * 使用模和指數生成RSA私鑰 * 注意:【此代碼用了默認補位方式,為RSA/None/PKCS1Padding,不同JDK默認的補位方式可能不同,如Android默認是RSA * /None/NoPadding】 * * @param modulus * 模 * @param exponent * 指數 * @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; // 加密數據長度 <= 模長-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碼轉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轉字符串 */ 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 的整數 m ,那么如果要加密大于 n 的整數,怎么辦? > 在 Java 中 進行 RSA 加密時,有 一個 錯誤為 ArrayIndexOutOfBoundsException: too much data for RSA block > 該錯誤就是加密數據過長導致的。 這里涉及到幾個知識點 -- **密鑰長度/密文長度/明文長度** 1. 明文長度 明文長度(bytes) **<**= 密鑰長度(bytes)-11. 如果 明文長度 大于 規定,則出現上述的問題,可以按照下文中的解決方法處理 2. 密鑰長度 下限是96bits(12bytes) 上限未知。不過目前為止,被破解的最長的密鑰長度 為 768位,所以 1024 位基本安全, 2048 位絕對安全 3. 密文長度 - 不分片加密 -- 密文長度 == 密鑰長度 - 分片加密-- 密文長度 == 密鑰長度*分片數 例如 明文 8 bytes , 密鑰 128 bits 每片明文長度 = 128/8 - 11 = 5 bytes 分片數 = 8/5 +1 = 2 密文長度 = 128/8 * 2 = 32 bytes **解決方法** 1. 分片加密 -- 是把長信息分割成若干段短消息,每段分別加密; 2. 先選擇一種"對稱性加密算法"(比如DES),用這種算法的密鑰加密信息,再用RSA公鑰加密DES密鑰。 未完待續。。。 ## 結語 發現排版,好像是有問題的,閱讀效果不理想,可以去我的[個人博客](https://3dot141.cn)中。 都看到這里了,點個**關注**,點波**贊**再走,QAQ。 你的小手**輕點**,是我最大的動力哦。 > 一只想當程序員的1米88**處女座**大可愛如此說道。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67991.html
摘要:的加密算法由于之前看過是由實現的。基于協議使用作為密鑰交換算法加密算法密鑰與初始向量的長度為算法總結端密鑰算法套件端密鑰算法套件,則,,將被優先返回的使用問題問題第一次使用的時候,不顯示接口。 前言 因為排版不理想,所以直接用兩個文檔承載,有什么不便,還請擔待。killBase -- 密碼學(一) 傳送門 附錄 1. DES 詳細加密過程 1. **對輸入的密鑰進行變換**。 ...
摘要:以太坊的錢包在以太坊中,所有轉賬等交易操作都需要用賬戶來完成,一個合法的交易需要有發起賬戶和接收賬戶。比如常見的以太坊錢包有等。 一、錢包的說明 1. 現實中的錢包 大部分人錢包里都會有幾張銀行卡,每一張銀行卡都對應著一個賬戶,我們可以用這些賬戶進行支付、轉賬等操作。那么錢包的作用就是存放和管理這些銀行卡(賬戶)。 2. 以太坊的錢包 在以太坊中,所有轉賬等交易操作都需要用賬戶來完成,...
摘要:內容提示阿里云服務器入門教程步驟遠程連接實例根據您本地的操作系統,您可以從等操作系統連接實例。根據提示,分別輸入您的云服務器實例的用戶名和密碼。內容提示:阿里云ECS服務器入門教程:步驟 3 遠程連接 Linux 實例 根據您本地的操作系統,您可以從 Windows、Linux、Mac OS X 等操作系統連接 Linux 實例。本文介紹常用的連接服務器方式。更全面詳細的連接實例方式介紹,請...
摘要:文件如何生成的以太坊是使用對稱加密算法來加密私鑰生成文件,因此對稱加密秘鑰注意它其實也是發起交易時需要的解密秘鑰的選擇就非常關鍵,這個秘鑰是使用算法推導派生而出。加密推倒的相關配置是用于加密以太坊私鑰的對稱加密算法。 本文首發于深入淺出區塊鏈社區原文鏈接:[使用 ethers.js 開發以太坊 Web 錢包 2 - 賬號 Keystore 文件導入導出)](https://learnb...
閱讀 1706·2021-11-12 10:36
閱讀 1621·2021-11-12 10:36
閱讀 3446·2021-11-02 14:46
閱讀 3809·2019-08-30 15:56
閱讀 3557·2019-08-30 15:55
閱讀 1465·2019-08-30 15:44
閱讀 1048·2019-08-30 14:00
閱讀 2739·2019-08-29 18:41