一、非對(duì)稱(chēng)加密
非對(duì)稱(chēng)加密算法是一種密鑰的保密方法。
非對(duì)稱(chēng)加密算法需要兩個(gè)密鑰:公開(kāi)密鑰(publickey:簡(jiǎn)稱(chēng)公鑰)和私有密鑰(privatekey:簡(jiǎn)稱(chēng)私鑰)。公鑰與私鑰是一對(duì),如果用公鑰對(duì)數(shù)據(jù)進(jìn)行加密,只有用對(duì)應(yīng)的私鑰才能解密。因?yàn)榧用芎徒饷苁褂玫氖莾蓚€(gè)不同的密鑰,所以這種算法叫作非對(duì)稱(chēng)加密算法。 非對(duì)稱(chēng)加密算法實(shí)現(xiàn)機(jī)密信息交換的基本過(guò)程是:甲方生成一對(duì)密鑰并將公鑰公開(kāi),需要向甲方發(fā)送信息的其他角色(乙方)使用該密鑰(甲方的公鑰)對(duì)機(jī)密信息進(jìn)行加密后再發(fā)送給甲方;甲方再用自己私鑰對(duì)加密后的信息進(jìn)行解密。甲方想要回復(fù)乙方時(shí)正好相反,使用乙方的公鑰對(duì)數(shù)據(jù)進(jìn)行加密,同理,乙方使用自己的私鑰來(lái)進(jìn)行解密。
另一方面,甲方可以使用自己的私鑰對(duì)機(jī)密信息進(jìn)行簽名后再發(fā)送給乙方;乙方再用甲方的公鑰對(duì)甲方發(fā)送回來(lái)的數(shù)據(jù)進(jìn)行驗(yàn)簽。
甲方只能用其私鑰解密由其公鑰加密后的任何信息。 非對(duì)稱(chēng)加密算法的保密性比較好,它消除了最終用戶(hù)交換密鑰的需要。
非對(duì)稱(chēng)密碼體質(zhì)的特點(diǎn):算法強(qiáng)度復(fù)雜、安全性依賴(lài)于算法與密鑰但是由于其算法復(fù)雜,而使得加密解密速度沒(méi)有對(duì)稱(chēng)加密解密的速度快。對(duì)稱(chēng)密碼體制中只有一種密鑰,并且是非公開(kāi)的,如果要解密就得讓對(duì)方知道密鑰。所以保證其安全性就是保證密鑰的安全,而非對(duì)稱(chēng)密鑰體制有兩種密鑰,其中一個(gè)是公開(kāi)的,這樣就可以不需要像對(duì)稱(chēng)密碼那樣傳輸對(duì)方的密鑰了。這樣安全性就大了很多。
二、RSA算法
簡(jiǎn)介:
RSA公開(kāi)密鑰密碼體質(zhì)是一種使用不同的加密密鑰與解密密鑰,“由已知加密密鑰推導(dǎo)出解密密鑰在計(jì)算上是不可行的”密碼體制 。
在公開(kāi)密鑰密碼體制中,加密密鑰(即公開(kāi)密鑰)PK是公開(kāi)信息,而解密密鑰(即秘密密鑰)SK是需要保密的。加密算法E和解密算法D也都是公開(kāi)的。雖然解密密鑰SK是由公開(kāi)密鑰PK決定的,但卻不能根據(jù)PK計(jì)算出SK 。
正是基于這種理論,1978年出現(xiàn)了著名的RSA算法,它通常是先生成一對(duì)RSA密鑰,其中之一是保密密鑰,由用戶(hù)保存;另一個(gè)為公開(kāi)密鑰,可對(duì)外公開(kāi),甚至可在網(wǎng)絡(luò)服務(wù)器中注冊(cè)。為提高保密強(qiáng)度,RSA密鑰至少為500位長(zhǎng),一般推薦使用1024位。這就使加密的計(jì)算量很大。為減少計(jì)算量,在傳送信息時(shí),常采用傳統(tǒng)加密方法與公開(kāi)密鑰加密方法相結(jié)合的方式,即信息采用改進(jìn)的DES或IDEA對(duì)話(huà)密鑰加密,然后使用RSA密鑰加密對(duì)話(huà)密鑰和信息摘要。對(duì)方收到信息后,用不同的密鑰解密并可核對(duì)信息摘要 。
RSA是被研究得最廣泛的公鑰算法,從提出到現(xiàn)在已近三十年,經(jīng)歷了各種攻擊的考驗(yàn),逐漸為人們接受,普遍認(rèn)為是目前最優(yōu)秀的公鑰方案之一。1983年麻省理工學(xué)院在美國(guó)為RSA算法申請(qǐng)了專(zhuān)利。
算法原理:
RSA公開(kāi)密鑰密碼體制的原理是:根據(jù)數(shù)論,尋求兩個(gè)大素?cái)?shù)比較簡(jiǎn)單,而將它們的乘積進(jìn)行因式分解卻極其困難,因此可以將乘積公開(kāi)作為加密密鑰 。
算法描述:
(1)任意選取兩個(gè)不同的大素?cái)?shù)p和q計(jì)算乘積
(2)任意選取一個(gè)大整數(shù)e,滿(mǎn)足
整數(shù)e用做加密鑰(注意:e的選取是很容易的,例如,所有大于p和q的素?cái)?shù)都可用)
(3)確定的解密鑰d,滿(mǎn)足
即
是一個(gè)任意的整數(shù);所以,若知道e和則很容易計(jì)算出d
(4)公開(kāi)整數(shù)n和e,秘密保存d
(5)將明文m(m<n是一個(gè)整數(shù))加密成密文c,加密算法為
(6)將密文c解密為明文m,解密算法為
RSA允許你選擇公鑰的大小。512位的密鑰被視為不安全的;768位的密鑰不用擔(dān)心受到除了國(guó)家安全管理(NSA)外的其他事物的危害;1024位的密鑰幾乎是安全的。RSA在一些主要產(chǎn)品內(nèi)部都有嵌入,像 Windows、網(wǎng)景 Navigator、 Quicken和 Lotus Notes 。
三、RSA算法Java語(yǔ)言實(shí)現(xiàn)
RSA算法工具類(lèi)源碼:
package com.ljt.rsa.util;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName: RSAUtil
* @Description: RSA非對(duì)稱(chēng)加密算法工具類(lèi)
* @Author: 寒山月初°C
* @Date 2021/5/16 17:47
* @Version 1.0
*/
public class RSAUtil {
public static final String CHARSET = "UTF-8";
public static final String RSA_ALGORITHM = "RSA";
public static Map<String, String> createKeys(int keySize){
//為RSA算法創(chuàng)建一個(gè)KeyPairGenerator對(duì)象(KeyPairGenerator,密鑰對(duì)生成器,用于生成公鑰和私鑰對(duì))
KeyPairGenerator kpg;
try{
kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM);
}catch(NoSuchAlgorithmException e){
throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]");
}
//初始化KeyPairGenerator對(duì)象,密鑰長(zhǎng)度
kpg.initialize(keySize);
//生成密匙對(duì)
KeyPair keyPair = kpg.generateKeyPair();
//得到公鑰
Key publicKey = keyPair.getPublic();
String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded()); //返回一個(gè)publicKey經(jīng)過(guò)二次加密后的字符串
//得到私鑰
Key privateKey = keyPair.getPrivate();
String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded()); 返回一個(gè)privateKey經(jīng)過(guò)二次加密后的字符串
Map<String, String> keyPairMap = new HashMap<String, String>();
keyPairMap.put("publicKey", publicKeyStr);
keyPairMap.put("privateKey", privateKeyStr);
return keyPairMap;
}
/**
* 得到公鑰
* @param publicKey 密鑰字符串(經(jīng)過(guò)base64編碼)
* @throws Exception
*/
public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
//通過(guò)X509編碼的Key指令獲得公鑰對(duì)象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
return key;
}
/**
* 得到私鑰
* @param privateKey 密鑰字符串(經(jīng)過(guò)base64編碼)
* @throws Exception
*/
public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
//通過(guò)PKCS#8編碼的Key指令獲得私鑰對(duì)象
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
return key;
}
/**
* 公鑰加密
* @param data
* @param publicKey
* @return
*/
public static String publicEncrypt(String data, RSAPublicKey publicKey){
try{
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength()));
}catch(Exception e){
throw new RuntimeException("加密字符串[" + data + "]時(shí)遇到異常", e);
}
}
/**
* 私鑰解密
* @param data
* @param privateKey
* @return
*/
public static String privateDecrypt(String data, RSAPrivateKey privateKey){
try{
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), CHARSET);
}catch(Exception e){
throw new RuntimeException("解密字符串[" + data + "]時(shí)遇到異常", e);
}
}
/**
* 私鑰加密
* @param data
* @param privateKey
* @return
*/
public static String privateEncrypt(String data, RSAPrivateKey privateKey){
try{
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), privateKey.getModulus().bitLength()));
}catch(Exception e){
throw new RuntimeException("加密字符串[" + data + "]時(shí)遇到異常", e);
}
}
/**
* 公鑰解密
* @param data
* @param publicKey
* @return
*/
public static String publicDecrypt(String data, RSAPublicKey publicKey){
try{
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()), CHARSET);
}catch(Exception e){
throw new RuntimeException("解密字符串[" + data + "]時(shí)遇到異常", e);
}
}
private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize){
int maxBlock = 0;
if(opmode == Cipher.DECRYPT_MODE){
maxBlock = keySize / 8;
}else{
maxBlock = keySize / 8 - 11;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] buff;
int i = 0;
try{
while(datas.length > offSet){
if(datas.length-offSet > maxBlock){
buff = cipher.doFinal(datas, offSet, maxBlock);
}else{
buff = cipher.doFinal(datas, offSet, datas.length-offSet);
}
out.write(buff, 0, buff.length);
i++;
offSet = i * maxBlock;
}
}catch(Exception e){
throw new RuntimeException("加解密閥值為["+maxBlock+"]的數(shù)據(jù)時(shí)發(fā)生異常", e);
}
byte[] resultDatas = out.toByteArray();
IOUtils.closeQuietly(out);
return resultDatas;
}
}
編寫(xiě)測(cè)試類(lèi):
class Test{
public static void main (String[] args) throws Exception {
Map<String, String> keyMap = RSAUtil.createKeys(1024);
String publicKey = keyMap.get("publicKey");
String privateKey = keyMap.get("privateKey");
System.out.println("公鑰:
" + publicKey);
System.out.println("私鑰:
" + privateKey);
System.out.println("公鑰加密——私鑰解密");
String str = "寒山月初℃";
System.out.println("
明文:
" + str);
System.out.println("
明文大小:
" + str.getBytes().length);
String encodedData = RSAUtil.publicEncrypt(str, RSAUtil.getPublicKey(publicKey));
System.out.println("密文:
" + encodedData);
String decodedData = RSAUtil.privateDecrypt(encodedData, RSAUtil.getPrivateKey(privateKey));
System.out.println("解密后文字:
" + decodedData);
}
}
運(yùn)行結(jié)果:
公鑰:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyrF0HBVsYdA2fTy1iYIWh7j1OoCDzLiBWomWO3Ngn1ajl2wSPk05E7yINxLiTaQSA0H86EWv0jRJrGSdg6kwqzhWv53hza4xEXozLNgDR5L0bxEAmtv1abFALwpMHMPr8NzbpvXHwNaHer6mBrhXDVuyPdgZkWuh0kLrpvXHetQIDAQAB
私鑰:
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALKsXQcFWxh0DZ9PLWJghaHuPU6gIPMuIFaiZY7c2CfVqOXbBI-TTkTvIg3EuJNpBIDQfzoRa_SNEmsZJ2DqTCrOFa_neHNrjERejMs2ANHkvRvEQCa2_VpsUAvCkwcw-vw3Num9cfA1od6vqYGuFcNW7I92BmRa6HSQuum9cd61AgMBAAECgYA5KNch9d6stgPdoVDdlg9qPHM0ghnIcks6K_3ddF1acQn1btnIrNFvUClOyk5aKlCcfRcWlpg4xiDMTmHAqXPv_H2AQTqqLdhKC6cz0AZDuiv_itO40rqmvi9n0lcJWP0zq3cJyNlE8ogNsb9heHn_XdPIxD4tdl3QztZQHBfOgQJBAObDr9SBD0EsiGCeULMEj-hEOHsMh0NANpHvNdzKj9xNb28fAZ4H8reRG5frUqpCSTkxgigBwsMhYeQu_ebNoAUCQQDGNl8iVw219K0e3Awwd7TUmM8Ugt8intD1rbYObsYDZlss6rzsm0XzUgkJE9X6xcdu_O5jWZ49mgC3i-jg7HLxAkBZ9h283VdiFAdSi0VwlK25YacXKUouCIF9oODBo2I0AygXDOJnhje0Imi8b-v5HgBHwKo6CH2x7nioKT2oVa81AkByl8KedtfNZ1yjJ7LAXqSj-IhYImVgfZLvRnOnmnFOS-HQcRGydP6W8smYfuhJ6Agp6X7k30317VAWzYNgbjLxAkEAvOYGU33Ll871QFzWTW8eHg1SJMP4oTL3jKuQi5lVMrZTWoCQF_wvuHKAKgIs0AzFwh5vrkNN1fv5QASzwtIGzg
公鑰加密——私鑰解密
明文:
寒山月初℃
明文大?。?br> 15
密文:
pnQYCefqnlYLZ2wuMcxsbkD9feA3WFcDXShYx6HajvlsriQGWzb4Xxdwz0KTzjz3nqho9AxUc2bZmBhq05v-DCyB14u2NyabENuMXoiKft4QGKNVG3WxGps55xRHr3lVt4Rj59mDBX_manNsQDwxj7gy_Brv6Uv_NRzd6M91aGk
解密后文字:
寒山月初℃ Process finished with exit code 0
到此這篇關(guān)于用Java實(shí)現(xiàn)RSA非對(duì)稱(chēng)加密算法的文章就介紹到這了,更多相關(guān)Java實(shí)現(xiàn)RSA非對(duì)稱(chēng)加密算法內(nèi)容,請(qǐng)搜索W3Cschool以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,也希望大家以后多多支持!