資訊加密技術
-
- 一、加密的方式
-
- 1. 對稱加密
-
- 1. 簡介
- 2. 優缺點:
- 3. 經典對稱加密:
-
- DES
- AES
- 2. 非對稱加密
-
- 1. 用法
- 2. 典型非對稱加密——RSA
- 3. 實作原理
- 4. 特點
- 5. 對比
- 6. RSA應用場景:
- 3. 單向散列加密
-
- 特點
- 二、加密算法實作
-
- 1. 非對稱加密(RSA)
-
- 1. 生成秘鑰
- 2. 前端對利用公鑰對資料進行加密
- 3. 後端利用私鑰對資料進行解密
- 2. 對稱加密
-
- AES
- 3. 單向散列加密
-
- MD5
- SHA1
- 三、加密算法比較
一、加密的方式
1. 對稱加密
1. 簡介
加密和解密使用同一個密鑰。
2. 優缺點:
- 算法公開,計算量小,加密速度快,加密效率高
- 雙方使用相同的鑰匙,安全性得不到保證
- 秘鑰管理比較難,不适合網際網路,一般用于内部系統
3. 經典對稱加密:
- DES(Data Encryption Standard):資料加密标準(現在用的比較少,因為它的加密強度不夠,能夠暴力破解)
- 3DES:原理和DES幾乎是一樣的,隻是使用3個密鑰,對相同的資料執行三次加密,增強加密強度。(缺點:要維護3個密鑰,大大增加了維護成本)
- AES(Advanced Encryption Standard):進階加密标準,目前美國國家安全局使用的,蘋果的鑰匙串通路采用的就AES加密。是現在公認的最安全的加密方式,是對稱密鑰加密中最流行的算法。
DES
DES(Data Encryption Standard)是目前最為流行的加密算法之一。DES是對稱的,也就是說它使用同一個密鑰來加密和解密資料。
原理
DES 使用一個 56 位的密鑰以及附加的 8 位奇偶校驗位,産生最大 64 位的分組大小。這是一個疊代的分組密碼,使用稱為 Feistel 的技術,其中将加密的文本塊分成兩半。使用子密鑰對其中一半應用循環功能,然後将輸出與另一半進行"異或"運算;接着交換這兩半,這一過程會繼續下去,但最後一個循環不交換。DES 使用 16 個循環,使用異或,置換,代換,移位操作四種基本運算。
不過,DES已可破解,是以針對保密級别特别高的資料推薦使用非對稱加密算法。
優缺點
AES
屬性
- 秘鑰
用來加密明文的密碼,在對稱加密算法中,加密與解密的密鑰是相同的。密鑰為接收方與發送方協商産生,但不可以直接在網絡上傳輸,否則會導緻密鑰洩漏,通常是通過非對稱加密算法加密密鑰,然後再通過網絡傳輸給對方,或者直接面對面商量密鑰。密鑰是絕對不可以洩漏的,否則會被攻擊者還原密文,竊取機密資料。
- AES加密函數
設AES加密函數為E,則 C = E(K, P),其中P為明文,K為密鑰,C為密文。也就是說,把明文P和密鑰K作為加密函數的參數輸入,則加密函數E會輸出密文C。
- AES解密函數
設AES解密函數為D,則 P = D(K, C),其中C為密文,K為密鑰,P為明文。也就是說,把密文C和密鑰K作為解密函數的參數輸入,則解密函數會輸出明文P。
原理
基于原理逐漸實作AES加密算法
2. 非對稱加密
1. 用法
(1)乙方生成兩把密鑰(公鑰和私鑰)。公鑰是公開的,任何人都可以獲得,私鑰則是保密的。
(2)甲方擷取乙方的公鑰,然後用它對資訊加密。
(3)乙方得到加密後的資訊,用私鑰解密。
2. 典型非對稱加密——RSA
RSA非常可靠,密鑰越長,它就越難破解。根據已經披露的文獻,目前被破解的最長RSA密鑰是768個二進制位。也就是說,長度超過768位的密鑰,還無法破解(至少沒人公開宣布)。是以可以認為,1024位的RSA密鑰基本安全,2048位的密鑰極其安全。
3. 實作原理
RSA算法原理
4. 特點
- 算法強度複雜,安全性依賴于算法與密鑰。
- 加密解密速度慢。适合 小資料量 加解密或資料簽名
- 密鑰容易管理
5. 對比
與對稱加密算法的對比:
- 對稱加密隻有一種密鑰,并且是非公開的,如果要解密就得讓對方知道密鑰。
- 非對稱加密有兩種密鑰,其中一個是公開的。
6. RSA應用場景:
由于RSA算法的加密解密速度要比對稱算法速度慢很多,在實際應用中,通常采取
資料本身的加密和解密使用對稱加密算法(AES)。
用RSA算法加密并傳輸對稱算法所需的密鑰。
3. 單向散列加密
不可逆,隻能加密,不能解密
單向散列加密是指通過對不同輸入長度的資訊進行散列計算,得到固定長度的輸出,這個散列計算過程是單向的,即不能對固定長度的輸出進行計算進而獲得輸入資訊。
利用單向散列加密的這個特性,可以進行密碼加密儲存,即使用者注冊時輸入的密碼不直接儲存到資料庫,而是對密碼進行單向散列加密,将密文存入資料庫,使用者登入時,進行密碼驗證,同樣計算得到輸入密碼的密文,并和資料庫中的密文比較,如果一緻,則密碼驗證成功。為了加強單向散列計算的安全性,還會給雜湊演算法加點salt,salt相當于加密的密鑰,增加破解的難度。常用的單向雜湊演算法有MD5、SHA等。
特點
- 算法強度複雜
- 無秘鑰
二、加密算法實作
1. 非對稱加密(RSA)
前端公鑰加密,後端私鑰解密。
1. 生成秘鑰
利用線上生成秘鑰工具生成非對稱加密公鑰私鑰對
線上生成非對稱公鑰私鑰對
2. 前端對利用公鑰對資料進行加密
工具類
import JSEncrypt from 'jsencrypt/bin/jsencrypt'
// 密鑰對生成 http://web.chacuo.net/netrsakeypair
const publicKey = '...'
const privateKey = '...'
// 加密
export function encrypt(txt) {
const encryptor = new JSEncrypt()
encryptor.setPublicKey(publicKey) // 設定公鑰
return encryptor.encrypt(txt) // 對需要加密的資料進行加密
}
// 解密
export function decrypt(txt) {
const encryptor = new JSEncrypt()
encryptor.setPrivateKey(privateKey)
return encryptor.decrypt(txt)
}
使用公鑰加密
3. 後端利用私鑰對資料進行解密
工具類
package com.advance.utils;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* description Rsa 工具類,公鑰私鑰生成,加解密
* @author https://www.cnblogs.com/nihaorz/p/10690643.html
* @date 2020-12-15
**/
public class RsaUtils {
private static final String SRC = "123456";
public static void main(String[] args) throws Exception {
System.out.println("\n");
RsaKeyPair keyPair = generateKeyPair();
System.out.println("公鑰:" + keyPair.getPublicKey());
System.out.println("私鑰:" + keyPair.getPrivateKey());
System.out.println("\n");
test1(keyPair);
System.out.println("\n");
test2(keyPair);
System.out.println("\n");
}
/**
* 公鑰加密私鑰解密
*/
private static void test1(RsaKeyPair keyPair) throws Exception {
System.out.println("***************** 公鑰加密私鑰解密開始 *****************");
String text1 = encryptByPublicKey(keyPair.getPublicKey(), RsaUtils.SRC);
String text2 = decryptByPrivateKey(keyPair.getPrivateKey(), text1);
System.out.println("加密前:" + RsaUtils.SRC);
System.out.println("加密後:" + text1);
System.out.println("解密後:" + text2);
if (RsaUtils.SRC.equals(text2)) {
System.out.println("解密字元串和原始字元串一緻,解密成功");
} else {
System.out.println("解密字元串和原始字元串不一緻,解密失敗");
}
System.out.println("***************** 公鑰加密私鑰解密結束 *****************");
}
/**
* 私鑰加密公鑰解密
* @throws Exception /
*/
private static void test2(RsaKeyPair keyPair) throws Exception {
System.out.println("***************** 私鑰加密公鑰解密開始 *****************");
String text1 = encryptByPrivateKey(keyPair.getPrivateKey(), RsaUtils.SRC);
String text2 = decryptByPublicKey(keyPair.getPublicKey(), text1);
System.out.println("加密前:" + RsaUtils.SRC);
System.out.println("加密後:" + text1);
System.out.println("解密後:" + text2);
if (RsaUtils.SRC.equals(text2)) {
System.out.println("解密字元串和原始字元串一緻,解密成功");
} else {
System.out.println("解密字元串和原始字元串不一緻,解密失敗");
}
System.out.println("***************** 私鑰加密公鑰解密結束 *****************");
}
/**
* 公鑰解密
*
* @param publicKeyText 公鑰
* @param text 待解密的資訊
* @return /
* @throws Exception /
*/
public static String decryptByPublicKey(String publicKeyText, String text) throws Exception {
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
byte[] result = cipher.doFinal(Base64.decodeBase64(text));
return new String(result);
}
/**
* 私鑰加密
*
* @param privateKeyText 私鑰
* @param text 待加密的資訊
* @return /
* @throws Exception /
*/
public static String encryptByPrivateKey(String privateKeyText, String text) throws Exception {
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] result = cipher.doFinal(text.getBytes());
return Base64.encodeBase64String(result);
}
/**
* 私鑰解密
*
* @param privateKeyText 私鑰
* @param text 待解密的文本
* @return /
* @throws Exception /
*/
public static String decryptByPrivateKey(String privateKeyText, String text) throws Exception {
PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] result = cipher.doFinal(Base64.decodeBase64(text));
return new String(result);
}
/**
* 公鑰加密
*
* @param publicKeyText 公鑰
* @param text 待加密的文本
* @return /
*/
public static String encryptByPublicKey(String publicKeyText, String text) throws Exception {
X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] result = cipher.doFinal(text.getBytes());
return Base64.encodeBase64String(result);
}
/**
* 建構RSA密鑰對
*
* @return /
* @throws NoSuchAlgorithmException /
*/
public static RsaKeyPair generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
return new RsaKeyPair(publicKeyString, privateKeyString);
}
/**
* RSA密鑰對對象
*/
public static class RsaKeyPair {
private final String publicKey;
private final String privateKey;
public RsaKeyPair(String publicKey, String privateKey) {
this.publicKey = publicKey;
this.privateKey = privateKey;
}
public String getPublicKey() {
return publicKey;
}
public String getPrivateKey() {
return privateKey;
}
}
}
使用私鑰解密
2. 對稱加密
java實作AES加密解密算法
AES
package com.marchosft.security;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
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;
import java.util.Base64;
/**
* Description:java實作AES加密解密算法 AES加密結果用Base64再做加密處理
* Date: 2020/12/16 10:59
**/
public class AesUtil {
private static final String DEFAULT_KEY = "12345678";
static final Base64.Decoder DECODER = Base64.getDecoder();
static final Base64.Encoder ENCODER = Base64.getEncoder();
static final String CHARSET = "utf-8";
static final String AES = "AES";
/**
* 先AES加密,再Base64加密
*
* @param content 待加密的内容
* @return /
*/
public static String encodeBase64(String content) {
//AES加密
String encode = encode(content);
//加密失敗傳回空
if (encode == null) {
return null;
}
try {
//Base64加密
return ENCODER.encodeToString(encode.getBytes(CHARSET));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* 先Base64解密,再AES解密
*
* @param content 待解密的内容
* @return /
*/
public static String decodeBase64(String content) {
try {
//Base64解密
String s = new String(DECODER.decode(content), CHARSET);
//AES解密
return decode(s);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//解密失敗傳回空
return null;
}
/**
* AES加密
*
* @param content 待加密的内容
* @return /
*/
public static String encode(String content) {
return encode(DEFAULT_KEY, content);
}
/**
* AES解密
*
* @param content 待解密的内容
* @return /
*/
public static String decode(String content) {
return decode(DEFAULT_KEY, content);
}
/**
* AES加密
* 1.構造密鑰生成器
* 2.根據ecnodeRules規則初始化密鑰生成器
* 3.産生密鑰
* 4.建立和初始化密碼器
* 5.内容加密
* 6.傳回字元串
*/
public static String encode(String encodeRules, String content) {
try {
//1.構造密鑰生成器,指定為AES算法,不區分大小寫
KeyGenerator keygen = KeyGenerator.getInstance(AES);
//2.根據ecnodeRules規則初始化密鑰生成器
//生成一個128位的随機源,根據傳入的位元組數組
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(encodeRules.getBytes());
keygen.init(128, random);
//3.産生原始對稱密鑰
SecretKey originalKey = keygen.generateKey();
// 4.獲得原始對稱密鑰的位元組數組
byte[] raw = originalKey.getEncoded();
//5.根據位元組數組生成AES密鑰
SecretKey key = new SecretKeySpec(raw, AES);
//6.根據指定算法AES自成密碼器
Cipher cipher = Cipher.getInstance(AES);
//7.初始化密碼器,第一個參數為加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二個參數為使用的KEY
cipher.init(Cipher.ENCRYPT_MODE, key);
//8.擷取加密内容的位元組數組(這裡要設定為utf-8)不然内容中如果有中文和英文混合中文就會解密為亂碼
byte[] byteEncode = content.getBytes(CHARSET);
//9.根據密碼器的初始化方式--加密:将資料加密
byte[] byteAes = cipher.doFinal(byteEncode);
//10.将加密後的資料轉換為字元串
//這裡用Base64Encoder中會找不到包
//解決辦法:
//在項目的Build path中先移除JRE System Library,再添加庫JRE System Library,重新編譯後就一切正常了。
//11.将字元串傳回
return new String(new BASE64Encoder().encode(byteAes));
} catch (Exception e) {
e.printStackTrace();
}
//加密失敗傳回空
return null;
}
/**
* AES解密
* 解密過程:
* 1.同加密1-4步
* 2.将加密後的字元串反紡成byte[]數組
* 3.将加密内容解密
*/
public static String decode(String encodeRules, String content) {
try {
//1.構造密鑰生成器,指定為AES算法,不區分大小寫
KeyGenerator keygen = KeyGenerator.getInstance(AES);
//2.根據ecnodeRules規則初始化密鑰生成器
//生成一個128位的随機源,根據傳入的位元組數組
// keygen.init(128, new SecureRandom(encodeRules.getBytes()));
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(encodeRules.getBytes());
keygen.init(128, random);
//3.産生原始對稱密鑰
SecretKey originalKey = keygen.generateKey();
//4.獲得原始對稱密鑰的位元組數組
byte[] raw = originalKey.getEncoded();
//5.根據位元組數組生成AES密鑰
SecretKey key = new SecretKeySpec(raw, AES);
//6.根據指定算法AES自成密碼器
Cipher cipher = Cipher.getInstance(AES);
//7.初始化密碼器,第一個參數為加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二個參數為使用的KEY
cipher.init(Cipher.DECRYPT_MODE, key);
//8.将加密并編碼後的内容解碼成位元組數組
byte[] byteContent = new BASE64Decoder().decodeBuffer(content);
/*
* 解密
*/
byte[] byteDecode = cipher.doFinal(byteContent);
return new String(byteDecode, CHARSET);
} catch (Exception e) {
e.printStackTrace();
}
//解密失敗傳回空
return null;
}
public static void main(String[] args) {
String a = "1236";
String s = encodeBase64(a);
System.out.println(s);
String s1 = decodeBase64(s);
System.out.println(s1);
}
}
3. 單向散列加密
MD5
public static final byte[] computeMD5(byte[] content) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
return md5.digest(content);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
SHA1
public static byte[] computeSHA1(byte[] content) {
try {
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
return sha1.digest(content);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
三、加密算法比較
1、雜湊演算法比較
名稱 | 安全性 | 速度 |
---|---|---|
SHA-1 | 高 | 慢 |
MD5 | 中 | 快 |
2、對稱加密算法比較
名稱 | 密鑰名稱 | 運作速度 | 安全性 | 資源消耗 |
---|---|---|---|---|
DES | 56位 | 較快 | 低 | 中 |
3DES | 112位或168位 | 慢 | 中 | 高 |
AES | 128、192、256位 | 快 | 高 | 低 |
3、非對稱加密算法比較
名稱 | 成熟度 | 安全性 | 運算速度 | 資源消耗 |
---|---|---|---|---|
RSA | 高 | 高 | 中 | 中 |
ECC | 高 | 高 | 慢 | 高 |