什麼是密碼學?
密碼學是保護信息安全的科學,它通過加密技術將可讀的信息(明文)轉換為不可讀的形式(密文),只有授權方才能解密恢復原始內容。就像給信息上了一把"數字鎖",只有擁有正確"鑰匙"的人才能打開

一、古典密碼學:密碼學的起源

古典密碼學主要靠 “替換” 和 “移位”,原理簡單,適合手動計算,常見於戰爭、書信保密。

1.1 核心原理

① 替換法 - 用固定規則替換原文中的字符

示例:bee 
b → w, e → p
密文:wpp

分類:

  • 單表替換:所有字符使用同一張替換表
原始:abcde
替換:swtrp

缺點:容易被破解 —— 比如英文中 “e” 出現頻率最高,只要統計密文中哪個字符出現最多,大概率就是 “e” 的替換。

  • 多表替換:使用多張替換表,按密鑰輪換使用
表1:abcde → swtrp
表2:abcde → chfhk  
表3:abcde → jftou

原文:bee
密鑰:312(表示用表3、表1、表2)
密文:fpk

優點:比單表安全,破解難度高很多。

② 移位法 - 按字母表位置移動字符

把字母表按固定位數 “平移”,最經典的是 “凱撒加密”(凱撒大帝用來給軍隊發命令)。

凱撒加密示例:
原始:abcde
後移2位:cdefg
"hello" → "jgnnq"

缺點:移位位數有限(最多 25 位),暴力嘗試幾次就能破解。

1.2 古典密碼的破解

頻率分析法:利用字母出現的統計規律

  • 英文中’e’出現頻率最高(約12.7%)
  • ‘t’, ‘a’, 'o’等也有明顯特徵
  • 通過分析密文字母頻率推測替換規則

歷史名機恩尼格瑪密碼機(二戰時期德國使用,後被圖靈破解)

二、現代密碼學三大支柱

現代密碼學不再靠人工 / 簡單機器,而是靠數學算法,能應對海量數據、高併發場景,核心分 3 類:散列函數、對稱加密、非對稱加密

2.1 散列函數(哈希函數):“不可逆的指紋”

散列函數能把任意長度的明文,變成固定長度、不可逆的密文(叫 “哈希值” 或 “消息摘要”),就像給信息蓋 “唯一指紋”。

核心特點:

  • 不可逆:知道哈希值,無法反推明文(比如知道 “123” 的 MD5 是 “202cb962ac59075b964b07152d234b70”,沒法反推 “123”);
  • 唯一性:不同明文(除非刻意構造 “碰撞”)的哈希值一定不同;
  • 固定長度:不管明文是 1 字節還是 1GB,哈希值長度固定(比如 MD5 是 32 位十六進制,SHA-256 是 64 位十六進制)。

常見算法及用途:

算法

哈希值長度

用途

例子(明文 “123”)

MD5

32 位十六進制

文件校驗、密碼存儲(已逐漸被淘汰,易碰撞)

202cb962ac59075b964b07152d234b70

SHA-1(Secure Hash Algorithm)

40 位十六進制

早期 Git 版本控制(已淘汰)

40bd001563085fc35165329ea1ff5c5ecbdbbeef

SHA-256

64 位十六進制

現在主流(文件校驗、區塊鏈、密碼存儲)

a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3

實戰場景:

  • 網站存密碼:不會存明文 “123456”,而是存它的 SHA-256 哈希值,登錄時比對哈希值(即使數據庫泄露,黑客也拿不到明文密碼);
  • 下載軟件校驗:官方給出安裝包的 SHA-256 值,你下載後算一遍,如果一致,説明沒被篡改。

Java 代碼示例(計算 MD5):

import java.security.MessageDigest;

public class HashDemo {
    public static void main(String[] args) throws Exception {
        String input = "123"; // 明文
        // 1. 獲取MD5算法實例
        MessageDigest md = MessageDigest.getInstance("MD5");
        // 2. 計算哈希值(字節數組)
        byte[] hashBytes = md.digest(input.getBytes());
        // 3. 轉成16進制字符串(方便查看)
        StringBuilder sb = new StringBuilder();
        for (byte b : hashBytes) {
            sb.append(String.format("%02x", b)); // %02x表示補0成2位十六進制
        }
        System.out.println("MD5哈希值:" + sb.toString()); // 輸出:202cb962ac59075b964b07152d234b70
    }
}

2.2 對稱加密:同一把鑰匙

加密和解密用同一把密鑰,就像你家的門,鑰匙既能鎖門也能開門。特點是 “快”,適合加密大量數據。

(1)常見算法對比:

算法

密鑰長度

特點

用途

DES

8 字節(64 位,含 1 位校驗)

早期算法,安全性低(已淘汰)

舊系統兼容

3DES

24 字節(3 個 DES 密鑰)

對 DES 三次加密,安全性提高,但速度慢

舊金融系統

AES

16/192/256 字節(推薦 16 字節)

現在主流,速度快、安全性高

手機支付、文件加密、HTTPS 數據傳輸

技術分類:

  • 流加密:逐位加密,如RC4
    123456789 → 先加密1,再加密2,再加密3…
  • 塊加密:分組加密,如AES
    12345678 → 分成[1234]和[5678]分別加密
    特點:
  • ✅ 加密速度快
  • ✅ 適合大數據量加密
  • ❌ 密鑰分發和管理困難
  • ❌ 無法實現數字簽名

(2)關鍵概念:加密模式 + 填充模式

對稱加密按 “塊” 處理數據(比如 AES 每次處理 16 字節),需要解決 “數據不夠塊長” 和 “相同明文出相同密文” 的問題:

① 加密模式:決定怎麼處理多塊數據

模式

特點

優點

缺點

ECB

每塊獨立加密,相同明文塊出相同密文塊

並行處理,速度快

不安全(容易被破解規律)

CBC

每塊先和前一塊密文 “異或”,再加密

相同明文出不同密文,安全

串行處理,速度稍慢(需要初始向量 IV)

例子:加密 “abcabcabc”(AES-16 字節,ECB vs CBC)

  • ECB:兩個 “abc” 塊加密後密文相同;
  • CBC:第一個 “abc” 用 IV 加密,第二個 “abc” 和第一個密文異或後加密,密文不同。
    推薦:用 CBC 模式,更安全。
② 填充模式:解決 “數據不夠塊長”

如果數據長度不是塊長的整數倍(比如 AES-16 字節,數據只有 10 字節),需要 “補滿”:

  • NoPadding:不填充,要求數據必須是塊長的整數倍(否則報錯);
  • PKCS5Padding:缺 n 字節就補 n 個 “n”(比如缺 6 字節,補 6 個 “\x06”),最常用。

(3)實戰注意:結合 Base64

對稱加密的密文是 “字節數組”(比如[65, -12, 34]),直接傳輸會亂碼,所以通常用Base64 編碼轉成字符串(比如 “QT4i”)。
⚠️ 注意:Base64 是編碼不是加密,目的是 “方便傳輸”,不是 “保密”!

(4)Java 代碼示例(AES-CBC 加密):

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class AesDemo {
    // AES密鑰(16字節)、初始向量IV(16字節,CBC模式必須)
    private static final String KEY = "1234567890abcdef"; 
    private static final String IV = "abcdef1234567890";

    // 加密:明文→密文(Base64字符串)
    public static String encrypt(String plaintext) throws Exception {
        // 1. 生成密鑰和IV
        SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(), "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes());
        // 2. 初始化Cipher(CBC模式+PKCS5Padding)
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        // 3. 加密→Base64編碼
        byte[] cipherBytes = cipher.doFinal(plaintext.getBytes());
        return Base64.getEncoder().encodeToString(cipherBytes);
    }

    // 解密:密文(Base64字符串)→明文
    public static String decrypt(String ciphertext) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(), "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes());
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        // 4. Base64解碼→解密
        byte[] plainBytes = cipher.doFinal(Base64.getDecoder().decode(ciphertext));
        return new String(plainBytes);
    }

    public static void main(String[] args) throws Exception {
        String plaintext = "我是秘密消息";
        // 加密
        String ciphertext = encrypt(plaintext);
        System.out.println("加密後(Base64):" + ciphertext); // 比如:xY+...(長字符串)
        // 解密
        String decrypted = decrypt(ciphertext);
        System.out.println("解密後:" + decrypted); // 輸出:我是秘密消息
    }
}

3. 非對稱加密:“公鑰加密,私鑰解密”

用一對密鑰(公鑰 + 私鑰):公鑰可以公開(像地址一樣分享給別人),私鑰自己保存(絕對不能泄露)。特點是 “安全”,但速度慢,適合加密少量數據(比如密鑰)。

(1)核心規則:

  • 公鑰加密的密文,只有對應的私鑰能解密;
  • 私鑰加密的密文(叫 “數字簽名”),只有對應的公鑰能解密;
  • 公鑰由私鑰生成,無法從公鑰反推私鑰。

(2)常見算法對比:

算法

密鑰長度

特點

用途

RSA

1024/2048/4096 位(推薦 2048 位)

兼容性好,應用廣

數字簽名、密鑰交換(HTTPS)

ECC

160/256 位

相同安全級下,密鑰更短、速度更快

移動端加密、區塊鏈(比特幣用 ECC)

DSA

1024 位

只用於數字簽名,不能加密數據

身份驗證

(3)實戰場景:HTTPS 的 “密鑰交換”**

HTTPS 為什麼安全?
因為它結合了 “對稱 + 非對稱” 加密:

  1. 瀏覽器向服務器要 “公鑰”;
  2. 瀏覽器用公鑰加密 “對稱密鑰”(比如 AES 密鑰),發給服務器;
  3. 服務器用私鑰解密,拿到對稱密鑰;
  4. 後續數據傳輸,都用對稱密鑰加密(快)。
    —— 既解決了對稱加密 “密鑰難傳輸” 的問題,又解決了非對稱加密 “慢” 的問題。

(4)Java 代碼示例(RSA 生成密鑰對 + 加密):

import javax.crypto.Cipher;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;

public class RsaDemo {
    public static void main(String[] args) throws Exception {
        String algorithm = "RSA";
        String plaintext = "要傳輸的AES密鑰:1234567890abcdef";

        // 1. 生成RSA密鑰對(公鑰+私鑰)
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(algorithm);
        keyPairGen.initialize(2048); // 密鑰長度2048位
        KeyPair keyPair = keyPairGen.generateKeyPair();
        PublicKey publicKey = keyPair.getPublic(); // 公鑰(可公開)
        PrivateKey privateKey = keyPair.getPrivate(); // 私鑰(自己存)

        // 2. 打印公鑰和私鑰(Base64編碼,方便查看)
        System.out.println("公鑰(Base64):" + Base64.getEncoder().encodeToString(publicKey.getEncoded()));
        System.out.println("私鑰(Base64):" + Base64.getEncoder().encodeToString(privateKey.getEncoded()));

        // 3. 公鑰加密(加密少量數據,比如對稱密鑰)
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes());
        String encrypted = Base64.getEncoder().encodeToString(encryptedBytes);
        System.out.println("公鑰加密後:" + encrypted);

        // 4. 私鑰解密
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encrypted));
        String decrypted = new String(decryptedBytes);
        System.out.println("私鑰解密後:" + decrypted); // 輸出:要傳輸的AES密鑰:1234567890abcdef
    }
}

三、密碼學實戰指南

3.1 對稱 vs 非對稱:如何選擇?

特性

對稱加密

非對稱加密

速度

快(適合大數據)

慢(適合小數據)

密鑰管理

複雜(密鑰分發難)

簡單(公鑰可公開)

簽名功能

不支持

支持

典型應用

文件加密、數據庫加密

密鑰交換、數字簽名

最佳實踐: 結合兩者優勢

  • 用非對稱加密安全傳輸對稱加密的密鑰
  • 用對稱加密快速加密實際數據

3.2 密鑰長度建議

  • RSA:至少2048位(1024位已不安全)
  • ECC:256位(相當於RSA 3072位安全性)
  • AES:128位(平衡安全與性能)

密鑰越長越安全?
不一定!AES-128 位已經足夠安全(破解需要的算力遠超全球總和),更長的密鑰(如 256 位)會增加性能消耗,沒必要。

3.3 Base64:不是加密的編碼

重要認知: Base64不是加密算法!它只是 “字節→字符串” 的編碼方式,目的是讓二進制數據能夠用文本形式安全傳輸,“避免傳輸亂碼”。
原理: 每3個字節(24位)轉換為4個6位的Base64字符

  • 1 字節 = 8 位,3 字節 = 24 位;
  • 把 24 位分成 4 組,每組 6 位;
  • 6 位最大是 63(2^6-1),對應 64 個字符(A-Z、a-z、0-9、+、/);
  • 如果不足 3 字節,缺 1 字節補 1 個 “=”,缺 2 字節補 2 個 “=”。

例子:編碼 “ab”(2 字節 = 16 位)

  • 16 位→補 8 位 0→24 位,分成 4 組 6 位;
  • 對應 Base64 字符:Y、W、I、=;
  • 最終編碼結果:“YWI=”。

與Base58區別:
Base58(Base64 的 “簡化版”):Base58 去掉了容易混淆的字符(0、O、1、l)和特殊符號(+、/),適合手寫或肉眼識別,比如比特幣地址用 Base58 編碼。

3.4 數字簽名:網絡世界的"手寫簽名"

數字簽名用 “私鑰簽名,公鑰驗證”,解決 “信息被篡改” 和 “發件人抵賴” 的問題
作用:

  • 身份認證:證明消息發送者的身份
  • 完整性驗證:確保消息未被篡改
  • 不可否認:發送者不能否認發送過的消息

實現過程:

  1. 對消息計算哈希值
  2. 用私鑰加密哈希值(這就是數字簽名)
  3. 接收方用公鑰解密並驗證哈希值

比如軟件發佈:

  1. 軟件開發者用私鑰對 “軟件哈希值” 簽名(生成簽名文件);
  2. 用户下載軟件後,算軟件的哈希值,並用開發者的公鑰驗證簽名
  3. 如果驗證通過,説明軟件沒被篡改,且確實是開發者發佈的。

四、實際開發注意事項

4.1 字符串處理陷阱

加密解密後,一定要用**new String()**,別用toString()!

// ❌ 錯誤方式 - 會輸出哈希值而不是實際內容
byte[] data = "hello".getBytes();
System.out.println(data.toString()); // 輸出: [B@1540e19d

// ✅ 正確方式 - 使用明確的字符編碼
System.out.println(new String(data, "UTF-8")); // 輸出: hello

4.2 現代密碼學發展趨勢

  • 後量子密碼學:抵抗量子計算機攻擊的新算法
  • 同態加密:在加密狀態下直接進行計算
  • 國密算法:中國自主研發的密碼算法體系(SM2, SM3, SM4)

五、總結:現代密碼學核心用法表

需求

推薦技術

關鍵點

密碼存儲、文件校驗

SHA-256(散列函數)

不可逆,固定長度

大量數據加密(文件、傳輸)

AES-CBC(對稱加密)+ Base64

密鑰 16 字節,用 CBC 模式 + PKCS5Padding

密鑰交換、數字簽名

RSA-2048/ECC-256(非對稱加密)

公鑰公開,私鑰保密

避免傳輸亂碼

Base64

不是加密,是編碼

密碼學就像網絡世界的"安全衞士",從簡單的字母替換髮展到今天覆雜的數學算法。它的核心不是 “搞懂複雜算法”,而是 “選對工具”—— 比如加密文件用 AES,存密碼用 SHA-256,傳輸密鑰用 RSA。

記住黃金法則沒有絕對的安全,只有相對的安全。 持續學習、及時更新加密方案才是真正的安全保障。