RSA加密演算法 RSA公開金鑰加密演算法是1977年由Ron Rivest, Adi Shamir 和Leonard Adleman一起提出, RSA就是他們三人姓氏開頭字母拼在一起組成的。 RSA是目前最有影響力和最常用的公開金鑰加密演算法, 它能夠抵抗到目前為止已知的絕大多數密碼攻擊, 至今未被完全攻破。 目前已被ISO推薦為公開金鑰資料加密標準。
RSA演算法是第一個能同時用於加密和數位簽章的演算法, 也易於理解和操作。 RSA是被研究得最廣泛的公開金鑰演算法, 從提出到現今的三十多年裡, 經歷了各種攻擊的考驗, 逐漸為人們接受, 截止2017年被普遍認為是最優秀的公開金鑰方案之一。
RSA公開金鑰密碼體制 所謂的公開金鑰密碼體制就是使用不同的加密金鑰與解密金鑰, 是一種“由已知加密金鑰推導出解密金鑰在計算上是不可行的”密碼體制。
在公開金鑰密碼體制中, 加密金鑰(即公開金鑰)PK是公開信息, 而解密金鑰(即秘密金鑰)SK是需要保密的。
根據金鑰的使用方法, 可以將密碼分為對稱密碼和公開金鑰密碼
對稱密碼:加密和解密使用同一種金鑰的方式
公開金鑰密碼:加密和解密使用不同的密碼的方式, 因此公開金鑰密碼通常也稱為非對稱密碼。
RSA演算法實現過程 RSA演算法基於一個十分簡單的數論事實:將兩個大素數相乘十分容易, 但那時想要對其乘積進行因式分解卻極其困難, 因此可以將乘積公開作為加密金鑰, 即公開金鑰, 而兩個大素數組合成私密金鑰。 公開金鑰是可發佈的供任何人使用, 私密金鑰則為自己所有,
解密者擁有私密金鑰, 並且將由私密金鑰計算生成的公開金鑰發佈給加密者。 加密都使用公開金鑰進行加密, 並將密文發送到解密者, 解密者用私密金鑰解密將密文解碼為明文。
以甲要把資訊發給乙為例, 首先確定角色:甲為加密者, 乙為解密者。 首先由乙隨機確定一個KEY, 稱之為密匙, 將這個KEY始終保存在機器B中而不發出來;然後, 由這個 KEY計算出另一個KEY, 稱之為公匙。 這個公開金鑰的特性是幾乎不可能通過它自身計算出生成它的私密金鑰。 接下來通過網路把這個公開金鑰傳給甲, 甲收到公開金鑰後, 利用公開金鑰對資訊加密, 並把密文通過網路發送到乙, 最後乙利用已知的私密金鑰, 就對密文進行解碼了。
RSA演算法實現過程為:
1、隨意選擇兩個大的質數p和q, p不等於q, 計算N=pq。
2、根據歐拉函數, 不大於N且與N互質的整數個數為(p-1)(q-1)。
3、選擇一個整數e與(p-1)(q-1)互質, 並且e小於(p-1)(q-1)。
4、用以下這個公式計算d:d× e ≡ 1 (mod (p-1)(q-1))。
5、將p和q的記錄銷毀。
以上內容中, (N,e)是公開金鑰, (N,d)是私密金鑰。
RSA演算法的應用 RSA的公開金鑰和私密金鑰是由KeyPairGenerator生成的, 獲取KeyPairGenerator的實例後還需要設置其金鑰位元數。 設置金鑰位數越高, 加密過程越安全, 一般使用1024位。 如下代碼:
[代碼]java代碼:
1 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA);2 // 金鑰位數3 keyPairGen.initialize(1024);公開金鑰和私密金鑰可以通過KeyPairGenerator執行generateKeyPair()後生成金鑰對KeyPair, 通過KeyPair.getPublic()和KeyPair.getPrivate()來獲取。 如下代碼:
[代碼]java代碼:
1 // 動態生成金鑰對, 這是當前最耗時的操作, 一般要2s以上。 2 KeyPair keyPair = keyPairGen.generateKeyPair();3 // 公開金鑰4 PublicKey publicKey = (RSAPublicKey) keyPair.getPublic();5 // 私密金鑰6 PrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();7 byte[] publicKeyData = publicKey.getEncoded();8 byte[] privateKeyData = publicKey.getEncoded();公開金鑰和私密金鑰都有它們自己獨特的比特編碼,
[代碼]java代碼:
01 // 通過公開金鑰byte[]將公開金鑰還原, 適用於RSA演算法02 public static PublicKey getPublicKey(byte[] keyBytes) throws03 NoSuchAlgorithmException,InvalidKeySpecException {04 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);05 KeyFactory keyFactory = KeyFactory.getInstance(“RSA”);06 PublicKey publicKey = keyFactory.generatePublic(keySpec);07 return publicKey;08 }09 // 通過私密金鑰byte[]將公開金鑰還原, 適用於RSA演算法10 public static PrivateKey getPrivateKey(byte[] keyBytes) throws11 NoSuchAlgorithmException,InvalidKeySpecException {12 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);13 KeyFactory keyFactory = KeyFactory.getInstance(“RSA”);14 PrivateKey privateKey = keyFactory.generatePrivate(keySpec);15 return privateKey;16 }在上文講到的RSA演算法實現過程中提到(N,e)是公開金鑰, (N,d)是私密金鑰。 既然已經獲取到了PublicKey和PrivateKey了, 那如何取到N、e、d這三個值呢。 要取到這三個值, 首先要將PublicKey和PrivateKey強制轉換成RSAPublicKey和RSAPrivateKey。 共同的N值可以通過getModulus()獲取。 執行RSAPublicKey.getPublicExponent()可以獲取到公開金鑰中的e值, 執行RSAPrivateKey.getPrivateExponent()可以獲取私密金鑰中的d值。 這三者返回類型都是BigInteger。 代碼如下:
[代碼]java代碼:01 // 列印公開金鑰資訊02 public static void printPublicKeyInfo(PublicKey key){03 RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;04 Log.d(MainActivity.TAG, “RSAPublicKey:”);05 Log.d(MainActivity.TAG, “Modulus.length=” +06 rsaPublicKey.getModulus().bitLength());07 Log.d(MainActivity.TAG, “Modulus=” +08 rsaPublicKey.getModulus().toString());09 Log.d(MainActivity.TAG, “PublicExponent.length=” +10 rsaPublicKey.getPublicExponent().bitLength());11 Log.d(MainActivity.TAG, “PublicExponent=” +12 rsaPublicKey.getPublicExponent().toString());13 }1415 // 列印私密金鑰資訊16 public static void printPublicKeyInfo(PrivateKey key){17 RSAPrivateKey rsaPublicKey = (RSAPrivateKey) privateKey;18 Log.d(MainActivity.TAG, “RSAPrivateKey:”);19 Log.d(MainActivity.TAG, “Modulus.length=” +20 rsaPrivateKey.getModulus().bitLength());21 Log.d(MainActivity.TAG, “Modulus=” +22 rsaPrivateKey.getModulus().toString());23 Log.d(MainActivity.TAG, “PublicExponent.length=” +24 rsaPrivateKey.getPrivateExponent().bitLength());25 Log.d(MainActivity.TAG, “PublicExponent=” +26 rsaPrivateKey.getPrivateExponent().toString());27 }由於程式中動態生成KeyPair對明文加密後生成的密文是不可測的, 所以在實際開發中通常在生成一個KeyPair後將公開金鑰和私密金鑰的N、e、d這三個特徵值記錄下來, 在真實的開發中使用這三個特徵值再去將PublicKey和PrivateKey還原出來。還原方法如下:
[代碼]java代碼: 01 // 使用N、e值還原公開金鑰02 public static PublicKey getPublicKey(String modulus, String03 publicExponent)04 throws NoSuchAlgorithmException, InvalidKeySpecException {05 BigInteger bigIntModulus = new BigInteger(modulus);06 BigInteger bigIntPrivateExponent = new BigInteger(publicExponent);07 RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus,08 bigIntPrivateExponent);09 KeyFactory keyFactory = KeyFactory.getInstance(“RSA”);10 PublicKey publicKey = keyFactory.generatePublic(keySpec);11 return publicKey;12 }1314 // 使用N、d值還原公開金鑰15 public static PrivateKey getPrivateKey(String modulus, String16 privateExponent)17 throws NoSuchAlgorithmException, InvalidKeySpecException {18 BigInteger bigIntModulus = new BigInteger(modulus);19 BigInteger bigIntPrivateExponent = new BigInteger(privateExponent);20 RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(bigIntModulus,21 bigIntPrivateExponent);22 KeyFactory keyFactory = KeyFactory.getInstance(“RSA”);23 PrivateKey privateKey = keyFactory.generatePrivate(keySpec);24 return privateKey;25 }公開金鑰和私密金鑰都具備後,就可以使用加解密的工具類javax.crypto.Cipher對明文和密文進行處理了。與所有的引擎類一樣,可以通過調用Cipher類中的getInstance(String transformation)靜態工廠方法得到Cipher物件。該方法中的參數描述了由指定輸入產生輸出所進行的操作或操作集合,可以是下列兩種形式之一:“algorithm/mode/padding”或“algorithm”。例如下面的例子就是有效的transformation形式:”DES/CBC/PKCS5Padding”或”DES”。如果沒有指定模式或填充方式,就使用特定提供者指定的預設模式或預設填充方式。
Cipher的加密和解密方式所調用的方法和過程都一樣,只是傳參不同的區別。如下代碼:
[代碼]java代碼:
1 // 編碼前設定編碼方式及金鑰2 cipher.init(mode, key);3 // 傳入編碼資料並返回編碼結果4 byte[] dataResult = cipher.doFinal(input);Cipher.init(mode, key)方法中MODE指加密或解密模式,值為Cipher.ENCRYPT_MODE或Cipher.DECRYPT_MODE,參數key在加密時傳入PublicKey,在解密時以PrivateKey傳入。Cipher.doFinal(byte[] data)則是將待編碼數據傳入後並返回編碼結果。為了將編碼結果轉為可讀字串,通常最後還使用BASE 64演算法對最終的byte[]資料編碼後顯示給開發者。
SSL證書是HTTP明文協定升級HTTPS加密協定的重要管道,是網路安全傳輸的加密通道。關於更多SSL證書的資訊,請關注數安時代(GDCA)。GDCA致力於網路資訊安全,已通過WebTrust 的國際認證,是全球可信任的證書簽發機構。GDCA專業技術團隊將根據使用者具體情況為其提供最優的產品選擇建議,並針對不同的應用或伺服器要求提供專業對應的HTTPS解決方案。
文章來源於https://www.trustauth.cn/baike/24298.html
在真實的開發中使用這三個特徵值再去將PublicKey和PrivateKey還原出來。還原方法如下:[代碼]java代碼: 01 // 使用N、e值還原公開金鑰02 public static PublicKey getPublicKey(String modulus, String03 publicExponent)04 throws NoSuchAlgorithmException, InvalidKeySpecException {05 BigInteger bigIntModulus = new BigInteger(modulus);06 BigInteger bigIntPrivateExponent = new BigInteger(publicExponent);07 RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus,08 bigIntPrivateExponent);09 KeyFactory keyFactory = KeyFactory.getInstance(“RSA”);10 PublicKey publicKey = keyFactory.generatePublic(keySpec);11 return publicKey;12 }1314 // 使用N、d值還原公開金鑰15 public static PrivateKey getPrivateKey(String modulus, String16 privateExponent)17 throws NoSuchAlgorithmException, InvalidKeySpecException {18 BigInteger bigIntModulus = new BigInteger(modulus);19 BigInteger bigIntPrivateExponent = new BigInteger(privateExponent);20 RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(bigIntModulus,21 bigIntPrivateExponent);22 KeyFactory keyFactory = KeyFactory.getInstance(“RSA”);23 PrivateKey privateKey = keyFactory.generatePrivate(keySpec);24 return privateKey;25 }公開金鑰和私密金鑰都具備後,就可以使用加解密的工具類javax.crypto.Cipher對明文和密文進行處理了。與所有的引擎類一樣,可以通過調用Cipher類中的getInstance(String transformation)靜態工廠方法得到Cipher物件。該方法中的參數描述了由指定輸入產生輸出所進行的操作或操作集合,可以是下列兩種形式之一:“algorithm/mode/padding”或“algorithm”。例如下面的例子就是有效的transformation形式:”DES/CBC/PKCS5Padding”或”DES”。如果沒有指定模式或填充方式,就使用特定提供者指定的預設模式或預設填充方式。
Cipher的加密和解密方式所調用的方法和過程都一樣,只是傳參不同的區別。如下代碼:
[代碼]java代碼:
1 // 編碼前設定編碼方式及金鑰2 cipher.init(mode, key);3 // 傳入編碼資料並返回編碼結果4 byte[] dataResult = cipher.doFinal(input);Cipher.init(mode, key)方法中MODE指加密或解密模式,值為Cipher.ENCRYPT_MODE或Cipher.DECRYPT_MODE,參數key在加密時傳入PublicKey,在解密時以PrivateKey傳入。Cipher.doFinal(byte[] data)則是將待編碼數據傳入後並返回編碼結果。為了將編碼結果轉為可讀字串,通常最後還使用BASE 64演算法對最終的byte[]資料編碼後顯示給開發者。
SSL證書是HTTP明文協定升級HTTPS加密協定的重要管道,是網路安全傳輸的加密通道。關於更多SSL證書的資訊,請關注數安時代(GDCA)。GDCA致力於網路資訊安全,已通過WebTrust 的國際認證,是全球可信任的證書簽發機構。GDCA專業技術團隊將根據使用者具體情況為其提供最優的產品選擇建議,並針對不同的應用或伺服器要求提供專業對應的HTTPS解決方案。
文章來源於https://www.trustauth.cn/baike/24298.html