文章目录
-
- 1. 加密基础知识
-
- 1.1 什么是加密?
- 1.2 加密的历史简介
-
- 1.2.1 古典加密
- 1.2.2 现代加密的起源
- 1.3 加密的基本概念
-
- 1.3.1 密码学中的关键术语
- 1.3.2 加密的基本原则
- 1.4 加密的分类
-
- 1.4.1 对称加密(Symmetric Encryption)
- 1.4.2 非对称加密(Asymmetric Encryption)
- 1.4.3 哈希函数(Hash Functions)
- 1.5 加密的核心特性
- 2. 对称加密详解
-
- 2.1 对称加密的工作原理
- 2.2 对称加密的分类
-
- 2.2.1 块加密(Block Ciphers)
- 2.2.2 流加密(Stream Ciphers)
- 2.3 常用对称加密算法详解
-
- 2.3.1 DES(Data Encryption Standard)
- 2.3.2 3DES(Triple DES)
- 2.3.3 AES(Advanced Encryption Standard)
- 2.3.4 Blowfish
- 2.4 对称加密的优缺点
-
- 2.4.1 优点
- 2.4.2 缺点
- 2.5 对称加密的实际应用场景
- 2.6 对称加密中的填充
- 2.7 对称加密密钥生成
- 3. 非对称加密详解
-
- 3.1 非对称加密的工作原理
- 3.2 常用非对称加密算法
-
- 3.2.1 RSA(Rivest-Shamir-Adleman)
- 3.2.2 ECC(Elliptic Curve Cryptography)
- 3.2.3 DSA(Digital Signature Algorithm)
- 3.2.4 DH(Diffie-Hellman)
- 3.3 非对称加密的优缺点
-
- 3.3.1 优点
- 3.3.2 缺点
- 3.4 非对称加密的实际应用场景
- 3.5 混合加密系统
- 4. 散列算法详解
-
- 4.1 散列算法的特性
- 4.2 常用散列算法
-
- 4.2.1 MD5(Message Digest Algorithm 5)
- 4.2.2 SHA(Secure Hash Algorithm)系列
- 4.2.3 HMAC(Hash-based Message Authentication Code)
- 4.3 散列算法的实际应用
- 4.4 安全的密码散列
-
- 4.4.1 盐(Salt)
- 4.4.2 常用的密码散列算法
- 5. 数字签名详解
-
- 5.1 数字签名的工作原理
- 5.2 数字签名的特性
- 5.3 常用数字签名算法
-
- 5.3.1 RSA签名
- 5.3.2 DSA签名
- 5.3.3 ECDSA(Elliptic Curve Digital Signature Algorithm)
- 5.4 数字签名的应用场景
- 5.5 JAR文件签名示例
- 6. 常见加密标准和协议
-
- 6.1 SSL/TLS协议
-
- 6.1.1 工作原理
- 6.1.2 Java中的SSL/TLS示例
- 6.2 OpenPGP
- 6.3 X.509证书
- 6.4 PKCS(公钥加密标准)
- 7. Java加解密应用与实践
-
- 7.1 Java加密架构(JCA)概述
- 7.2 文件加密解密实用例子
- 7.3 安全密码存储
- 7.4 数据签名与验证
- 7.5 安全的客户端-服务器通信
- 7.6 加密配置信息
- 8. 加密在实际场景中的应用
-
- 8.1 网络安全应用
-
- 8.1.1 HTTPS/TLS
- 8.1.2 VPN (虚拟专用网络)
- 8.1.3 SSH (安全Shell)
- 8.2 数据存储安全
-
- 8.2.1 全盘加密
- 8.2.2 数据库加密
- 8.2.3 云存储加密
- 8.3 身份验证和访问控制
-
- 8.3.1 密码存储
- 8.3.2 多因素认证
- 8.3.3 OAuth和JWT
- 8.4 移动和物联网安全
-
- 8.4.1 移动应用数据加密
- 8.4.2 物联网设备安全
- 8.5 区块链和加密货币
- 9. 加密实践的常见问题与解决方案
-
- 9.1 密钥管理挑战
- 9.2 加密算法选择错误
- 9.3 实施缺陷和漏洞
- 9.4 加密过度使用导致性能问题
- 9.5 合规性和法律考虑
1. 加密基础知识
1.1 什么是加密?
加密是将明文信息转换为难以理解的密文的过程,目的是保护信息的机密性。只有拥有正确密钥的人才能将密文转换回明文,这个过程称为解密。
明文 + 加密算法 + 密钥 = 密文
密文 + 解密算法 + 密钥 = 明文
1.2 加密的历史简介
1.2.1 古典加密
最早的加密可以追溯到古埃及时期,大约公元前1900年。随着时间的推移,出现了各种加密方法:
-
凯撒密码:古罗马时期的简单替换密码,由朱利叶斯·凯撒使用。它通过将字母表中的每个字母移动固定位置来加密信息。
例如,位移量为3的凯撒密码:
明文:HELLO 密文:KHOOR (每个字母在字母表中向后移动3位)
-
维吉尼亚密码:16世纪出现的多表替换密码,使用一系列不同的凯撒密码来加密消息的不同部分。
1.2.2 现代加密的起源
二战期间,加密技术得到了极大发展,特别是德国的恩尼格玛机(Enigma machine)和英国破解恩尼格玛密码的努力。计算机时代的到来彻底改变了加密领域,1970年代出现了现代加密的两个重要里程碑:
- DES(数据加密标准):1977年由美国国家标准与技术研究院(NIST)发布
- RSA算法:1977年由Rivest、Shamir和Adleman三位密码学家发明的第一个实用的公钥加密系统
1.3 加密的基本概念
1.3.1 密码学中的关键术语
- 明文(Plaintext):原始、可读的信息
- 密文(Ciphertext):经过加密后的、不可读的信息
- 加密(Encryption):将明文转换为密文的过程
- 解密(Decryption):将密文转换回明文的过程
- 密钥(Key):控制加密和解密操作的参数
- 密码算法(Cipher):执行加密和解密的数学函数或算法
1.3.2 加密的基本原则
- 克克霍夫原则:即使加密系统的所有细节(除了密钥)都是公开的,系统也应该是安全的
- 香农理论:完美的加密系统需要密钥长度至少与明文一样长
- 计算安全性:实际的加密系统依赖于计算难题,使得在合理的时间内无法破解
1.4 加密的分类
加密主要分为三大类:
1.4.1 对称加密(Symmetric Encryption)
使用同一个密钥进行加密和解密。
特点:
- 速度快,适合大量数据加密
- 需要安全地共享密钥
- 代表算法:AES, DES, 3DES, Blowfish
1.4.2 非对称加密(Asymmetric Encryption)
使用一对密钥:公钥和私钥。公钥用于加密,私钥用于解密。
特点:
- 解决了密钥分发问题
- 计算密集型,速度较慢
- 代表算法:RSA, DSA, ECC, ElGamal
1.4.3 哈希函数(Hash Functions)
将任意长度的输入转换为固定长度的输出,且不可逆。
特点:
- 不使用密钥
- 无法从哈希值恢复原始数据
- 用于验证数据完整性
- 代表算法:MD5, SHA-1, SHA-256, SHA-3
1.5 加密的核心特性
现代加密系统通常提供以下四种核心安全服务:
- 机密性(Confidentiality):确保只有授权方可以读取信息
- 完整性(Integrity):确保信息在传输过程中未被修改
- 认证(Authentication):确认信息来源的真实性
- 不可否认性(Non-repudiation):防止发送方否认曾发送过信息
2. 对称加密详解
对称加密是最古老、最直观的加密形式,也称为"共享密钥加密"或"秘密密钥加密"。
2.1 对称加密的工作原理
在对称加密中,加密和解密使用同一个密钥:
- 发送方使用密钥和加密算法将明文转换为密文
- 接收方使用同一个密钥和解密算法将密文转换回明文
加密:明文 + 密钥 + 算法 = 密文
解密:密文 + 密钥 + 算法 = 明文
2.2 对称加密的分类
对称加密算法主要分为两类:
2.2.1 块加密(Block Ciphers)
将明文分成固定大小的块,然后对每个块进行加密。最常见的块大小是64位和128位。
主要算法:
- DES(Data Encryption Standard)
- 3DES(Triple DES)
- AES(Advanced Encryption Standard)
- Blowfish
- Twofish
工作模式:
块加密有多种工作模式,每种模式有不同的安全属性:
- ECB(Electronic Codebook):最简单的模式,直接对每个块加密,但安全性较低
- CBC(Cipher Block Chaining):每个块与前一个密文块异或后再加密
- CFB(Cipher Feedback):将密码算法转换为流密码
- OFB(Output Feedback):类似CFB,但使用加密输出而非密文进行反馈
- CTR(Counter):将块密码转换为流密码,使用计数器确保每个块使用不同的输入
2.2.2 流加密(Stream Ciphers)
一次加密一位或一字节数据,通常使用伪随机密钥流(keystream)与明文进行异或操作。
主要算法:
- RC4(Rivest Cipher 4)
- ChaCha20
- A5/1, A5/2(用于GSM通信)
- SNOW 3G(用于3G网络)
2.3 常用对称加密算法详解
2.3.1 DES(Data Encryption Standard)
简介:1977年成为美国联邦标准的第一个公开加密算法。
特点:
- 块大小:64位
- 密钥长度:56位(实际为64位,但8位用于奇偶校验)
- 轮数:16轮
- 目前被认为不安全,因为56位密钥可以通过暴力破解
Java示例:
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class DESExample {
public static void main(String[] args) throws Exception {
// 生成DES密钥
KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
SecretKey secretKey = keyGenerator.generateKey();
// 获取密钥的字节表示
byte[] keyBytes = secretKey.getEncoded();
// 创建DES密钥规范
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "DES");
// 创建加密器
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
// 加密
String plainText = "Hello, DES!";
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
System.out.println("加密后: " + encryptedText);
// 解密
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
String decryptedText = new String(decryptedBytes);
System.out.println("解密后: " + decryptedText);
}
}
2.3.2 3DES(Triple DES)
简介:为增强DES安全性而开发,使用三重DES加密。
特点:
- 块大小:64位
- 密钥长度:112位或168位(取决于是使用两个还是三个不同密钥)
- 操作:对每个数据块应用三次DES(加密-解密-加密或加密-加密-加密)
- 比DES安全,但比AES慢
Java示例:
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class TripleDESExample {
public static void main(String[] args) throws Exception {
// 生成3DES密钥
KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede"); // DESede = Triple DES
SecretKey secretKey = keyGenerator.generateKey();
// 获取密钥的字节表示
byte[] keyBytes = secretKey.getEncoded();
// 创建3DES密钥规范
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "DESede");
// 创建加密器
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
// 加密
String plainText = "Hello, Triple DES!";
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
System.out.println("加密后: " + encryptedText);
// 解密
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
String decryptedText = new String(decryptedBytes);
System.out.println("解密后: " + decryptedText);
}
}
2.3.3 AES(Advanced Encryption Standard)
简介:2001年成为新的加密标准,取代了DES。由Rijndael算法改编而来。
特点:
- 块大小:128位
- 密钥长度:128位、192位或256位
- 轮数:取决于密钥长度(128位密钥为10轮,192位为12轮,256位为14轮)
- 高效、安全,目前是最广泛使用的对称加密算法
Java示例:
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Base64;
public class AESExample {
public static void main(String[] args) throws Exception {
// 生成AES密钥
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256); // 使用256位密钥
SecretKey secretKey = keyGenerator.generateKey();
// 获取密钥的字节表示
byte[] keyBytes = secretKey.getEncoded();
// 创建AES密钥规范
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
// 创建初始化向量IV(使用CBC模式时需要)
byte[] ivBytes = new byte[16];
new SecureRandom().nextBytes(ivBytes);
IvParameterSpec iv = new IvParameterSpec(ivBytes);
// 创建加密器,使用CBC模式和PKCS5填充
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 加密
String plainText = "Hello, AES!";
cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
// 将加密结果和IV一起编码
String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
String ivText = Base64.getEncoder().encodeToString(ivBytes);
System.out.println("加密后: " + encryptedText);
System.out.println("初始化向量: " + ivText);
// 解密
cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
String decryptedText = new String(decryptedBytes);
System.out.println("解密后: " + decryptedText);
}
}
2.3.4 Blowfish
简介:1993年由Bruce Schneier设计的快速块加密算法。
特点:
- 块大小:64位
- 可变密钥长度:32位到448位
- 轮数:16轮
- 设计简单,实现高效
Java示例:
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class BlowfishExample {
public static void main(String[] args) throws Exception {
// 生成Blowfish密钥
KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
keyGenerator.init(128); // 使用128位密钥
SecretKey secretKey = keyGenerator.generateKey();
// 获取密钥的字节表示
byte[] keyBytes = secretKey.getEncoded();
// 创建Blowfish密钥规范
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "Blowfish");
// 创建加密器
Cipher cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
// 加密
String plainText = "Hello, Blowfish!";
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
System.out.println("加密后: " + encryptedText);
// 解密
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
String decryptedText = new String(decryptedBytes);
System.out.println("解密后: " + decryptedText);
}
}
2.4 对称加密的优缺点
2.4.1 优点
- 速度快:对称加密算法通常非常高效,特别适合加密大量数据
- 实现简单:算法相对简单,易于实现
- 安全性高:当使用足够长的密钥时,提供很高的安全性
2.4.2 缺点
- 密钥分发问题:安全地共享密钥是一个主要挑战
- 密钥管理复杂:随着通信方数量增加,需要管理的密钥数量呈指数增长
- 不提供真正的认证:不能确认信息的来源
2.5 对称加密的实际应用场景
- 文件加密:保护存储在硬盘或云存储中的敏感文件
- 数据库加密:加密存储在数据库中的敏感数据
- 通信加密:TLS/SSL协议中的会话加密
- 硬盘加密:BitLocker、FileVault等全盘加密解决方案
- VPN通信:虚拟专用网络中的数据加密
2.6 对称加密中的填充
当明文长度不是块大小的整数倍时,需要使用填充(Padding)来补齐最后一个块。常见的填充方案包括:
- PKCS#7/PKCS#5 Padding:添加n个值为n的字节(n是需要填充的字节数)
- ISO/IEC 7816-4 Padding:添加一个值为0x80的字节,其余填充0x00
- ANSI X.923 Padding:最后一个字节表示填充的字节数,其余填充0x00
- Zero Padding:简单地用0填充
Java中的填充示例:
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class PaddingExample {
public static void main(String[] args) throws Exception {
// 创建一个简单的AES密钥
byte[] keyBytes = "0123456789abcdef".getBytes();
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
// 测试不同的填充方式
String plainText = "测试填充";
String[] paddings = {
"AES/ECB/PKCS5Padding", "AES/ECB/NoPadding"};
for (String padding : paddings) {
try {
Cipher cipher = Cipher.getInstance(padding);
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
// 加密
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
System.out.println(padding + " 加密结果: " + encryptedText);
System.out.println(padding + " 加密结果长度: " + encryptedBytes.length + " 字节");
// 解密
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
String decryptedText = new String(decryptedBytes);
System.out.println(padding + " 解密结果: " + decryptedText);
System.out.println();
} catch (Exception e) {
System.out.println(padding + " 错误: " + e.getMessage());
System.out.println();
}
}
}
}
2.7 对称加密密钥生成
在实际应用中,密钥应该是真正随机的。Java提供了几种方法来生成安全的随机密钥:
使用KeyGenerator生成密钥:
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
public class KeyGenerationExample {
public static void main(String[] args) throws NoSuchAlgorithmException {
// 为AES生成128位密钥
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128, SecureRandom.getInstanceStrong());
SecretKey secretKey = keyGen.generateKey();
// 输出密钥的Base64编码表示
String encodedKey = Base64.getEncoder().encodeToString(secretKey.getEncoded());
System.out.println("生成的AES密钥: " + encodedKey);
// 为Blowfish生成256位密钥
keyGen = KeyGenerator.getInstance("Blowfish");
keyGen.init(256, SecureRandom.getInstanceStrong());
secretKey = keyGen.generateKey();
// 输出密钥的Base64编码表示
encodedKey = Base64.getEncoder().encodeToString(secretKey.getEncoded());
System.out.println("生成的Blowfish密钥: " + encodedKey);
}
}
使用密码生成密钥:
在实际应用中,有时需要从用户密码生成密钥,这通常通过密钥派生函数(KDF)如PBKDF2实现:
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Base64;
public class PasswordBasedKeyExample {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {
// 用户密码和盐值
String password = "user_password";
byte[] salt = "random_salt".getBytes();
// 使用PBKDF2生成密钥
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");
// 输出密钥的Base64编码表示
String encodedKey = Base64.getEncoder().encodeToString(secretKey.getEncoded());
System.out.println("从密码生成的AES密钥: " + encodedKey);
}
}
3. 非对称加密详解
与对称加密不同,非对称加密(也称为公钥加密)使用一对密钥:公钥和私钥。公钥可以自由分发,而私钥必须保密。
3.1 非对称加密的工作原理
非对称加密基于数学问题,如大整数分解和离散对数:
- 加密:使用接收方的公钥加密消息,只有拥有对应私钥的接收方才能解密
- 数字签名:使用发送方的私钥对消息进行签名,任何人都可以使用发送方的公钥验证签名的真实性
加密:明文 + 接收方公钥 = 密文
解密:密文 + 接收方私钥 = 明文
签名:消息 + 发送方私钥 = 数字签名
验证:消息 + 数字签名 + 发送方公钥 = 真/假
3.2 常用非对称加密算法
3.2.1 RSA(Rivest-Shamir-Adleman)
简介:1977年发明,是第一个既可用于加密又可用于数字签名的算法。
工作原理:
- 基于大整数分解的难题
- 密钥生成涉及选择两个大素数并计算它们的乘积
- 安全性取决于大整数分解的计算困难性
特点:
- 密钥长度:通常为1024、2048或4096位
- 加密消息的大小有限制
- 比对称加密慢100-1000倍
- 广泛用于安全通信和数字签名
Java示例(密钥生成、加密和解密):
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
import javax.crypto.Cipher;
public class RSAExample {
public static void main(String[] args) throws Exception {
// 生成RSA密钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048); // 使用2048位密钥
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
// 打印密钥
System.out.println("公钥: " + Base64.getEncoder().encodeToString(publicKey.getEncoded()));
System.out.println("私钥: " + Base64.getEncoder().encodeToString(privateKey.getEncoded()));
// 加密
String plainText = "Hello, RSA!";
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = encryptCipher.doFinal(plainText.getBytes());
String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
System.out.println("加密后: " + encryptedText);
// 解密
Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedBytes = decryptCipher.doFinal(Base64.getDecoder().decode(encryptedText));
String decryptedText = new String(decryptedBytes);
System.out.println("解密后: " + decryptedText);
}
}
RSA数字签名示例:
import java.security.*;
import java.util.Base64;
public class RSASignatureExample {
public static void main(String[] args) throws Exception {
// 生成RSA密钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
// 要签名的数据
String data = "这是需要签名的重要文档";
// 签名
byte[] signature = sign(data.getBytes(), privateKey);
System.out.println("签名: " + Base64.getEncoder().encodeToString(signature));
// 验证签名
boolean isValid = verify(data.getBytes(), signature, publicKey);
System.out.println("签名验证: " + (isValid ? "有效" : "无效"));
// 验证被篡改的数据
String tamperedData = "这是被篡改的重要文档";
boolean isTamperedValid = verify(tamperedData.getBytes(), signature, publicKey);
System.out.println("篡改数据签名验证: " + (isTamperedValid ? "有效" : "无效"));
}
// 使用私钥签名数据
public static byte[] sign(byte[] data, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
}
// 使用公钥验证签名
public static boolean verify(byte[] data, byte[] signatureBytes, PublicKey publicKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(publicKey);
signature.update(data);
return signature.verify(signatureBytes);
}
}
3.2.2 ECC(Elliptic Curve Cryptography)
简介:基于椭圆曲线数学的加密算法,与RSA相比,提供相同安全性但使用更短的密钥。
工作原理:
- 基于椭圆曲线上的离散对数问题
- 使用点乘法进行加密操作
特点:
- 密钥长度短:224-521位的ECC密钥提供与2048-15360位RSA密钥相当的安全性
- 计算效率高
- 特别适合资源受限的设备,如智能卡和移动设备
Java示例(ECDSA数字签名):
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.util.Base64;
public class ECDSASignatureExample {
public static void main(String[] args) throws Exception {
// 生成EC密钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
keyPairGenerator.initialize(ecSpec);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
// 要签名的数据
String data = "使用ECDSA算法签名的数据";
// 签名
byte[] signature = sign(data.getBytes(), privateKey);
System.out.println("ECDSA签名: " + Base64.getEncoder().encodeToString(signature));
// 验证签名
boolean isValid = verify(data.getBytes(), signature, publicKey);
System.out.println("ECDSA签名验证: " + (isValid ? "有效" : "无效"));
}
// 使用私钥签名数据
public static byte[] sign(byte[] data, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withECDSA");
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
}
// 使用公钥验证签名
public static boolean verify(byte[] data, byte[] signatureBytes, PublicKey publicKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withECDSA");
signature.initVerify(publicKey);
signature.update(data);
return signature.verify(signatureBytes);
}
}
3.2.3 DSA(Digital Signature Algorithm)
简介:专门为数字签名设计的算法。
特点:
- 只用于数字签名,不能用于加密
- 签名生成比RSA快
- 签名验证比RSA慢
- 密钥长度通常为1024-3072位
Java示例:
import java.security.*;
import java.util.Base64;
public class DSASignatureExample {
public static void main(String[] args) throws Exception {
// 生成DSA密钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
// 要签名的数据
String data = "使用DSA算法签名的数据";
// 签名
byte[] signature = sign(data.getBytes(), privateKey);
System.out.println("DSA签名: " + Base64.getEncoder().encodeToString(signature));
// 验证签名
boolean isValid = verify(data.getBytes(), signature, publicKey);
System.out.println("DSA签名验证: " + (isValid ? "有效" : "无效"));
}
// 使用私钥签名数据
public static byte[] sign(byte[] data, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withDSA");
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
}
// 使用公钥验证签名
public static boolean verify(byte[] data, byte[] signatureBytes, PublicKey publicKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withDSA");
signature.initVerify(publicKey);
signature.update(data);
return signature.verify(signatureBytes);
}
}
3.2.4 DH(Diffie-Hellman)
简介:第一个发布的密钥交换协议,允许两方在不安全的通道上安全地建立共享密钥。
工作原理:
- 基于离散对数问题
- 双方交换公开值,各自计算相同的共享密钥,而不直接传输密钥
特点:
- 不用于加密或签名,只用于密钥交换
- 常用于建立对称加密的会话密钥
- 易受中间人攻击,除非使用身份验证
Java示例(密钥交换):
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.util.Base64;
public class DHKeyExchangeExample {
public static void main(String[] args) throws Exception {
// 初始化参数
KeyPairGenerator aliceKpg = KeyPairGenerator.getInstance("DH");
aliceKpg.initialize(2048);
KeyPair aliceKp = aliceKpg.generateKeyPair();
// 获取Alice的公钥和私钥
PublicKey alicePubKey = aliceKp.getPublic();
PrivateKey alicePrivKey = aliceKp.getPrivate();
// Bob接收Alice的公钥并生成自己的密钥对
KeyPairGenerator bobKpg = KeyPairGenerator.getInstance("DH");
bobKpg.initialize(((DHPublicKey)alicePubKey).getParams());
KeyPair bobKp = bobKpg.generateKeyPair();
// 获取Bob的公钥和私钥
PublicKey bobPubKey = bobKp.getPublic();
PrivateKey bobPrivKey = bobKp.getPrivate();
// Alice使用Bob的公钥和自己的私钥生成共享密钥
KeyAgreement aliceKa = KeyAgreement.getInstance("DH");
aliceKa.init(alicePrivKey);
aliceKa.doPhase(bobPubKey, true);
byte[] aliceSharedSecret = aliceKa.generateSecret();
// Bob使用Alice的公钥和自己的私钥生成共享密钥
KeyAgreement bobKa = KeyAgreement.getInstance("DH");
bobKa.init(bobPrivKey);
bobKa.doPhase(alicePubKey, true);
byte[] bobSharedSecret = bobKa.generateSecret();
// 打印共享密钥
System.out.println("Alice的共享密钥: " + Base64.getEncoder().encodeToString(aliceSharedSecret));
System.out.println("Bob的共享密钥: " + Base64.getEncoder().encodeToString(bobSharedSecret));
// 从共享密钥派生AES密钥
SecretKey aliceAesKey