最新推薦文章于 2023-09-02 23:43:02 發(fā)布
一. 什么是加密
加密,是以某種特殊的算法改變原有的信息數(shù)據(jù),使得未授權(quán)的用戶即使獲得了已加密的信息,但因不知解密的方法,仍然無法了解信息的內(nèi)容。在網(wǎng)絡數(shù)據(jù)傳輸過程中會經(jīng)常用到報文加密,通常是對報文體body信息或者某些參數(shù)進行加密。大體上分為雙向加密和單向加密,而雙向加密又分為對稱加密和非對稱加密.
二.加密方式有哪些,具體怎么加密
(一).雙向加密
1 .對稱秘鑰加密
對稱秘鑰加密,就是采用這種加密方法的雙方使用方式用同樣的密鑰進行加密和解密。密鑰是控制加密及解密過程的指令。算法是一組規(guī)則,規(guī)定如何進行加密和解密
常用的對稱加密有:DES、IDEA、RC2、RC4、SKIPJACK、RC5、AES算法等
(1). DES加密(秘鑰key至少8位)
DES算法為密碼體制中的對稱密碼體制,又被成為美國數(shù)據(jù)加密標準,是1972年美國IBM公司研制的對稱密碼體制加密算法。 明文按64位進行分組, 密鑰長64位,密鑰事實上是56位參與DES運算(第8、16、24、32、40、48、56、64位是校驗位, 使得每個密鑰都有奇數(shù)個1)分組后的明文組和56位的密鑰按位替代或交換的方法形成密文組的加密方法。
以下加密方式秘鑰長度需要大于等于8
import net.minidev.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
public class DESEncryptUtil {
private static Logger LOGGER = LoggerFactory.getLogger(DESEncryptUtil.class);
//加密
public static String encrypt(String data,String key){
if(StringUtils.isBlank(data)||StringUtils.isBlank(key)){
LOGGER.info("參數(shù)和密鑰不允許為空");
return null;
}
String strs = null;
try {
byte[] bytes = encryptOrDecrypt(Cipher.ENCRYPT_MODE,data.getBytes(),key.getBytes());
// base64編碼字節(jié)
strs = new String(new Base64().encode(bytes),"utf-8");
} catch (UnsupportedEncodingException e) {
LOGGER.error("加密失敗,errormsg={}",e.getMessage());
}
return strs;
}
//解密
public static String decrypt(String data,String key){
if(StringUtils.isBlank(data)||StringUtils.isBlank(key)){
LOGGER.info("參數(shù)和密鑰不允許為空");
return null;
}
String strs = null;
try {
byte[] src = new Base64().decode(data);
byte[] bytes = encryptOrDecrypt(Cipher.DECRYPT_MODE,src,key.getBytes());
strs = new String(bytes,"utf-8");
} catch (UnsupportedEncodingException e) {
LOGGER.error("解密失敗,errormsg={}",e.getMessage());
}
return strs;
}
public static byte[] encryptOrDecrypt(int mode,byte[] data,byte[] key){
try{
// 強隨機數(shù)生成器 (RNG)
SecureRandom random = new SecureRandom();
// DESKeySpec是一個成加密密鑰的密鑰內(nèi)容的(透明)規(guī)范的接口。
DESKeySpec desKey = new DESKeySpec(key);
// 創(chuàng)建一個密匙工廠,然后用它把DESKeySpec轉(zhuǎn)換成
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
// 得到密鑰對象SecretKey
SecretKey securekey = keyFactory.generateSecret(desKey);
// Cipher對象實際完成加密操作
Cipher cipher = Cipher.getInstance("DES");
// 用密匙初始化Cipher對象
cipher.init(mode, securekey, random);
// 現(xiàn)在,獲取數(shù)據(jù)并加密,正式執(zhí)行加密操作
return cipher.doFinal(data);
}catch(Throwable e){
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
JSONObject json = new JSONObject();
json.put("首聯(lián)","一葉扁舟伴水流");
String data = encrypt(json.toJSONString(),"12345678");
System.out.println("明文是:"+json);
System.out.println("加密后:"+data);
System.out.println("解密后:"+decrypt(data,"12345678"));
}
}
運行結(jié)果是:
(2)AES加密(秘鑰key至少8位)
AES密碼學中的高級加密標準(Advanced Encryption Standard,AES),又稱 高級加密標準
Rijndael加密法,是美國聯(lián)邦政府采用的一種區(qū)塊加密標準。這個標準用來替代原先的DES,已經(jīng)被多方分析且廣為全世界所使用。經(jīng)過五年的甄選流程,高級加密標準由美國國家標準與技術(shù)研究院(NIST)于2001年11月26日發(fā)布于FIPS PUB 197,并在2002年5月26日成為有效的標準。2006年,高級加密標準已然成為對稱密鑰加密中最流行的算法之一。該算法為比利時密碼學家Joan Daemen和Vincent Rijmen所設(shè)計,結(jié)合兩位作者的名字,以Rijndael之命名之,投稿高級加密標準的甄選流程。(Rijdael的發(fā)音近于 "Rhinedoll"。)
import net.minidev.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
public class AESUtils {
private static Logger LOGGER = LoggerFactory.getLogger(AESUtils.class);
public static String encrypt(String data,String key){
if(StringUtils.isBlank(data)||StringUtils.isBlank(key)){
LOGGER.info("參數(shù)和密鑰不允許為空");
return null;
}
String strs = null;
try {
byte[] bytes = doAES(Cipher.ENCRYPT_MODE,data.getBytes(),key.getBytes());
// base64編碼字節(jié)
strs = new String(new Base64().encode(bytes),"utf-8");
} catch (UnsupportedEncodingException e) {
LOGGER.error("加密失敗,errormsg={}",e.getMessage());
}
return strs;
}
public static String decrypt(String data,String key){
if(StringUtils.isBlank(data)||StringUtils.isBlank(key)){
LOGGER.info("參數(shù)和密鑰不允許為空");
return null;
}
String strs = null;
try {
byte[] src = new Base64().decode(data);
byte[] bytes = doAES(Cipher.DECRYPT_MODE,src,key.getBytes());
strs = new String(bytes,"utf-8");
} catch (UnsupportedEncodingException e) {
LOGGER.error("解密失敗,errormsg={}",e.getMessage());
}
return strs;
}
public static byte[] doAES(int mode,byte[] data,byte[] key){
try{
//1.構(gòu)造密鑰生成器,指定為AES算法,不區(qū)分大小寫
KeyGenerator kgen = KeyGenerator.getInstance("AES");
//2.根據(jù)ecnodeRules規(guī)則初始化密鑰生成器
//生成一個128位的隨機源,根據(jù)傳入的字節(jié)數(shù)組
kgen.init(128, new SecureRandom(key));
//3.產(chǎn)生原始對稱密鑰
SecretKey secretKey = kgen.generateKey();
//4.獲得原始對稱密鑰的字節(jié)數(shù)組
byte[] enCodeFormat = secretKey.getEncoded();
//5.根據(jù)字節(jié)數(shù)組生成AES密鑰
SecretKeySpec keySpec = new SecretKeySpec(enCodeFormat,"AES");
//6.根據(jù)指定算法AES自成密碼器
Cipher cipher = Cipher.getInstance("AES");// 創(chuàng)建密碼器
//7.初始化密碼器,第一個參數(shù)為加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二個參數(shù)為使用的KEY
cipher.init(mode, keySpec);// 初始化
return cipher.doFinal(data);
}catch (Exception e){
LOGGER.error("加解密失敗,errormsg={}",e.getMessage());
}
return null;
}
public static void main(String[] args) {
JSONObject json = new JSONObject();
json.put("首聯(lián)","一葉扁舟伴水流");
String data = encrypt(json.toJSONString(),"123456789");
System.out.println("明文是:"+json);
System.out.println("加密后:"+data);
System.out.println("解密后:"+decrypt(data,"123456789"));
}
}
2 .非對稱秘鑰加密
1976年,美國學者Dime和Henman為解決信息公開傳送和密鑰管理問題,提出一種新的密鑰交換協(xié)議,允許在不安全的媒體上的通訊雙方交換信息,安全地達成一致的密鑰,這就是“公開密鑰系統(tǒng)”。相對于“對稱加密算法”這種方法也叫做“非對稱加密算法”。 與對稱加密算法不同,非對稱加密算法需要兩個密鑰:公開密鑰(publickey)和私有密鑰 (privatekey)。公開密鑰與私有密鑰是一對,如果用公開密鑰對數(shù)據(jù)進行加密,只有用對應的私有密鑰才能解密;如果用私有密鑰對數(shù)據(jù)進行加密,那么只有用對應的公開密鑰才能解密。因為加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。
(1). RSA 公鑰加密算法(1024位key的最多只能加密127位數(shù)據(jù))
RSA 公鑰加密算法是1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美國麻省理工學院)開發(fā)的。RSA取名來自開發(fā)他們?nèi)叩拿帧SA是目前最有影響力的公鑰加密算法,它能夠抵抗到目前為止已知的所有密碼攻擊,已被ISO推薦為公鑰數(shù)據(jù)加密標準。RSA算法基于一個十分簡單的數(shù)論事實:將兩個大素數(shù)相乘十分容易,但那時想要對其乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密密鑰。
import net.minidev.json.JSONObject;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
public class RSA {
/**
* 加密
* @param publicKey
* @param srcBytes
* @return
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public static byte[] encrypt(RSAPublicKey publicKey, byte[] srcBytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
if(publicKey!=null){
//Cipher負責完成加密或解密工作,基于RSA
Cipher cipher = Cipher.getInstance("RSA");
//根據(jù)公鑰,對Cipher對象進行初始化
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] resultBytes = cipher.doFinal(srcBytes);
return resultBytes;
}
return null;
}
/**
* 解密
* @param privateKey
* @param srcBytes
* @return
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public static byte[] decrypt(RSAPrivateKey privateKey, byte[] srcBytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
if(privateKey!=null){
//Cipher負責完成加密或解密工作,基于RSA
Cipher cipher = Cipher.getInstance("RSA");
//根據(jù)公鑰,對Cipher對象進行初始化
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] resultBytes = cipher.doFinal(srcBytes);
return resultBytes;
}
return null;
}
/**
* @param args
* @throws NoSuchAlgorithmException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
* @throws NoSuchPaddingException
* @throws InvalidKeyException
*/
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
JSONObject json = new JSONObject();
json.put("首聯(lián)","一葉扁舟伴水流");
//KeyPairGenerator類用于生成公鑰和私鑰對,基于RSA算法生成對象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
//初始化密鑰對生成器,密鑰大小為1024位
keyPairGen.initialize(1024);
//生成一個密鑰對,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
//得到私鑰
RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();
//得到公鑰
RSAPublicKey publicKey = (RSAPublicKey)keyPair.getPublic();
//用公鑰加密
byte[] srcBytes = json.toJSONString().getBytes();
byte[] resultBytes = encrypt(publicKey, srcBytes);
//用私鑰解密
byte[] decBytes = decrypt(privateKey, resultBytes);
System.out.println("明文是:" + json.toJSONString());
System.out.println("加密后是:" + new String(resultBytes));
System.out.println("解密后是:" + new String(decBytes));
}
}
控制臺輸出結(jié)果:
(2). DSA加密算法
Digital Signature Algorithm (DSA)是Schnorr和ElGamal簽名算法的變種,被美國NIST作為DSS(DigitalSignature Standard)。
import net.minidev.json.JSONObject;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
public class DSAUtils {
public static final String KEY_ALGORITHM = "DSA";
public static final String SIGNATURE_ALGORITHM = "DSA";
public static final String DEFAULT_SEED = "$%^*%^()(HJG8awfjas7"; //默認種子
public static final String PUBLIC_KEY = "DSAPublicKey";
public static final String PRIVATE_KEY = "DSAPrivateKey";
public static void main(String[] args) throws Exception {
JSONObject json = new JSONObject();
json.put("首聯(lián)","一葉扁舟伴水流");
String str = json.toJSONString();
byte[] data = str.getBytes();
Map<String, Object> keyMap = initKey();// 構(gòu)建密鑰
PublicKey publicKey = (PublicKey) keyMap.get(PUBLIC_KEY);
PrivateKey privateKey = (PrivateKey) keyMap.get(PRIVATE_KEY);
System.out.println("私鑰format:" + privateKey.getFormat());
System.out.println("公鑰format:" + publicKey.getFormat());
// 產(chǎn)生簽名
String sign = sign(data, getPrivateKey(keyMap));
System.out.println(sign);
// 驗證簽名
boolean verify1 = verify("aaa".getBytes(), getPublicKey(keyMap), sign);
System.err.println("經(jīng)驗證 數(shù)據(jù)和簽名匹配:" + verify1);
boolean verify = verify(data, getPublicKey(keyMap), sign);
System.err.println("經(jīng)驗證 數(shù)據(jù)和簽名匹配:" + verify);
}
/**
* 生成密鑰
*
* @param seed 種子
* @return 密鑰對象
* @throws Exception
*/
public static Map<String, Object> initKey(String seed) throws Exception {
System.out.println("生成密鑰");
KeyPairGenerator keygen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
SecureRandom secureRandom = new SecureRandom();
secureRandom.setSeed(seed.getBytes());
//Modulus size must range from 512 to 1024 and be a multiple of 64
keygen.initialize(640, secureRandom);
KeyPair keys = keygen.genKeyPair();
PrivateKey privateKey = keys.getPrivate();
PublicKey publicKey = keys.getPublic();
Map<String, Object> map = new HashMap<String, Object>(2);
map.put(PUBLIC_KEY, publicKey);
map.put(PRIVATE_KEY, privateKey);
return map;
}
/**
* 生成默認密鑰
*
* @return 密鑰對象
* @throws Exception
*/
public static Map<String, Object> initKey() throws Exception {
return initKey(DEFAULT_SEED);
}
/**
* 取得私鑰
*
* @param keyMap
* @return
* @throws Exception
*/
public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
Key key = (Key) keyMap.get(PRIVATE_KEY);
return encryptBASE64(key.getEncoded()); //base64加密私鑰
}
/**
* 取得公鑰
*
* @param keyMap
* @return
* @throws Exception
*/
public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
Key key = (Key) keyMap.get(PUBLIC_KEY);
return encryptBASE64(key.getEncoded()); //base64加密公鑰
}
/**
* 用私鑰對信息進行數(shù)字簽名
* @param data 加密數(shù)據(jù)
* @param privateKey 私鑰-base64加密的
* @return
* @throws Exception
*/
public static String sign(byte[] data, String privateKey) throws Exception {
System.out.println("用私鑰對信息進行數(shù)字簽名");
byte[] keyBytes = decryptBASE64(privateKey);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey priKey = factory.generatePrivate(keySpec);//生成 私鑰
//用私鑰對信息進行數(shù)字簽名
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(priKey);
signature.update(data);
return encryptBASE64(signature.sign());
}
/**
* BASE64Encoder 加密
* @param data 要加密的數(shù)據(jù)
* @return 加密后的字符串
*/
private static String encryptBASE64(byte[] data) {
BASE64Encoder encoder = new BASE64Encoder();
String encode = encoder.encode(data);
return encode;
}
/**
* BASE64Decoder 解密
* @param data 要解密的字符串
* @return 解密后的byte[]
* @throws Exception
*/
private static byte[] decryptBASE64(String data) throws Exception {
BASE64Decoder decoder = new BASE64Decoder();
byte[] buffer = decoder.decodeBuffer(data);
return buffer;
}
/**
* 校驗數(shù)字簽名
* @param data 加密數(shù)據(jù)
* @param publicKey
* @param sign 數(shù)字簽名
* @return
* @throws Exception
*/
public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
byte[] keyBytes = decryptBASE64(publicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(pubKey);
signature.update(data);
return signature.verify(decryptBASE64(sign)); //驗證簽名
}
}
控制臺輸出結(jié)果:
(二).單向加密
MD5 即Message-Digest Algorithm 5(信息-摘要算法 5),用于確保信息傳輸完整一致。是計算機廣泛使用的雜湊算法之一(又譯摘要算法、哈希算法),主流編程語言普遍已有MD5實現(xiàn)。將數(shù)據(jù)(如漢字)運算為另一固定長度值,是雜湊算法的基礎(chǔ)原理,MD5的前身有MD2、MD3和MD4。MD5的作用是讓大容量信息在用數(shù)字簽名軟件簽署私人密鑰前被"壓縮"成一種保密的格式(就是把一個任意長度的字節(jié)串變換成一定長的十六進制數(shù)字串)。
除了MD5以外,其中比較有名的還有sha-1、RIPEMD以及Haval等
import net.minidev.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Utils {
public static byte[] encrypt(String data) throws NoSuchAlgorithmException {
// 根據(jù)MD5算法生成MessageDigest對象
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] src = data.getBytes();
// 使用src更新摘要
md5.update(src);
// 完成哈希計算,得到result
return md5.digest();
}
public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
JSONObject json = new JSONObject();
json.put("首聯(lián)","一葉扁舟伴水流");
System.out.println("明文是:"+json);
byte[] result = encrypt(json.toJSONString());
System.out.println("密文是:"+new String(result,"utf-8"));
}
}
2.SHA加密
SHA 是一種數(shù)據(jù)加密算法,該算法經(jīng)過加密專家多年來的發(fā)展和改進已日益完善,現(xiàn)在已成為公認的最安全的散列算法之一,并被廣泛使用。該算法的思想是接收一段明文,然后以一種不可逆的方式將它轉(zhuǎn)換成一段(通常更?。┟芪模部梢院唵蔚睦斫鉃槿∫淮斎氪a(稱為預映射或信息),并把它們轉(zhuǎn)化為長度較短、位數(shù)固定的輸出序列即散列值(也稱為信息摘要或信息認證代碼)的過程。散列函數(shù)值可以說時對明文的一種“指紋”或是“摘要”所以對散列值的數(shù)字簽名就可以視為對此明文的數(shù)字簽名。
import net.minidev.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class SHAUtils {
public static byte[] encrypt(String data) throws NoSuchAlgorithmException {
// 根據(jù)SHA算法生成MessageDigest對象
MessageDigest md5 = MessageDigest.getInstance("SHA");
byte[] src = data.getBytes();
// 使用src更新摘要
md5.update(src);
// 完成哈希計算,得到result
return md5.digest();
}
public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
JSONObject json = new JSONObject();
json.put("首聯(lián)","一葉扁舟伴水流");
System.out.println("明文是:"+json);
byte[] result = encrypt(json.toJSONString());
System.out.println("密文是:"+new String(result,"utf-8"));
}
參考資料:
https://blog.csdn.net/MJM_49/article/details/77429883
https://blog.csdn.net/jjwwmlp456/article/details/21016177
文章知識點與官方知識檔案匹配,可進一步學習相關(guān)知識