常见的对称加密和非对称加密算法详解 及详细java代码展示

加密算法是信息安全的核心技术,用于保护数据的机密性、完整性和身份验证。本文将详细介绍对称加密和非对称加密的常见算法,包括原理、特点、应用场景,并提供完整的 Java 代码示例(基于 javax.crypto 标准库)。

一、对称加密算法详解

对称加密使用同一个密钥完成加密和解密,核心是“密钥共享”。适用于大量数据加密(如文件、数据库),但密钥管理是关键挑战。

1. AES(高级加密标准,Advanced Encryption Standard)

AES 是 NIST 于 2001 年选定的对称加密标准,取代了 DES,是目前最安全、应用最广泛的对称加密算法。支持 128/192/256 位密钥,分组长度固定为 128 位(16 字节)。

(1)核心原理

分组模式:AES 是分组密码,需将明文按 128 位分组(不足补填充)。常用模式:

CBC(密码分组链接):需初始化向量(IV),增强安全性(防止相同明文生成相同密文)。GCM(Galois/Counter Mode):提供认证加密(同时保证机密性和完整性),推荐用于高安全场景。

密钥扩展:将原始密钥扩展为轮密钥(Round Key),用于多轮加密(AES-128 需 10 轮,AES-256 需 14 轮)。

(2)Java 代码示例(AES-CBC-PKCS5Padding)

import javax.crypto.Cipher;

import javax.crypto.spec.IvParameterSpec;

import javax.crypto.spec.SecretKeySpec;

import java.nio.charset.StandardCharsets;

import java.security.SecureRandom;

import java.util.Base64;

public class AesExample {

// AES 密钥(16/24/32 字节对应 AES-128/192/256,示例使用 AES-128)

private static final byte[] KEY = "ThisIsASecretKey123".getBytes(StandardCharsets.UTF_8); // 16 字节

private static final String ALGORITHM = "AES/CBC/PKCS5Padding"; // 算法/模式/填充

/**

* AES 加密(CBC 模式)

* @param plaintext 明文

* @return 密文(Base64 编码,包含 IV 和密文)

*/

public static String encrypt(String plaintext) throws Exception {

// 生成随机 IV(CBC 模式必须,长度等于分组长度 16 字节)

SecureRandom random = new SecureRandom();

byte[] ivBytes = new byte[16];

random.nextBytes(ivBytes);

IvParameterSpec iv = new IvParameterSpec(ivBytes);

// 初始化加密器

SecretKeySpec keySpec = new SecretKeySpec(KEY, "AES");

Cipher cipher = Cipher.getInstance(ALGORITHM);

cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);

// 加密并拼接 IV 和密文(IV 需传输给解密方)

byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

byte[] ivAndCiphertext = new byte[ivBytes.length + ciphertext.length];

System.arraycopy(ivBytes, 0, ivAndCiphertext, 0, ivBytes.length);

System.arraycopy(ciphertext, 0, ivAndCiphertext, ivBytes.length, ciphertext.length);

return Base64.getEncoder().encodeToString(ivAndCiphertext);

}

/**

* AES 解密(CBC 模式)

* @param encryptedText 密文(Base64 编码,包含 IV 和密文)

* @return 明文

*/

public static String decrypt(String encryptedText) throws Exception {

// 解析 IV 和密文

byte[] ivAndCiphertext = Base64.getDecoder().decode(encryptedText);

byte[] ivBytes = new byte[16]; // IV 固定 16 字节

System.arraycopy(ivAndCiphertext, 0, ivBytes, 0, ivBytes.length);

IvParameterSpec iv = new IvParameterSpec(ivBytes);

byte[] ciphertext = new byte[ivAndCiphertext.length - ivBytes.length];

System.arraycopy(ivAndCiphertext, ivBytes.length, ciphertext, 0, ciphertext.length);

// 初始化解密器

SecretKeySpec keySpec = new SecretKeySpec(KEY, "AES");

Cipher cipher = Cipher.getInstance(ALGORITHM);

cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);

// 解密

byte[] plaintextBytes = cipher.doFinal(ciphertext);

return new String(plaintextBytes, StandardCharsets.UTF_8);

}

public static void main(String[] args) {

try {

String plaintext = "Hello, AES Encryption!";

String encrypted = encrypt(plaintext);

String decrypted = decrypt(encrypted);

System.out.println("明文: " + plaintext);

System.out.println("密文: " + encrypted);

System.out.println("解密后: " + decrypted);

} catch (Exception e) {

e.printStackTrace();

}

}

}

(3)Java 代码示例(AES-GCM 认证加密)

GCM 模式提供认证加密(同时保证机密性和完整性),推荐用于高安全场景(如 TLS 1.3)。

import javax.crypto.Cipher;

import javax.crypto.spec.GCMParameterSpec;

import javax.crypto.spec.SecretKeySpec;

import java.nio.ByteBuffer;

import java.nio.charset.StandardCharsets;

import java.security.SecureRandom;

import java.util.Base64;

public class AesGcmExample {

private static final byte[] KEY = "ThisIsASecretKey1234".getBytes(StandardCharsets.UTF_8); // 16 字节(AES-128)

private static final int GCM_IV_LENGTH = 12; // GCM 推荐 IV 长度 12 字节

private static final int GCM_TAG_LENGTH = 16; // GCM 标签长度 16 字节

public static String encrypt(String plaintext) throws Exception {

// 生成随机 IV

SecureRandom random = new SecureRandom();

byte[] iv = new byte[GCM_IV_LENGTH];

random.nextBytes(iv);

// 初始化加密器

SecretKeySpec keySpec = new SecretKeySpec(KEY, "AES");

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);

cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec);

// 加密

byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

// 拼接 IV、标签和密文(格式:IV(12) + 标签(16) + 密文)

ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + GCM_TAG_LENGTH + ciphertext.length);

byteBuffer.put(iv);

byteBuffer.put(cipher.getIV()); // 实际 IV 已包含在 byteBuffer 中,此处可优化

byteBuffer.put(ciphertext);

return Base64.getEncoder().encodeToString(byteBuffer.array());

}

public static String decrypt(String encryptedText) throws Exception {

// 解析 IV、标签和密文

byte[] data = Base64.getDecoder().decode(encryptedText);

byte[] iv = new byte[GCM_IV_LENGTH];

System.arraycopy(data, 0, iv, 0, iv.length);

byte[] tag = new byte[GCM_TAG_LENGTH];

System.arraycopy(data, iv.length, tag, 0, tag.length);

byte[] ciphertext = new byte[data.length - iv.length - tag.length];

System.arraycopy(data, iv.length + tag.length, ciphertext, 0, ciphertext.length);

// 初始化解密器

SecretKeySpec keySpec = new SecretKeySpec(KEY, "AES");

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);

cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);

cipher.update(tag); // 设置认证标签

// 解密

byte[] plaintextBytes = cipher.doFinal(ciphertext);

return new String(plaintextBytes, StandardCharsets.UTF_8);

}

public static void main(String[] args) {

try {

String plaintext = "Hello, AES-GCM Encryption!";

String encrypted = encrypt(plaintext);

String decrypted = decrypt(encrypted);

System.out.println("明文: " + plaintext);

System.out.println("密文: " + encrypted);

System.out.println("解密后: " + decrypted);

} catch (Exception e) {

e.printStackTrace();

}

}

}

2. DES(数据加密标准,Data Encryption Standard)

DES 是 1977 年由 IBM 开发的早期对称加密算法,因密钥过短(56 位)已被 AES 取代,仅用于遗留系统。

(1)核心原理

分组长度:64 位(实际有效 56 位,8 位用于校验)。密钥长度:56 位(弱密钥,易被暴力破解)。弱点:易受差分分析和线性分析攻击,目前已被证明不安全。

(2)Java 代码示例(DES-CBC-PKCS5Padding)

import javax.crypto.Cipher;

import javax.crypto.spec.IvParameterSpec;

import javax.crypto.spec.SecretKeySpec;

import java.nio.charset.StandardCharsets;

import java.util.Base64;

public class DesExample {

// DES 密钥(8 字节,56 位有效)

private static final byte[] KEY = "12345678".getBytes(StandardCharsets.UTF_8); // 8 字节

private static final String ALGORITHM = "DES/CBC/PKCS5Padding";

public static String encrypt(String plaintext) throws Exception {

// 生成随机 IV(CBC 模式需要,8 字节)

SecureRandom random = new SecureRandom();

byte[] ivBytes = new byte[8];

random.nextBytes(ivBytes);

IvParameterSpec iv = new IvParameterSpec(ivBytes);

// 初始化加密器

SecretKeySpec keySpec = new SecretKeySpec(KEY, "DES");

Cipher cipher = Cipher.getInstance(ALGORITHM);

cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);

// 加密并拼接 IV 和密文

byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

byte[] ivAndCiphertext = new byte[ivBytes.length + ciphertext.length];

System.arraycopy(ivBytes, 0, ivAndCiphertext, 0, ivBytes.length);

System.arraycopy(ciphertext, 0, ivAndCiphertext, ivBytes.length, ciphertext.length);

return Base64.getEncoder().encodeToString(ivAndCiphertext);

}

public static String decrypt(String encryptedText) throws Exception {

// 解析 IV 和密文

byte[] ivAndCiphertext = Base64.getDecoder().decode(encryptedText);

byte[] ivBytes = new byte[8];

System.arraycopy(ivAndCiphertext, 0, ivBytes, 0, ivBytes.length);

IvParameterSpec iv = new IvParameterSpec(ivBytes);

byte[] ciphertext = new byte[ivAndCiphertext.length - ivBytes.length];

System.arraycopy(ivAndCiphertext, ivBytes.length, ciphertext, 0, ciphertext.length);

// 初始化解密器

SecretKeySpec keySpec = new SecretKeySpec(KEY, "DES");

Cipher cipher = Cipher.getInstance(ALGORITHM);

cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);

// 解密

byte[] plaintextBytes = cipher.doFinal(ciphertext);

return new String(plaintextBytes, StandardCharsets.UTF_8);

}

public static void main(String[] args) {

try {

String plaintext = "Hello, DES Encryption!";

String encrypted = encrypt(plaintext);

String decrypted = decrypt(encrypted);

System.out.println("明文: " + plaintext);

System.out.println("密文: " + encrypted);

System.out.println("解密后: " + decrypted);

} catch (Exception e) {

e.printStackTrace();

}

}

}

3. 3DES(三重数据加密标准,Triple DES)

3DES 是 DES 的改进版,通过三次 DES 加密增强安全性(密钥长度 168 位),但因性能较低,逐渐被 AES 取代。

(1)核心原理

加密流程:密文 = E(K3, D(K2, E(K1, 明文)))(K1、K2、K3 为三个独立密钥)。密钥长度:168 位(3×56 位),但实际有效密钥长度为 112 位(若 K1=K3)。

(2)Java 代码示例(3DES-CBC-PKCS5Padding)

import javax.crypto.Cipher;

import javax.crypto.spec.IvParameterSpec;

import javax.crypto.spec.SecretKeySpec;

import java.nio.charset.StandardCharsets;

import java.util.Base64;

public class TripleDesExample {

// 3DES 密钥(24 字节,168 位)

private static final byte[] KEY = "ThisIsASecretKey123456".getBytes(StandardCharsets.UTF_8); // 24 字节

private static final String ALGORITHM = "DESede/CBC/PKCS5Padding"; // DESede 是 3DES 的别名

public static String encrypt(String plaintext) throws Exception {

// 生成随机 IV(8 字节)

SecureRandom random = new SecureRandom();

byte[] ivBytes = new byte[8];

random.nextBytes(ivBytes);

IvParameterSpec iv = new IvParameterSpec(ivBytes);

// 初始化加密器

SecretKeySpec keySpec = new SecretKeySpec(KEY, "DESede");

Cipher cipher = Cipher.getInstance(ALGORITHM);

cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);

// 加密并拼接 IV 和密文

byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

byte[] ivAndCiphertext = new byte[ivBytes.length + ciphertext.length];

System.arraycopy(ivBytes, 0, ivAndCiphertext, 0, ivBytes.length);

System.arraycopy(ciphertext, 0, ivAndCiphertext, ivBytes.length, ciphertext.length);

return Base64.getEncoder().encodeToString(ivAndCiphertext);

}

public static String decrypt(String encryptedText) throws Exception {

// 解析 IV 和密文

byte[] ivAndCiphertext = Base64.getDecoder().decode(encryptedText);

byte[] ivBytes = new byte[8];

System.arraycopy(ivAndCiphertext, 0, ivBytes, 0, ivBytes.length);

IvParameterSpec iv = new IvParameterSpec(ivBytes);

byte[] ciphertext = new byte[ivAndCiphertext.length - ivBytes.length];

System.arraycopy(ivAndCiphertext, ivBytes.length, ciphertext, 0, ciphertext.length);

// 初始化解密器

SecretKeySpec keySpec = new SecretKeySpec(KEY, "DESede");

Cipher cipher = Cipher.getInstance(ALGORITHM);

cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);

// 解密

byte[] plaintextBytes = cipher.doFinal(ciphertext);

return new String(plaintextBytes, StandardCharsets.UTF_8);

}

public static void main(String[] args) {

try {

String plaintext = "Hello, 3DES Encryption!";

String encrypted = encrypt(plaintext);

String decrypted = decrypt(encrypted);

System.out.println("明文: " + plaintext);

System.out.println("密文: " + encrypted);

System.out.println("解密后: " + decrypted);

} catch (Exception e) {

e.printStackTrace();

}

}

}

二、非对称加密算法详解

非对称加密使用公钥加密、私钥解密(或私钥签名、公钥验证),密钥对(公钥+私钥)通过数学难题生成,公钥可公开,私钥需严格保密。

1. RSA(Rivest-Shamir-Adleman)

RSA 是最经典的非对称加密算法,基于大整数分解的困难性(分解两个大素数的乘积极难)。

(1)核心原理

密钥生成:

选择两个大素数 (p) 和 (q),计算 (N = p \times q)。计算欧拉函数 (\phi(N) = (p-1)(q-1))。选择公钥指数 (e)(与 (\phi(N)) 互质,通常取 65537)。计算私钥指数 (d)(满足 (e \times d \equiv 1 \mod \phi(N)))。公钥为 ((N, e)),私钥为 ((N, d))。

加密:(C = M^e \mod N)((M) 为明文,(C) 为密文)。解密:(M = C^d \mod N)。

(2)Java 代码示例(RSA 加密/解密)

import javax.crypto.BadPaddingException;

import javax.crypto.Cipher;

import javax.crypto.IllegalBlockSizeException;

import java.security.*;

import java.security.spec.PKCS8EncodedKeySpec;

import java.security.spec.X509EncodedKeySpec;

import java.util.Base64;

public class RsaExample {

// RSA 密钥长度(推荐 2048 位以上)

private static final int KEY_LENGTH = 2048;

/**

* 生成 RSA 密钥对

*/

public static KeyPair generateKeyPair() throws Exception {

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");

keyPairGenerator.initialize(KEY_LENGTH);

return keyPairGenerator.generateKeyPair();

}

/**

* RSA 公钥加密

*/

public static String encrypt(String plaintext, PublicKey publicKey) throws Exception {

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

cipher.init(Cipher.ENCRYPT_MODE, publicKey);

byte[] ciphertext = cipher.doFinal(plaintext.getBytes());

return Base64.getEncoder().encodeToString(ciphertext);

}

/**

* RSA 私钥解密

*/

public static String decrypt(String encryptedText, PrivateKey privateKey) throws Exception {

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

cipher.init(Cipher.DECRYPT_MODE, privateKey);

byte[] ciphertext = Base64.getDecoder().decode(encryptedText);

byte[] plaintextBytes = cipher.doFinal(ciphertext);

return new String(plaintextBytes);

}

/**

* 从 Base64 字符串加载公钥

*/

public static PublicKey loadPublicKey(String publicKeyBase64) throws Exception {

byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyBase64);

X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);

KeyFactory keyFactory = KeyFactory.getInstance("RSA");

return keyFactory.generatePublic(keySpec);

}

/**

* 从 Base64 字符串加载私钥

*/

public static PrivateKey loadPrivateKey(String privateKeyBase64) throws Exception {

byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyBase64);

PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);

KeyFactory keyFactory = KeyFactory.getInstance("RSA");

return keyFactory.generatePrivate(keySpec);

}

public static void main(String[] args) {

try {

// 生成密钥对

KeyPair keyPair = generateKeyPair();

PublicKey publicKey = keyPair.getPublic();

PrivateKey privateKey = keyPair.getPrivate();

// 打印公钥和私钥(Base64 编码)

String publicKeyBase64 = Base64.getEncoder().encodeToString(publicKey.getEncoded());

String privateKeyBase64 = Base64.getEncoder().encodeToString(privateKey.getEncoded());

System.out.println("公钥 (Base64): " + publicKeyBase64);

System.out.println("私钥 (Base64): " + privateKeyBase64);

// 加密和解密

String plaintext = "Hello, RSA Encryption!";

String encrypted = encrypt(plaintext, publicKey);

String decrypted = decrypt(encrypted, privateKey);

System.out.println("明文: " + plaintext);

System.out.println("密文: " + encrypted);

System.out.println("解密后: " + decrypted);

} catch (Exception e) {

e.printStackTrace();

}

}

}

2. ECC(椭圆曲线密码学,Elliptic Curve Cryptography)

ECC 基于椭圆曲线离散对数问题的困难性,密钥更短(256 位 ECC 密钥安全性等价于 3072 位 RSA 密钥),性能更优,适合移动设备和物联网。

(1)核心原理

数学基础:在有限域上的椭圆曲线 (y^2 = x^3 + ax + b) 中,求解离散对数 (k)(已知 (Q = k \times P),求 (k))极难。密钥生成:

选择椭圆曲线参数(如 secp256r1)。选择私钥 (k)(随机数,256 位)。计算公钥 (Q = k \times G)((G) 为曲线生成元)。

(2)Java 代码示例(ECC 密钥对生成与签名)

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.*;

import java.security.spec.ECGenParameterSpec;

import java.util.Base64;

public class EccExample {

static {

// 添加 Bouncy Castle 提供者(Java 标准库不直接支持 ECC 签名)

Security.addProvider(new BouncyCastleProvider());

}

/**

* 生成 ECC 密钥对(secp256r1 曲线)

*/

public static KeyPair generateEccKeyPair() throws Exception {

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");

ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("secp256r1");

keyPairGenerator.initialize(ecGenParameterSpec, new SecureRandom());

return keyPairGenerator.generateKeyPair();

}

/**

* ECC 私钥签名

*/

public static String sign(String plaintext, PrivateKey privateKey) throws Exception {

Signature signature = Signature.getInstance("SHA256withECDSA", "BC");

signature.initSign(privateKey);

signature.update(plaintext.getBytes());

byte[] signBytes = signature.sign();

return Base64.getEncoder().encodeToString(signBytes);

}

/**

* ECC 公钥验证签名

*/

public static boolean verify(String plaintext, String signBase64, PublicKey publicKey) throws Exception {

Signature signature = Signature.getInstance("SHA256withECDSA", "BC");

signature.initVerify(publicKey);

signature.update(plaintext.getBytes());

byte[] signBytes = Base64.getDecoder().decode(signBase64);

return signature.verify(signBytes);

}

public static void main(String[] args) {

try {

// 生成 ECC 密钥对

KeyPair keyPair = generateEccKeyPair();

PublicKey publicKey = keyPair.getPublic();

PrivateKey privateKey = keyPair.getPrivate();

// 打印公钥和私钥(Base64 编码)

String publicKeyBase64 = Base64.getEncoder().encodeToString(publicKey.getEncoded());

String privateKeyBase64 = Base64.getEncoder().encodeToString(privateKey.getEncoded());

System.out.println("ECC 公钥 (Base64): " + publicKeyBase64);

System.out.println("ECC 私钥 (Base64): " + privateKeyBase64);

// 签名和验证

String plaintext = "Hello, ECC Signature!";

String sign = sign(plaintext, privateKey);

boolean isValid = verify(plaintext, sign, publicKey);

System.out.println("明文: " + plaintext);

System.out.println("签名: " + sign);

System.out.println("签名验证结果: " + (isValid ? "有效" : "无效"));

} catch (Exception e) {

e.printStackTrace();

}

}

}

三、对称与非对称加密对比与应用

1. 核心差异

维度对称加密非对称加密密钥数量1 个(共享)2 个(公钥+私钥)加密速度快(硬件加速友好)慢(大数运算)密钥管理困难(需安全传输)简单(公钥可公开)安全强度依赖密钥长度(如 AES-256)依赖数学难题(如 RSA-2048)典型用途大量数据加密(如文件、数据库)密钥交换、数字签名(如 HTTPS)2. 实际应用中的结合使用

实际系统中,对称与非对称加密通常协同工作,以兼顾效率与安全:

(1)HTTPS 协议(TLS 握手)

步骤 1:密钥交换:客户端与服务器通过非对称加密(如 RSA 或 ECDHE)协商生成临时对称密钥(会话密钥)。步骤 2:数据传输:使用会话密钥(对称加密)加密后续通信数据(如 AES-GCM)。

(2)数字签名与加密结合

签名:用私钥对数据哈希值签名(非对称加密),公钥验证签名真实性。加密:用公钥加密数据(非对称加密),私钥解密(仅适用于小数据)。

四、总结与最佳实践

1. 对称加密选择建议

优先 AES(AES-256-GCM 最佳),避免使用 DES/3DES。密钥管理:通过非对称加密(如 RSA)安全传输 AES 密钥。

2. 非对称加密选择建议

RSA:经典选择,适合密钥交换和签名(密钥长度 ≥2048 位)。ECC:更高效,适合移动设备、物联网(256 位密钥安全性等价于 RSA-3072 位)。

3. 注意事项

密钥安全:私钥需严格保密(存储在安全模块 HSM 中),公钥可公开。填充模式:避免使用不安全的填充(如 DES 的 ECB 模式),推荐 AES-GCM、RSA-PKCS1Padding。性能优化:对称加密用于大量数据,非对称加密仅用于密钥交换和签名。

纯学习 多mark 多交流

友情链接:
Copyright © 2022 86年世界杯_世界杯预选赛阿根廷 - fjyfzz.com All Rights Reserved.