1.加密概要
2.對稱加密算法
3.非對稱加密算法
非對稱加密算法需要兩個密鑰:公開密鑰(publickey)和私有密鑰(privatekey)。
公開密鑰與私有密鑰是一對,如果用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;如用私有密鑰對數據進行加密,那麼只有用對應的公開密鑰才能解密。
因爲加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。
非對稱加密算法實現機密信息交換的基本過程是:
①甲方生成一對密鑰並將其中的一把作爲公用密鑰向其它方公開;
②得到該公用密鑰的乙方使用該密鑰對機密信息進行加密後再發送給甲方;
③甲方再用自己保存的另一把專用密鑰對加密後的信息進行解密。
另一方面,甲方可以使用乙方的公鑰對機密信息進行簽名後再發送給乙方;乙方再用自己的私匙對數據 進行驗籤。
甲方只能用其專用密鑰解密由其公用密鑰加密後的任何信息。 非對稱加密算法的保密性比較好,它消除了最終用戶交換密鑰的需要。
非對稱密碼體制的特點:算法強度複雜、安全性依賴於算法與密鑰但是由於其算法複雜,而使得加密解密速度沒有對稱加密解密的速度快。
對稱密碼體制中只有一種密鑰,並且是非公開的,如果要解密就得讓對方知道密鑰。所以保證其安全性就是保證密鑰的安全,而非對稱密鑰體
制有兩種密鑰,其中一個是公開的,這樣就可以不需要像對稱密碼那樣傳輸對方的密鑰了。這樣安全性就大了很多。
3.1工作原理:
1.A要向B發送信息,A和B都要產生一對用於加密和解密的公鑰和私鑰。
2.A的私鑰保密,A的公鑰告訴B;B的私鑰保密,B的公鑰告訴A。
3.A要給B發送信息時,A用B的公鑰加密信息,因爲A知道B的公鑰。
4.A將這個消息發給B(已經用B的公鑰加密消息)。
5.B收到這個消息後,B用自己的私鑰解密A的消息。其他所有收到這個報文的人都無法解密,因爲只有B纔有B的私鑰
非對稱加密的缺點是加解密速度要遠遠慢於對稱加密,在某些極端情況下,甚至能比對稱加密慢上1000倍。
3.2.主要功能
非對稱加密體系不要求通信雙方事先傳遞密鑰或有任何約定就能完成保密通信,並且密鑰管理方便,可實現防止假冒和抵賴,因此,更適合網絡通信中的保密通信要求
3.3.主要算法
RSA、Elgamal、揹包算法、Rabin、D-H、ECC(橢圓曲線加密算法)。
使用最廣泛的是RSA算法,Elgamal是另一種常用的非對稱加密算法。
Elgamal由Taher Elgamal於1985年發明,其基礎是DiffieˉHellman密鑰交換算法,後者使通信雙方能通過公開通信來推導出只有他們知道的祕密密鑰值
[DiffieˉHellman]。DiffieˉHellman是Whitfield Diffie和Martin Hellman於1976年發明的,被視爲第一種 非對稱加密算法,DiffieˉHellman 與RSA的
不同之處在於,DiffieˉHellman不是加密算法,它只是生成可用作對稱密鑰的祕密數值。在DiffieˉHellman密鑰交換過程中,發送方和接收方分別生成一
個祕密的隨機數,並根據隨機數推導出公開值,然後,雙方再交換公開值。DiffieˉHellman算法的基礎是具備生成共享密鑰的能力。只要交換了公開值,
雙方就能使用自己的私有數和對方的公開值來生成對稱密鑰,稱爲共享密鑰,對雙方來說,該對稱密鑰是相同的,可以用於使用對稱加密算法加密數據。
與RSA相比,DiffieˉHellman的優勢之一是每次交換密鑰時都使用一組新值,而使用RSA算法時,如果攻擊者獲得了私鑰,那麼他不僅能解密之前截獲的消息,
還能解密之後的所有消息。然而,RSA可以通過認證(如使用X.509數字證書)來防止中間人攻擊,但Diff ieˉHellman在應對中間人攻擊時非常脆弱。
4.算法區別:
非對稱加密算法與對稱加密算法的區別
首先,用於消息解密的密鑰值與用於消息加密的密鑰值不同;
其次,非對稱加密算法比對稱加密算法慢數千倍,但在保護通信安全方面,非對稱加密算法卻具有對稱密碼難以企及的優勢。
5.rsa算法
5.1rsa算法歷史:
1977年,三位數學家Rivest、Shamir 和 Adleman 設計了一種算法,可以實現非對稱加密。這種算法用他們三個人的名字命名
5.2RSA加密原理使用方式簽名驗證
RSA加密傳輸的實現
在加密前首先要生成祕鑰,祕鑰的生成可以使用java中的security包下的KeyPairGenerator來生成指定位數的祕鑰。生成的祕鑰爲byte類型,
一般可以用文件保存在使用的時候讀取,但是爲了方便寫在程序裏也可以用base64編碼成字符串,在使用的時候用base64解碼然後獲得祕鑰的對象。
具體實現與步驟:
5.2.1 獲得RSA密匙對對象
public static Map<String,Key> getRSAKeys() throws NoSuchAlgorithmException{
Map<String,Key> map=new TreeMap<String, Key>();
// RSA的公鑰和私鑰
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);//一般加密位數爲1024 對安全要求較高的情況下可以使用2048
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();//公鑰
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();//私鑰
map.put("publicKey", publicKey);
map.put("privateKey", privateKey);
return map;
}
5.2.2.生成RSA密匙對使用base64編碼打印出來
public static void createAndPrintKeyPairs() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
System.out.println(Base64.encodeBase64String(publicKey.getEncoded()));//打印公鑰
System.out.println(Base64.encodeBase64String(privateKey.getEncoded()));//打印私鑰
}
5.2.3. 根據base64編碼的公鑰字符串獲取公鑰對象
public static PublicKey getRSAPublicKeyByBase64String(String pubKey)
throws NoSuchAlgorithmException, InvalidKeySpecException{
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(pubKey));
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
return publicKey;
}
5.2.4.根據base64編碼的私鑰字符串獲取私鑰對象
public static PrivateKey getRSAPrivateKeyByBase64String(String priKey)
throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec pkcs8EncodedKeySpec =
new PKCS8EncodedKeySpec(Base64.decodeBase64(priKey));
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
return privateKey;
}
5.2.5.RSA簽名並使用Base64編碼.
public static String signRSAByBase64(PrivateKey key, String content) throws NoSuchAlgorithmException, InvalidKeyException, DecoderException, SignatureException, UnsupportedEncodingException {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(key);
signature.update(content.getBytes("UTF-8"));
return Base64.encodeBase64String(signature.sign());
}
5.2.6. 驗證使用Base64編碼的RSA簽名
public static boolean verifyRSAByBase64(PublicKey key, String content, String sign)
throws NoSuchAlgorithmException, InvalidKeyException, DecoderException,
SignatureException, UnsupportedEncodingException {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(key);
signature.update(content.getBytes("UTF-8"));
return signature.verify(Base64.decodeBase64(sign));
}
5.2.7. RSA簽名並使用HEX編碼
public static String signRSAByHex(PrivateKey key, String content) throws NoSuchAlgorithmException, InvalidKeyException, DecoderException, SignatureException, UnsupportedEncodingException {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(key);
signature.update(content.getBytes("UTF-8"));
return Hex.encodeHexString(signature.sign());
}
5.2.8. 驗證使用HEX編碼的RSA簽名
public static boolean verifyRSAByHex(PublicKey key, String content, String sign)
throws NoSuchAlgorithmException, InvalidKeyException, DecoderException,
SignatureException, UnsupportedEncodingException {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(key);
signature.update(content.getBytes("UTF-8"));
return signature.verify(Hex.decodeHex(sign.toCharArray()));
}
5.2.9. map轉String key=value&形式 注意必須是TreeMap, TreeMap保證key降序.
public static String map2str(TreeMap<String, String> map) {
List<String> values = new ArrayList<String>();
for (String key : map.keySet()) {
String value = key + "=" + map.get(key);
values.add(value);
}
return list2String(values,"&");
}
5.2.10. 遍歷list數據用plus拼接起來
public static String list2String(List<String> values,String plus){
StringBuilder bui = new StringBuilder();
if(values!=null&&values.size()>0){
for(String str :values){
bui.append(str);
bui.append(plus);
}
}
bui.deleteCharAt(bui.length()-1);
return bui.toString();
}
5.2.11. RSA非對稱加密,根據公鑰和原始內容產生加密內容
public static String encryptRSA(Key key, String plainText,String rsamod)
throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidKeyException, UnsupportedEncodingException,BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
Cipher cipher = Cipher.getInstance(rsamod);
cipher.init(Cipher.ENCRYPT_MODE, key);
return Base64.encodeBase64String(cipher.doFinal(plainText.getBytes(UTF_8)));
}
5.2.12. RSA非對稱解密,根據私鑰和加密內容產生原始內容
public static String decryptRSA(Key key, String content,String rsamod) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, DecoderException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException, InvalidAlgorithmParameterException {
Cipher cipher = Cipher.getInstance(rsamod);
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(Base64.decodeBase64(content)), UTF_8);
}
5.2.13.測試
public static void main(String[] args) throws NoSuchAlgorithmException,
UnsupportedEncodingException, NoSuchPaddingException, InvalidKeyException,
SignatureException, DecoderException, InvalidKeySpecException {
// 預先產生的公鑰
String pubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArIG
hXYMqK9dbb7CYXjOdYnYiONCX4KGkHo8pMpAK59l1L1Ve6y2IdW/6W5ZHth8mE/BK1YIVvS8HCifQsT02ewU2Oq6/ fcnlgH1vlFRHJNHjPpVlPyUjIPJjLQcnNFeMNHupBdUY6UK6dneBSzB+Yv7dF9/DKOClOOE2k5BUgYwLS74GN7Xewrn RODvK2Lka1y4VRUKwHuKRtWT2XrOBIka6R0q4pwV96MW+52+9ASc8stKU5ymSiILKEHUo/wY6AYSZYIfMphpuSMIK En0cJ3SdE1sFUeARJrPBu77bOl9YV9BGMIMb7CJm+TPW+KCBdjeo1pZP45CVSybFoFTw6wIDAQAB";
PublicKey publicKey = RSAUtil.getRSAPublicKeyByBase64String(pubKey);
// 預先產生的私鑰
String priKey = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggS
AgEAAoIBAQCsgaFdgyor11tvsJheM51idiI40JfgoaQejykykArn2XUvVV7rLYh1b/pblke2HyYT8ErVghW9LwcKJ9CxPTZ7 BTY6rr99yeWAfW+UVEck0eM+lWU/JSMg8mMtByc0V4w0e6kF1RjpQrp2d4FLMH5i/t0X38Mo4KU44TaTkFSBjAtLvgY 3td7CudE4O8rYuRrXLhVFQrAe4pG1ZPZes4EiRrpHSrinBX3oxb7nb70BJzyy0pTnKZKIgsoQdSj/BjoBhJlgh8ymGm5Iwg oSfRwndJ0TWwVR4BEms8G7vts6X1hX0EYwgxvsImb5M9b4oIF2N6jWlk/jkJVLJsWgVPDrAgMBAAECggEAcPtZ33Anr 50V4tnrgU8W1kT+9u0Pe+0CG42x8s7Khb0z9fNY/njM9fWIKHINt6dA/jAUIzBW4pgpaSpYkazAwOPR96859b3E1VnS OXjVO7VHu1aHgErnbg2yjOwxbiOkzT7snchKz4OHsk1k3gT90gKQdbF1FZHERLOkVhNidZFWwz6/dbqIMEXqQue35K V2bH0qL9m1sLogPAiIePA7JqD2WTz4oWkPFR5CYNE8qS7yPHmtfX8ITv4TKPN6EFIN7Q8vJqMv775lnBpWepq00Kv+N 9r2yn53/d7rzOxeZFndz3VwmneoolcXgWmukSueAxP553N1PXeLo7XGthey4QKBgQD6xmzcOeqDcq6urnAQtlfW/C4 xGRY28Gta7yLczWBi4a4Uw5Z0URxwb3LHQjpUQMV5F8UtPYh80Qr/8Og5HK4z2TNSwWyUqxP+r4vXkwgsCQKZF21 DimigncTv2qQplwvhWrKznpd+pfLmWigYdg4DPJaBbCk2NkpSlvnA319wkQKBgQCwGb0BALX80UrY0PXb8u7P76ly1d rcx8+/DgO2LxWsvjydFHbtHojv5wt73VJi39C+KfFCnj2S54fnYJkRbYdobCW2WvUtAD3mjQPqdQAgkc+5qNdAEtuqH 3UD/b5CY9kMnahSlLvgZRl3OwysucyhdRABDTjR+2Z/CrIQkc3HuwKBgQDL9VJYkyovGrkEDY/Lp+ItUhFnkVXF/SfzX4d lOgxon9Brxt+5XrbYo2wgr7atC7kQUcrmjqNRkNt3akIVIUR1mvPpHLPo/nNWswPzovwEhJd+V9VgF1QdPfQMeDEIO ndJI/EvsY7ZTLMPssfljS68ZyypuoSSOPmdznj26zW+YQKBgQCcjLUGMDCY6SJFrzXx63w75E3aJZ1kikj4CqhoDGGTaKc P6YJz96I6y0XdPnqgJWI3u6eb1nrcnvGlUq2g3aLzxLid7Sxqbf2ZeKETjCGp0pY88Ykxj9Ix4bcv7iJ2eLcazQk3KLwAlz/VS+ xPnPj6S8wHc06g9YI/zC1SJ5wtQwKBgQC21fZP0+HiM26FgSuS8KWIj0rx0j2hylgCy0aPW/OhyGmgPWOnhfjtxndWsQ VVo/Q5MgTHC34ffwSsF6lxVdmZXZA12JOsp6RCxovVzseYVKL/xapFYbeU53VAawJ0lSVTMa3yj2vI2+XcGpA9FAI02Af bDoqzXcExyuzoofRgsw==";
PrivateKey privateKey = RSAUtil.getRSAPrivateKeyByBase64String(priKey);
// 1. 準備發送的數據
TreeMap<String, String> map = new TreeMap<String, String>();
map.put("order_id", "1324679");
map.put("partner_no", "A001");
map.put("version", "V1.0");
map.put("comment", "");
// 1. 計算驗簽字段, sign字段不參與簽名
String line = map2str(map);
String sign = RSAUtil.signRSAByBase64(privateKey, line);
map.put("sign", sign);
// 1. 構造發送的數據, 發送, 發送格式爲JSON(需要阿里巴巴的fastjson)
String request = JSON.toJSONString(map);
System.out.println(request);
// 2. 接收到request, 將JSON轉換爲map
TreeMap<String, String> map2 = JSON.parseObject(request, new TypeReference<TreeMap<String, String>>() {});
String sign2 = map2.get("sign");
// 2. 剔除sign字段
map2.remove("sign");
String line2 = map2str(map2);
boolean isPassed = RSAUtil.verifyRSAByBase64(publicKey, line2, sign2);
System.out.println("驗簽結果 : " + isPassed);
}