天天看點

資訊加密技術 MD5 對稱加密 非對稱加密

資訊加密技術

    • 一、加密的方式
      • 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. 簡介

加密和解密使用同一個密鑰。

資訊加密技術 MD5 對稱加密 非對稱加密

2. 優缺點:

  • 算法公開,計算量小,加密速度快,加密效率高
  • 雙方使用相同的鑰匙,安全性得不到保證
  • 秘鑰管理比較難,不适合網際網路,一般用于内部系統

3. 經典對稱加密:

  1. DES(Data Encryption Standard):資料加密标準(現在用的比較少,因為它的加密強度不夠,能夠暴力破解)
  2. 3DES:原理和DES幾乎是一樣的,隻是使用3個密鑰,對相同的資料執行三次加密,增強加密強度。(缺點:要維護3個密鑰,大大增加了維護成本)
  3. AES(Advanced Encryption Standard):進階加密标準,目前美國國家安全局使用的,蘋果的鑰匙串通路采用的就AES加密。是現在公認的最安全的加密方式,是對稱密鑰加密中最流行的算法。
DES

DES(Data Encryption Standard)是目前最為流行的加密算法之一。DES是對稱的,也就是說它使用同一個密鑰來加密和解密資料。

原理

DES 使用一個 56 位的密鑰以及附加的 8 位奇偶校驗位,産生最大 64 位的分組大小。這是一個疊代的分組密碼,使用稱為 Feistel 的技術,其中将加密的文本塊分成兩半。使用子密鑰對其中一半應用循環功能,然後将輸出與另一半進行"異或"運算;接着交換這兩半,這一過程會繼續下去,但最後一個循環不交換。DES 使用 16 個循環,使用異或,置換,代換,移位操作四種基本運算。

不過,DES已可破解,是以針對保密級别特别高的資料推薦使用非對稱加密算法。

資訊加密技術 MD5 對稱加密 非對稱加密

優缺點

AES
資訊加密技術 MD5 對稱加密 非對稱加密

屬性

  1. 秘鑰
用來加密明文的密碼,在對稱加密算法中,加密與解密的密鑰是相同的。密鑰為接收方與發送方協商産生,但不可以直接在網絡上傳輸,否則會導緻密鑰洩漏,通常是通過非對稱加密算法加密密鑰,然後再通過網絡傳輸給對方,或者直接面對面商量密鑰。密鑰是絕對不可以洩漏的,否則會被攻擊者還原密文,竊取機密資料。
  1. AES加密函數
設AES加密函數為E,則 C = E(K, P),其中P為明文,K為密鑰,C為密文。也就是說,把明文P和密鑰K作為加密函數的參數輸入,則加密函數E會輸出密文C。
  1. 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算法加密并傳輸對稱算法所需的密鑰。

資訊加密技術 MD5 對稱加密 非對稱加密

3. 單向散列加密

不可逆,隻能加密,不能解密

單向散列加密是指通過對不同輸入長度的資訊進行散列計算,得到固定長度的輸出,這個散列計算過程是單向的,即不能對固定長度的輸出進行計算進而獲得輸入資訊。

利用單向散列加密的這個特性,可以進行密碼加密儲存,即使用者注冊時輸入的密碼不直接儲存到資料庫,而是對密碼進行單向散列加密,将密文存入資料庫,使用者登入時,進行密碼驗證,同樣計算得到輸入密碼的密文,并和資料庫中的密文比較,如果一緻,則密碼驗證成功。為了加強單向散列計算的安全性,還會給雜湊演算法加點salt,salt相當于加密的密鑰,增加破解的難度。常用的單向雜湊演算法有MD5、SHA等。

特點

  • 算法強度複雜
  • 無秘鑰

二、加密算法實作

1. 非對稱加密(RSA)

前端公鑰加密,後端私鑰解密。

資訊加密技術 MD5 對稱加密 非對稱加密

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