軟件的加密與解密是一個(gè)迷人的研究領(lǐng)域揽碘,它幾乎可以與任意一種計(jì)算機(jī)技術(shù)緊密結(jié)合——密碼學(xué)次屠、程序設(shè)計(jì)語(yǔ)言、操作系統(tǒng)雳刺、數(shù)據(jù)結(jié)構(gòu)劫灶。而由于這樣或者那樣的原因,對(duì)于這一領(lǐng)域的關(guān)注程度一直還處于低溫狀態(tài)掖桦。
網(wǎng)絡(luò)安全一般需要注意以下幾個(gè)關(guān)鍵點(diǎn):
完整性(Integrity):確保信息在傳輸過(guò)程中本昏,沒(méi)有被篡改。
私密性(Confidentiality):也就是通過(guò)加密枪汪,確保只有可信的實(shí)體可以看到這些信息涌穆。
源認(rèn)證(Authenticity):確保是可信的源發(fā)送了這些信息,而不是偽裝源發(fā)送的消息雀久。
不可否認(rèn)性(Nonrepudiation):不能事后否認(rèn)發(fā)送過(guò)這條信息蒲犬。
今天我們說(shuō)的是數(shù)據(jù)傳輸?shù)乃矫苄浴<用芗夹g(shù)是最常用的安全保密手段岸啡,利用技術(shù)手段把重要的數(shù)據(jù)變?yōu)閬y碼(加密)傳送原叮,到達(dá)目的地后再用相同或不同的手段還原(解密)。
加密技術(shù)包括兩個(gè)元素:算法和密鑰巡蘸。
一奋隶、使用異或加密解密
先來(lái)看一個(gè)簡(jiǎn)單的加密解密的實(shí)例。
package com.wuxiaolong.EncrypteDecrypt;
import org.apache.commons.codec.digest.DigestUtils;
/**
* Description:
*
* @author 諸葛小猿
* @date 2020-07-22
*/
public class Test1 {
? ? public static void main(String[] args) {
? ? ? ? String content = "我愛(ài)你";
? ? ? ? Integer key = 1000;
? ? ? ? // 用戶A發(fā)消息前悦荒,通過(guò)某種方式加密
? ? ? ? String encryptStr = xor(content,key);
? ? ? ? System.out.println(encryptStr);
? ? ? ? // 密文通過(guò)網(wǎng)絡(luò)傳輸
? ? ? ? // 用戶B收到密文后使用相同的方式解密
? ? ? ? String decryptStr = xor(encryptStr,key);
? ? ? ? System.out.println(decryptStr);
? ? }
? ? /**
? ? * 加密算法及秘鑰
? ? * @param content
? ? * @return
? ? */
? ? public static String? xor(String content, Integer key){
? ? ? ? char[] chars = content.toCharArray();
? ? ? ? for(int i=0; i<chars.length; i++){
? ? ? ? ? ? chars[i] = (char)? (chars[i]^key) ;
? ? ? ? }
? ? ? ? return new String(chars);
? ? }
}
這里自定義了一個(gè)加解密方法xor唯欣,這個(gè)方法接收兩個(gè)參數(shù),一個(gè)是原文content搬味,一個(gè)秘鑰key境氢。這樣有加密算法,有秘鑰碰纬,就可以加密了萍聊。
運(yùn)行的結(jié)果:
懹燙?? ? // 加密結(jié)果
我愛(ài)你? ? // 解密結(jié)果
二、異或加密解密原理講解
在發(fā)消息前悦析,需要使用算法+秘鑰對(duì)傳輸?shù)南ⅲ魑模┻M(jìn)行加密寿桨,加密后使用密文在網(wǎng)絡(luò)傳輸,傳輸?shù)侥康牡貢r(shí)强戴,再使用相同的算法+秘鑰將密文翻譯成明文亭螟。
在這個(gè)加密和解密的過(guò)程中挡鞍,使用了相同的算法+秘鑰。
這里可以看出预烙,一個(gè)明文連續(xù)使用相同的算法+秘鑰做兩次加密墨微,就可以得到原來(lái)的明文了。
這和計(jì)算機(jī)中的異或運(yùn)算(^)很像扁掸,異或英文為exclusive OR翘县,縮寫(xiě)成xor,異或運(yùn)行有兩個(gè)特點(diǎn):
兩個(gè)二進(jìn)制數(shù)字相同為0也糊,不同為1炼蹦。
一個(gè)數(shù)字兩次異或后羡宙,得到的是原數(shù)字本身狸剃。
下面使用一個(gè)字符a為例,和數(shù)字三進(jìn)行兩次異或運(yùn)算狗热,可以看出最終得到的結(jié)果還是a钞馁。
由于是位運(yùn)算,參與運(yùn)算的參數(shù)必須要轉(zhuǎn)化成二進(jìn)制后才能參與運(yùn)算匿刮。上面的算法public static String? xor(String content, Integer key)中僧凰,首先要將content轉(zhuǎn)化成一個(gè)字符數(shù)組,然后將數(shù)組的每一個(gè)字符熟丸,和整形的key做異或運(yùn)算得到新的字符训措,最終,將新的字符數(shù)組轉(zhuǎn)化成新的字符串光羞。
為什么不能使用content字符串直接與key求異或運(yùn)算绩鸣?因?yàn)樽址荒苤苯优c數(shù)字運(yùn)算,但是字符可以與數(shù)字運(yùn)算纱兑,所以字符串轉(zhuǎn)換成字符數(shù)組呀闻。
下面介紹的加密解密方法的底層,使用的都是二進(jìn)制潜慎,所以加密解密的參數(shù)最終都會(huì)轉(zhuǎn)換成二進(jìn)制字節(jié)數(shù)組的形式進(jìn)行處理捡多。
上面這種方法中,加密和解密使用的是相同的密鑰key铐炫,我們通常將這種方式稱(chēng)為對(duì)稱(chēng)加密垒手。如果加密和解密使用的是不同的秘鑰,則稱(chēng)之為非對(duì)稱(chēng)加密倒信。
三淫奔、對(duì)稱(chēng)加密
對(duì)于對(duì)稱(chēng)性加密,雙方通訊之前堤结,都要事先知道相同的密匙和算法唆迁,之后便是對(duì)數(shù)據(jù)進(jìn)行加解密了鸭丛。
這里介紹幾種常見(jiàn)的對(duì)稱(chēng)加密算法:DES,AES唐责。
3.1 DES
DES(Data Encryption Standard) 算法是美國(guó)政府機(jī)關(guān)為了保護(hù)信息處理中的計(jì)算機(jī)數(shù)據(jù)而使用的一種加密方式鳞溉,是一種常規(guī)密碼體制的密碼算法,目前已廣泛使用鼠哥。該算法輸入的是64比特的明文熟菲,在64比特密鑰的控制下產(chǎn)生64比特的密文;反之輸入64比特的密文朴恳,輸出64比特的明文抄罕。64比特 的密鑰中含有8個(gè)比特的奇偶校驗(yàn)位,所以實(shí)際有效密鑰長(zhǎng)度為56比特于颖。使用一個(gè) 56 位的密鑰以及附加的 8 位奇偶校驗(yàn)位呆贿,產(chǎn)生最大 64 位的分組大小。這是一個(gè)迭代的分組密碼森渐,使用稱(chēng)為 Feistel 的技術(shù)做入,其中將加密的文本塊分成兩半。使用子密鑰對(duì)其中一半應(yīng)用循環(huán)功能同衣,然后將輸出與另一半進(jìn)行"異或"運(yùn)算竟块;接著交換這兩半,這一過(guò)程會(huì)繼續(xù)下去耐齐,但最后一個(gè)循環(huán)不交換浪秘。DES 使用 16 個(gè)循環(huán),使用異或埠况,置換耸携,代換,移位操作四種基本運(yùn)算询枚。
下面是使用JDK進(jìn)行加密的示例代碼:
package com.wuxiaolong.EncrypteDecrypt;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.Key;
import java.util.Base64;
/**
* Description:
*
* @author 諸葛小猿
* @date 2020-07-23
*/
public class DESUtil {
? ? /**
? ? * 偏移變量违帆,固定占8位字節(jié)
? ? */
? ? private final static String IV_PARAMETER = "12345678";
? ? /**
? ? * 加密算法
? ? */
? ? private static final String ALGORITHM = "DES";
? ? /**
? ? * 加密/解密算法-工作模式-填充模式
? ? */
? ? private static final String CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding";
? ? /**
? ? * 默認(rèn)編碼
? ? */
? ? private static final String CHARSET = "utf-8";
? ? /**
? ? * 秘鑰
? ? */
? ? private static final String KEY = "key12345678";
? ? public static void main(String[] args) {
? ? ? ? String content = "我愛(ài)你";
? ? ? ? String encptStr = encrypt(KEY,content);
? ? ? ? System.out.println(encptStr);
? ? ? ? String decptStr = decrypt(KEY,encptStr);
? ? ? ? System.out.println(decptStr);
? ? }
? ? /**
? ? * 生成key
? ? *
? ? * @param password
? ? * @return
? ? * @throws Exception
? ? */
? ? private static Key generateKey(String password) throws Exception {
? ? ? ? DESKeySpec dks = new DESKeySpec(password.getBytes(CHARSET));
? ? ? ? SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
? ? ? ? return keyFactory.generateSecret(dks);
? ? }
? ? /**
? ? * DES加密字符串
? ? *
? ? * @param password 加密密碼,長(zhǎng)度不能夠小于8位
? ? * @param data 待加密字符串
? ? * @return 加密后內(nèi)容
? ? */
? ? public static String encrypt(String password, String data) {
? ? ? ? if (password== null || password.length() < 8) {
? ? ? ? ? ? throw new RuntimeException("加密失敗金蜀,key不能小于8位");
? ? ? ? }
? ? ? ? if (data == null)
? ? ? ? ? ? return null;
? ? ? ? try {
? ? ? ? ? ? Key secretKey = generateKey(password);
? ? ? ? ? ? Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
? ? ? ? ? ? IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
? ? ? ? ? ? cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
? ? ? ? ? ? // 加密
? ? ? ? ? ? byte[] bytes = cipher.doFinal(data.getBytes(CHARSET));
? ? ? ? ? ? // base64編碼? JDK1.8及以上可直接使用Base64刷后,JDK1.7及以下可以使用BASE64Encoder
? ? ? ? ? ? byte[] encode = Base64.getEncoder().encode(bytes);
? ? ? ? ? ? return new String(encode);
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? return data;
? ? ? ? }
? ? }
? ? /**
? ? * DES解密字符串
? ? *
? ? * @param password 解密密碼,長(zhǎng)度不能夠小于8位
? ? * @param data 待解密字符串
? ? * @return 解密后內(nèi)容
? ? */
? ? public static String decrypt(String password, String data) {
? ? ? ? if (password== null || password.length() < 8) {
? ? ? ? ? ? throw new RuntimeException("加密失敗渊抄,key不能小于8位");
? ? ? ? }
? ? ? ? if (data == null)
? ? ? ? ? ? return null;
? ? ? ? try {
? ? ? ? ? ? Key secretKey = generateKey(password);
? ? ? ? ? ? Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
? ? ? ? ? ? IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
? ? ? ? ? ? cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
? ? ? ? ? ? // base64解碼
? ? ? ? ? ? byte[] decode = Base64.getDecoder().decode(data.getBytes(CHARSET));
? ? ? ? ? ? // 解密
? ? ? ? ? ? byte[] decrypt = cipher.doFinal(decode);
? ? ? ? ? ? return new String(decrypt, CHARSET);
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? return data;
? ? ? ? }
? ? }
}? ?
上面代碼運(yùn)行的結(jié)果:
Xii999DE7LPx5io0awfOFw==? ? ? ? // 加密結(jié)果
我愛(ài)你? ? ? ? ? ? ? ? ? ? ? ? ? // 解密結(jié)果?
DES是一種分組數(shù)據(jù)加密技術(shù)(先將數(shù)據(jù)分成固定長(zhǎng)度的小數(shù)據(jù)塊尝胆,之后進(jìn)行加密),速度較快护桦,適用于大量數(shù)據(jù)加密含衔,比如文件加密。文件加密的代碼,可以關(guān)注我的公眾號(hào)贪染,輸入關(guān)鍵字“java-summary”獲取缓呛。
1997 年RSA數(shù)據(jù)安全公司發(fā)起了一項(xiàng)“DES 挑戰(zhàn)賽”的活動(dòng),志愿者四次分別用四個(gè)月杭隙、41天哟绊、56個(gè)小時(shí)和22個(gè)小時(shí)破解了其用56bit DES算法加密的密文。即DES加密算法在計(jì)算機(jī)速度提升后的今天被認(rèn)為是不安全的痰憎。所以針對(duì)保密級(jí)別特別高的數(shù)據(jù)推薦使用非對(duì)稱(chēng)加密算法票髓。
3.2 AES
AES (Advanced Encryption Standard),高級(jí)加密標(biāo)準(zhǔn)铣耘,是一種區(qū)塊加密標(biāo)準(zhǔn)洽沟。這個(gè)標(biāo)準(zhǔn)用來(lái)替代原先的DES,已經(jīng)被多方分析且廣為全世界所使用蜗细。
DES使用56位密鑰裆操,比較容易被破解,而AES可以使用128鳄乏、192跷车、和256位密鑰棘利,并且用128位分組加密和解密數(shù)據(jù)橱野,相對(duì)來(lái)說(shuō)安全很多。完善的加密算法在理論上是無(wú)法破解的善玫,除非使用窮盡法水援。使用窮盡法破解密鑰長(zhǎng)度在128位以上的加密數(shù)據(jù)是不現(xiàn)實(shí)的,僅存在理論上的可能性茅郎。統(tǒng)計(jì)顯示蜗元,即使使用目前世界上運(yùn)算速度最快的計(jì)算機(jī),窮盡128位密鑰也要花上幾十億年的時(shí)間系冗,更不用說(shuō)去破解采用256位密鑰長(zhǎng)度的AES算法了奕扣。
下面是AES的源碼展示:
package com.wuxiaolong.EncrypteDecrypt;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
/**
* Description:
*
* @author 諸葛小猿
* @date 2020-07-23
*/
public class AESUtil {
? ? /**
? ? * 加密算法
? ? */
? ? private static final String ALGORITHM = "AES";
? ? /**
? ? * 秘鑰長(zhǎng)度
? ? */
? ? private static final Integer KEY_LENGTH = 128;
? ? /**
? ? * 默認(rèn)編碼
? ? */
? ? private static final String CHARSET = "utf-8";
? ? /**
? ? * 秘鑰
? ? */
? ? private static final String KEY = "key12345678";
? ? public static void main(String[] args) throws Exception {
? ? ? ? String content = "我愛(ài)你";
? ? ? ? String encrypt = encrypt(content, KEY);
? ? ? ? System.out.println(encrypt);
? ? ? ? String decrypt = decrypt(encrypt, KEY);
? ? ? ? System.out.println(decrypt);
? ? }
? ? /**
? ? * 生成key
? ? *
? ? * @param password
? ? * @return
? ? * @throws Exception
? ? */
? ? private static SecretKeySpec generateKey(String password) throws Exception {
? ? ? ? // 創(chuàng)建AES的Key生產(chǎn)者
? ? ? ? KeyGenerator kgen = KeyGenerator.getInstance(ALGORITHM);
? ? ? ? // 利用用戶密碼作為隨機(jī)數(shù)初始化出
? ? ? ? // SecureRandom是生成安全隨機(jī)數(shù)序列,password.getBytes()是種子掌敬,只要種子相同惯豆,序列就一樣,所以解密只要有password就行
? ? ? ? kgen.init(KEY_LENGTH, new SecureRandom(password.getBytes()));
? ? ? ? // 根據(jù)用戶密碼奔害,生成一個(gè)密鑰
? ? ? ? SecretKey secretKey = kgen.generateKey();
? ? ? ? // 返回基本編碼格式的密鑰楷兽,如果此密鑰不支持編碼,則返回
? ? ? ? byte[] enCodeFormat = secretKey.getEncoded();
? ? ? ? // 轉(zhuǎn)換為AES專(zhuān)用密鑰
? ? ? ? SecretKeySpec key = new SecretKeySpec(enCodeFormat, ALGORITHM);
? ? ? ? return key;
? ? }
? ? /**
? ? * AES加密字符串
? ? *
? ? * @param content 需要被加密的字符串
? ? * @param password 加密需要的密碼
? ? * @return 密文
? ? */
? ? public static String encrypt(String content, String password) {
? ? ? ? try {
? ? ? ? ? ? SecretKeySpec key = generateKey(password);
? ? ? ? ? ? // 創(chuàng)建密碼器
? ? ? ? ? ? Cipher cipher = Cipher.getInstance(ALGORITHM);
? ? ? ? ? ? byte[] byteContent = content.getBytes(CHARSET);
? ? ? ? ? ? // 初始化為加密模式的密碼器
? ? ? ? ? ? cipher.init(Cipher.ENCRYPT_MODE, key);
? ? ? ? ? ? // 加密
? ? ? ? ? ? byte[] result = cipher.doFinal(byteContent);
? ? ? ? ? ? // 二進(jìn)制轉(zhuǎn)換成16進(jìn)制字符串
? ? ? ? ? ? String hexStr = parseByte2HexStr(result);
? ? ? ? ? ? return hexStr;
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? ? ? return null;
? ? }
? ? /**
? ? * 解密AES加密過(guò)的字符串
? ? *
? ? * @param content AES加密過(guò)過(guò)的內(nèi)容
? ? * @param password 加密時(shí)的密碼
? ? * @return 明文
? ? */
? ? public static String decrypt(String content, String password) {
? ? ? ? try {
? ? ? ? ? ? // 十六進(jìn)制字符串轉(zhuǎn)換成二進(jìn)制字節(jié)數(shù)組
? ? ? ? ? ? byte[] byteArr = parseHexStr2Byte(content);
? ? ? ? ? ? SecretKeySpec key = generateKey(password);
? ? ? ? ? ? Cipher cipher = Cipher.getInstance(ALGORITHM);
? ? ? ? ? ? cipher.init(Cipher.DECRYPT_MODE, key);
? ? ? ? ? ? // 解密
? ? ? ? ? ? byte[] result = cipher.doFinal(byteArr);
? ? ? ? ? ? return new String(result,CHARSET);
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? ? ? return null;
? ? }
? ? /**將二進(jìn)制轉(zhuǎn)換成16進(jìn)制
? ? * @param buf
? ? * @return
? ? */
? ? public static String parseByte2HexStr(byte buf[]) {
? ? ? ? StringBuffer sb = new StringBuffer();
? ? ? ? for (int i = 0; i < buf.length; i++) {
? ? ? ? ? ? String hex = Integer.toHexString(buf[i] & 0xFF);
? ? ? ? ? ? if (hex.length() == 1) {
? ? ? ? ? ? ? ? hex = '0' + hex;
? ? ? ? ? ? }
? ? ? ? ? ? sb.append(hex.toUpperCase());
? ? ? ? }
? ? ? ? return sb.toString();
? ? }
? ? /**將16進(jìn)制轉(zhuǎn)換為二進(jìn)制
? ? * @param hexStr
? ? * @return
? ? */
? ? public static byte[] parseHexStr2Byte(String hexStr) {
? ? ? ? if (hexStr.length() < 1)
? ? ? ? ? ? return null;
? ? ? ? byte[] result = new byte[hexStr.length()/2];
? ? ? ? for (int i = 0;i< hexStr.length()/2; i++) {
? ? ? ? ? ? int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
? ? ? ? ? ? int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
? ? ? ? ? ? result[i] = (byte) (high * 16 + low);
? ? ? ? }
? ? ? ? return result;
? ? }
}
上面代碼運(yùn)行的結(jié)果:
765B2080D288F81355CB2A235AD7938C? ? ? ? // 加密結(jié)果
我愛(ài)你? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 解密結(jié)果?
相較于DES而言华临,AES算法有著更高的速度和資源使用效率芯杀,安全級(jí)別也較之更高了,被稱(chēng)為下一代加密標(biāo)準(zhǔn)。目前世界上還有組織在研究如何攻破AES這堵堅(jiān)厚的墻揭厚,但是因?yàn)槠平鈺r(shí)間太長(zhǎng)却特,AES得到保障,但是所用的時(shí)間不斷縮小筛圆。隨著計(jì)算機(jī)計(jì)算速度的增快核偿,新算法的出現(xiàn),AES遭到的攻擊只會(huì)越來(lái)越猛烈顽染,不會(huì)停止的漾岳。
AES現(xiàn)在廣泛用于金融財(cái)務(wù)、在線交易粉寞、無(wú)線通信尼荆、數(shù)字存儲(chǔ)等領(lǐng)域,經(jīng)受了最嚴(yán)格的考驗(yàn)唧垦,但說(shuō)不定哪天就會(huì)步DES的后塵捅儒。
3.3 對(duì)稱(chēng)加密的特點(diǎn)
優(yōu)點(diǎn):
速度快。相對(duì)于非對(duì)稱(chēng)加密振亮,對(duì)稱(chēng)加密的性能更好巧还,加解密速度更快。
安全坊秸。只能說(shuō)相對(duì)還是安全的麸祷。
緊湊。加密后內(nèi)容的長(zhǎng)度基本變化不大褒搔。
缺點(diǎn):
如果雙方通訊時(shí)阶牍,通過(guò)明文傳輸共享密鑰,容易出現(xiàn)中途劫持和竊聽(tīng)的問(wèn)題星瘾。
隨著通訊的參與者數(shù)量的增加走孽,密鑰數(shù)量急劇膨脹((n×(n-1))/2)。
因?yàn)槊荑€數(shù)量過(guò)多琳状,對(duì)密鑰的管理和存儲(chǔ)是一個(gè)很大的問(wèn)題(后面我會(huì)專(zhuān)門(mén)開(kāi)一期說(shuō)秘鑰管理及系統(tǒng)設(shè)計(jì))磕瓷。
不支持?jǐn)?shù)字簽名和不可否認(rèn)性。
四念逞、非對(duì)稱(chēng)加密
對(duì)于非對(duì)稱(chēng)算法困食,雙方通訊之前,都需要事先生成一對(duì)密匙(公鑰肮柜、私鑰)陷舅,然后雙方交換公鑰。通常非對(duì)稱(chēng)加密使用的就是RAS算法审洞。
在使用非對(duì)稱(chēng)密鑰技術(shù)之前莱睁,所有參與者待讳,不管是用戶還是路由器等網(wǎng)絡(luò)設(shè)備,都需要預(yù)先使用非對(duì)稱(chēng)密鑰算法(例如RSA)產(chǎn)生一對(duì)密鑰仰剿,其中包括一個(gè)公鑰和一個(gè)私鑰创淡。公鑰可以放在一個(gè)服務(wù)器上共享給屬于這個(gè)密鑰系統(tǒng)的所有用戶與設(shè)備,而私鑰需要由持有者嚴(yán)格保護(hù)南吮,確保只有持有者才能唯一擁有琳彩。
非對(duì)稱(chēng)加密有很多優(yōu)點(diǎn),安全部凑、公鑰可以網(wǎng)絡(luò)傳輸?shù)嚷斗Α5羌用芩俣群苈粫?huì)用來(lái)加密上KB的數(shù)據(jù)涂邀。
關(guān)于RAS算法瘟仿,可以說(shuō)的內(nèi)容太多太多,比如RSR的數(shù)學(xué)原理比勉、公鑰加密私鑰解密劳较、私鑰簽名公鑰驗(yàn)簽、公私鑰生成浩聋、大文件如何加密观蜗、秘鑰如何管理等問(wèn)題。這些我都會(huì)在這個(gè)安全系列的其他文章中詳細(xì)說(shuō)明的衣洁。這一期以代碼展示為主墓捻,就不過(guò)多在這里說(shuō)了。
4.1 RSA
這里需要注意的是闸与,加密使用的是對(duì)方的公鑰毙替,解密使用的是對(duì)應(yīng)的私鑰岸售。
package com.wuxiaolong.EncrypteDecrypt;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
/**
* Description:
*
* @author 諸葛小猿
* @date 2020-07-24
*/
public class RSAEncrypt {
? ? //用于封裝隨機(jī)產(chǎn)生的公鑰與私鑰
? ? private static Map<Integer, String> keyMap = new HashMap<Integer, String>();
? ? public static void main(String[] args) throws Exception {
? ? ? ? //生成公鑰和私鑰
? ? ? ? genKeyPair();
? ? ? ? //加密字符串
? ? ? ? String message = "我愛(ài)你";
? ? ? ? System.out.println("隨機(jī)生成的公鑰為:" + keyMap.get(0));
? ? ? ? System.out.println("隨機(jī)生成的私鑰為:" + keyMap.get(1));
? ? ? ? String messageEn = encrypt(message,keyMap.get(0));
? ? ? ? System.out.println(message + "\t加密后的字符串為:" + messageEn);
? ? ? ? String messageDe = decrypt(messageEn,keyMap.get(1));
? ? ? ? System.out.println("還原后的字符串為:" + messageDe);
? ? }
? ? /**
? ? * 隨機(jī)生成密鑰對(duì)
? ? * @throws Exception
? ? */
? ? public static void genKeyPair() throws Exception {
? ? ? ? // KeyPairGenerator類(lèi)用于生成公鑰和私鑰對(duì)践樱,基于RSA算法生成對(duì)象
? ? ? ? KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
? ? ? ? // 初始化密鑰對(duì)生成器,密鑰大小為
? ? ? ? keyPairGen.initialize(2048,new SecureRandom());
? ? ? ? // 生成一個(gè)密鑰對(duì)凸丸,保存在keyPair中
? ? ? ? KeyPair keyPair = keyPairGen.generateKeyPair();
? ? ? ? // 得到私鑰拷邢、公鑰
? ? ? ? RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
? ? ? ? RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
? ? ? ? // 得到私鑰字符串
? ? ? ? String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
? ? ? ? String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
? ? ? ? // 將公鑰和私鑰保存到Map? 0表示公鑰? 1表示私鑰
? ? ? ? keyMap.put(0,publicKeyString);
? ? ? ? keyMap.put(1,privateKeyString);
? ? }
? ? /**
? ? * RSA公鑰加密
? ? * @param str 加密字符串
? ? * @param publicKey 公鑰
? ? * @return 密文
? ? * @throws Exception 加密過(guò)程中的異常信息
? ? */
? ? public static String encrypt( String str, String publicKey ) throws Exception{
? ? ? ? //base64編碼的公鑰
? ? ? ? byte[] decoded = Base64.decodeBase64(publicKey);
? ? ? ? RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
? ? ? ? //RSA加密
? ? ? ? Cipher cipher = Cipher.getInstance("RSA");
? ? ? ? cipher.init(Cipher.ENCRYPT_MODE, pubKey);
? ? ? ? String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
? ? ? ? return outStr;
? ? }
? ? /**
? ? * RSA私鑰解密
? ? * @param str 加密字符串
? ? * @param privateKey 私鑰
? ? * @return 明文
? ? * @throws Exception 解密過(guò)程中的異常信息
? ? */
? ? public static String decrypt(String str, String privateKey) throws Exception{
? ? ? ? //64位解碼加密后的字符串
? ? ? ? byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
? ? ? ? //base64編碼的私鑰
? ? ? ? byte[] decoded = Base64.decodeBase64(privateKey);
? ? ? ? RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
? ? ? ? //RSA解密
? ? ? ? Cipher cipher = Cipher.getInstance("RSA");
? ? ? ? cipher.init(Cipher.DECRYPT_MODE, priKey);
? ? ? ? String outStr = new String(cipher.doFinal(inputByte));
? ? ? ? return outStr;
? ? }
}
代碼運(yùn)行的結(jié)果:
隨機(jī)生成的公鑰為:
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgJW1vVhZWd8NDiTIrAJK5N4EipP5jWw8WIsWiX3SzZGpzRuz5duRjhubxS2kOoGP6GnOI8KMAHwcFCjtgQNLfvoufHG9OiRaKQEkPhypF1vsuEC0rzeOcWbzIAsWk7B6wboGd6Or4L2MAHsIrluISgICq6BU1cVb/XSPX9tbIOfrjRNsbX5DnNd39XZ4yUlqIDocCQtV3rmQlG4e4nlsJTw073/7/eNCkp7FMJVTch+rQspUPlks9V1ic9TmBhW7dszAGWz4BmIe1elar5bapivBtnVpRX+yEGZSQWkchTqSQTOeYfuh3GFDAYoWlGEx+OeUX8SsRK1V3zeiwv6lpQIDAQAB
隨機(jī)生成的私鑰為:
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCAlbW9WFlZ3w0OJMisAkrk3gSKk/mNbDxYixaJfdLNkanNG7Pl25GOG5vFLaQ6gY/oac4jwowAfBwUKO2BA0t++i58cb06JFopASQ+HKkXW+y4QLSvN45xZvMgCxaTsHrBugZ3o6vgvYwAewiuW4hKAgKroFTVxVv9dI9f21sg5+uNE2xtfkOc13f1dnjJSWogOhwJC1XeuZCUbh7ieWwlPDTvf/v940KSnsUwlVNyH6tCylQ+WSz1XWJz1OYGFbt2zMAZbPgGYh7V6VqvltqmK8G2dWlFf7IQZlJBaRyFOpJBM55h+6HcYUMBihaUYTH455RfxKxErVXfN6LC/qWlAgMBAAECggEAe+FAFWpfsuDcsAqqNmWDCBoJoATOAP0M6nUdwlqxVBGI2K1e1Q2Dnrhki0Pcm+0k2tHMotEUlob7ekSwBIJLIssfLA9cMf7Byg1qgFiWY4XRevYD3WcV2ZVImE92cdUtfySchHjv53ZVwkTGaUyP8lUbg4PVF5qrdHTuiHhJxFmqLwB6DC7HM9X2jleYJaNSZ2UwiloqkHAMDhqAu9212qZ4ISjbOg/iHDeTRKG3wIX989rsxAVSsruQm3DMZ/jeXzx8MpNjiLaT448dDSOhjhb1tOycMI7CWhYsuT7fOSFmtCtb9E3L8AVarKD2eiOqMaXj28wiuoST7lxa26hHoQKBgQDSmLPYHLXgOfJPIjuYv3IrBv9wr6H9N5FnSKYfISo8gQZJj4YWVFsc9/9vQyOOk0VvtSd28z0dixo1P4axEFe84vwVUsbgo7797nFLZWFm6tZZLgDiSgcxLhz9/5cjnY7irZMdPqKWQKkcFMm4Km8JX8BipwKVwuDiZ74enE1viQKBgQCcTpi0IxOaQQXWaDjG50MBBUIU0F1vM69apsJKeIY8XgE9Vsz/4yqwW7enIZHY15yx4btmZ/1ieOTqRI3x6SwFcgRZQD8OiKf/6WpHp7hXmTE34QJd9CPq+c8MgImd9BAX4rsdKp9pOGsTjFcAvLkU1crk/JQdht+p6VErJUwCPQKBgHLcFjqobgn9kMrYQOjugbY1+tva7t7Mj+FlHjWcQQz+0g8M2HUVTRxfplForNv2NsjWZM/bmlmipIimPTAVWcULh7GZlB6xMFoO0nvsr1MSghXhoVnKRmHsZKOj4yrppCS9xp8MqmCIo7NNIzfu7OCP+L3VmPNVdpIFQwwu840BAoGAUJx8RpK8flZAc3YmqfYE6VbT4LYhKcOHEQJlu1BzMljs3LySVvnKP0/d5FT8yc9Q4bBgHI1O8WUV8ffPGM6/REOsGHd4zb8OnX28sR2/hXXdG0txFBFgIMQa0wDLeGmxjxAAnicoNXTCTD+Zcyjhbuxfij71CFFRsmhA0zaV/6UCgYEAua9INHaJQ5VIFEyAWMHhfwQOU00BynQP0MugNwPypH9qejEzzBJ2fq8j69fxfeG2EENIiDymZMPwHybpYcipKT1aksCPu95HF1+yR6lNrSFDzn/kQu06bgB3V61wsgsKeDuDh++z381m1BONfK3MS1+BlxR/pJ59ikBLyB15tiQ=
我愛(ài)你 加密后的字符串為:
Qo2qkCPF27rfbfAV8k3uLH4ogVA8BlnhtKEvL77KH6wZQKmzrq3z794TuWU9PbJpkYLD2tALt6t0y+Rr9rpPHCqtAGXkzDddu7get/8eNs4N3i8yoOYW2ui7yny7v5cVd8ZsxSHcszmaSV+wb+5AJcMzQhOvWaRwx1WVEOkDp/qBENGFdfPJ8gecbL7YgnqzUtccaJQomQWIlXk88mAU8nAALHO/goEI2CK1HRtb+9qyQgjHU1zFhBsli5yA8NDcqiczFb/nV90yKLMhn5DpIm3gU/qquQltfnkflSk+KXe5BFThIVxcu2FBIovOaX+s82L4DJXtRZS+aCSrHOPfSg==
還原后的字符串為:我愛(ài)你
加密解密使用的秘鑰和簽名驗(yàn)簽的秘鑰使用不一樣,參考這個(gè)系列的其他文章屎慢。
4.2 非對(duì)稱(chēng)加密的特點(diǎn)
工作特點(diǎn):
用一個(gè)密鑰(公鑰)加密的數(shù)據(jù)瞭稼,只能用另一個(gè)密鑰(私鑰)來(lái)解密。
一個(gè)密鑰(私鑰)用來(lái)簽名腻惠,一個(gè)密鑰(公鑰)用來(lái)驗(yàn)簽环肘。
優(yōu)點(diǎn):
由于不必?fù)?dān)心交換的公鑰被劫持,所以非對(duì)稱(chēng)密鑰的分發(fā)更安全集灌。
密鑰數(shù)目和參與者數(shù)目相同悔雹。
在交換公鑰之前,不需要預(yù)先建立某種信任關(guān)系。
支持?jǐn)?shù)字簽名和不可否認(rèn)性腌零。
缺點(diǎn):
加密速度很慢梯找。要不用來(lái)加密上KB的數(shù)據(jù),可以用來(lái)加密key益涧,key的數(shù)據(jù)量較小锈锤。
加密后,密文會(huì)變長(zhǎng)闲询。