安全系列之——手寫(xiě) JAVA 加密、解密

軟件的加密與解密是一個(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)闲询。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末久免,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子扭弧,更是在濱河造成了極大的恐慌妄壶,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寄狼,死亡現(xiàn)場(chǎng)離奇詭異丁寄,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)泊愧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)伊磺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人删咱,你說(shuō)我怎么就攤上這事屑埋。” “怎么了痰滋?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵摘能,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我敲街,道長(zhǎng)团搞,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任多艇,我火速辦了婚禮逻恐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘峻黍。我一直安慰自己复隆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布姆涩。 她就那樣靜靜地躺著挽拂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪骨饿。 梳的紋絲不亂的頭發(fā)上亏栈,一...
    開(kāi)封第一講書(shū)人閱讀 49,764評(píng)論 1 290
  • 那天洪鸭,我揣著相機(jī)與錄音,去河邊找鬼仑扑。 笑死览爵,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的镇饮。 我是一名探鬼主播蜓竹,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼储藐!你這毒婦竟也來(lái)了俱济?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤钙勃,失蹤者是張志新(化名)和其女友劉穎蛛碌,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體辖源,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蔚携,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了克饶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酝蜒。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖矾湃,靈堂內(nèi)的尸體忽然破棺而出亡脑,到底是詐尸還是另有隱情,我是刑警寧澤邀跃,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布霉咨,位于F島的核電站,受9級(jí)特大地震影響拍屑,放射性物質(zhì)發(fā)生泄漏途戒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一丽涩、第九天 我趴在偏房一處隱蔽的房頂上張望棺滞。 院中可真熱鬧,春花似錦矢渊、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至室谚,卻和暖如春毡鉴,著一層夾襖步出監(jiān)牢的瞬間崔泵,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工猪瞬, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留憎瘸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓陈瘦,卻偏偏與公主長(zhǎng)得像幌甘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子痊项,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348