加解密
加密算法
加密算法概览
加密算法一般分为不可逆加密算法、可逆加密算法。
不可逆加密算法有:
- MD5
- HMAC
- SHA1
- SHA-224
- SHA-256
- HMACSHA256
- bcrypt
- PBKDF2
可逆加密算法分为对称加密算法、非堆成加密算法。
对称加密算法有:
- DES
- AES
- 3DES
非对称加密:
- RSA
- DSA
- ECC
加密算法详解
MD5
MD5,全称为“Message-Digest Algorithm 5”,翻译过来叫“信息摘要算法”。它可以将任意长度的数据通过散列算法,生成一个固定长度的散列值。MD5 算法的输出长度为 128 位,通常用 32 个 16 进制数(一个 16 进制数占 4 位)表示。
以下为 MD5 算法的 java 用法:
public class MD5Study {
public static String encrypt(String data) throws Exception {
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
byte[] digest = md5Digest.digest(data.getBytes());
Formatter formatter = new Formatter();
for (byte b : digest
) {
formatter.format("%02x", b);
}
return formatter.toString();
}
public static void main(String[] args) throws Exception {
String data = "hello world";
String md5Result = MD5Study.encrypt(data);
System.out.println(md5Result);
}
}MD5 算法有一些优点,比如计算速度快、输出长度固定、应用广泛等。但作为加密算法,它有一个最大的缺点,就是不安全。MD5 算法已经被攻破,可以使用暴力破解或彩虹表获得原始数据。
加盐,是指在原文里再加上一些不固定的字符串。加盐可以缓解散列算法被暴力破解的可能。
SHA-256
SHA(Secure Hash Algorithm)系列算法是一组密码散列函数,用于将任意长度的数据映射为固定长度的散列值。SHA 系列算法由美国国家安全局(NSA)于 1993 年设计,目前共有 SHA-1、SHA-2、SHA-3 三种版本。
SHA-1 系统算法存在缺陷,已不推荐使用。
SHA-2 算法包括 SHA-224、SHA-256、SHA-384、SHA-512 四种散列函数,分别将任意长度的数据映射为 224 位、256 位、384 位、512 位。
以下为 SHA-256 算法的 java 用法:
public class SHA256Study {
public static String encrypt(String data) throws Exception {
MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256");
byte[] digest = sha256Digest.digest(data.getBytes());
Formatter formatter = new Formatter();
for (byte b : digest
) {
//将每个字节转换成两个16进制数。
formatter.format("%02x", b);
}
return formatter.toString();
}
public static void main(String[] args) throws Exception {
String data = "hello world";
String sha256Result = SHA256Study.encrypt(data);
System.out.println(sha256Result);
}
}SHA-256 相比 MDA5 有以下优点:
- 散列值长度更长:SHA-256 算法的散列长度有 256 位,MD5 为 128 位,大大提高了攻击者暴力破解和彩虹表攻击的难度。
- 更强的碰撞抗性:SHA 算法采用了更复杂的运算过程和更多的轮次,使得攻击者更难以通过预计算或巧合找到碰撞。
彩虹表攻击(Rainbow Table Attack)是一种密码破解技术,旨在通过预先计算和存储的哈希值(与明文密码相关联的哈希值)来加快破解密码的过程。
DES
DES(Data Encryption Standard)算法是一种对称加密算法,由 IBM 公司于 1975 年研发,是最早的一种广泛应用的对称加密算法之一。
DES 算法使用 56 位密钥对数据进行加密,加密过程中使用了置换、替换、异或等运算,具有较高的安全性。
以下为 DES 算法的 java 用法:
public class DESStudy {
public static String encrypt(String data, String key) throws Exception {
// 创建DES算法的密钥对象,key为8字节。
KeySpec keySpec = new DESKeySpec(key.getBytes());
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
// 创建DES加密器对象
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// 加密明文数据
byte[] encryptedBytes = cipher.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public static String decrypt(String data, String key) throws Exception {
//创建DES算法的秘钥对象,key为8字节
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);
// 创建DES加密器对象
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
// 解密密文数据
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(data));
return new String(decryptedBytes);
}
public static void main(String[] args) throws Exception {
String key = "12345678";
String data = "hello world";
String encryptTest = DESStudy.encrypt(data, key);
System.out.println("加密结果为:" + encryptTest);
String decryptText = DESStudy.decrypt(encryptTest, key);
System.out.println("解密结果为:" + decryptText);
}
}DES 算法的速度较快,但在安全性上面已经不是最优选择,因为他的秘钥只有 8 字节,被暴力破解和差分攻击的风险较高。一般推荐使用更安全的加密算法,如 3DES、AES。
AES
AES(Advanced Encryption Standard)即高级加密标准,是一种对称加密算法,被广泛应用于数据加密和保护领域。AES 算法使用的密钥长度为 128 位、192 位或 256 位,比 DES 算法的密钥长度更长,安全性更高。
以下为 AES 算法的 java 的用法:
public class AESStudy {
public static String encrypt(String data, String key, String iv) throws Exception {
//生成AES秘钥
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES");
//生成AES向量
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
//初始化加密器
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//加密器设置加密模式、秘钥、向量
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
//对数据进行加密
byte[] bytes = cipher.doFinal(data.getBytes());
//加密后数据使用Base64编码
return Base64.getEncoder().encodeToString(bytes);
}
public static String decrypt(String data, String key, String iv) throws Exception {
//生成AES秘钥
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES");
//生成AES向量
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
//初始化加密器
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//加密器设置解密模式、秘钥、向量
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
//对加密后数据使用Base64解码
byte[] decodeData = Base64.getDecoder().decode(data);
//解密数据
byte[] bytes = cipher.doFinal(decodeData);
return new String(bytes);
}
public static void main(String[] args) throws Exception {
//秘钥长度支持128位、192位、256位,对应字符数量为16个、24个、32个
String key = "0123456789012345";
//向量长度为128位,对应字符数量为16个
String iv = "0123456789012345";
String data = "hello world";
String encryptText = encrypt(data, key, iv);
System.out.println("加密结果为:" + encryptText);
String decryptText = decrypt(encryptText, key, iv);
System.out.println("解密结果为:" + decryptText);
}
}需要注意的是,初始化向量(IV)在加密和解密过程中需要保持一致。在实际的生产应用中,初始化向量通常是随机生成的,并与加密一起存储和传输。
RSA
RSA(Rivest-Shamir-Adleman)是一种非对称加密算法,它是由 Ron Rivest、Adi Shamir 和 Leonard Adleman 在 1977 年共同提出的。RSA 算法基于数论中的数学问题,其安全性基于大整数分解的困难性。
以下为 RSA 算法的 java 用法:
public class RSAStudy {
public static KeyPair generateKeyPair() throws Exception {
//获取RSA秘钥对生成器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
//初始化RSA秘钥对生成器,设置秘钥大小
keyPairGenerator.initialize(2048);
//生成RSA键值对
return keyPairGenerator.generateKeyPair();
}
public static String encrypt(String data, Key publicKey) throws Exception, NoSuchAlgorithmException {
//创建RSA加密器实例
Cipher cipher = Cipher.getInstance("RSA");
//初始化RSA加密器
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
//对数据进行加密
byte[] encryptBytes = cipher.doFinal(data.getBytes());
//将加密后数据使用Base64编码
return Base64.getEncoder().encodeToString(encryptBytes);
}
public static String decrypt(String data, Key privateKey) throws Exception {
//创建RSA加密器实例
Cipher cipher = Cipher.getInstance("RSA");
//初始化RSA加密器
cipher.init(Cipher.DECRYPT_MODE, privateKey);
//对加密后数据使用Base64进行解码
byte[] decodeData = Base64.getDecoder().decode(data);
//对加密后数据进行解密
byte[] decodeBytes = cipher.doFinal(decodeData);
//返回解密的数据
return new String(decodeBytes);
}
public static void main(String[] args) throws Exception {
String data = "hello world";
KeyPair keyPair = generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
String encryptText = encrypt(data, publicKey);
System.out.println("加密结果为:" + encryptText);
String decryptText = decrypt(encryptText, privateKey);
System.out.println("解密结果为:" + decryptText);
}
}RSA 算法的优点是安全性高,公钥可以公开,私钥必须保密,保证了数据的安全性;可用于数字签名、密钥协商等多种应用场景。
缺点是加密、解密速度较慢,密钥长度越长,加密、解密时间越长;密钥长度过短容易被暴力破解,密钥长度过长则会增加计算量和存储空间的开销。
RSA 秘钥长度不一定是 2048 位,RSA 支持不同的秘钥长度,常见的有 1024、2048、4096。较短的秘钥,有被暴力破解的可能。较长的秘钥,则会增加计算量和存储空间的开销。一般来说,2048 位已经被广泛接受为具有较高安全性的长度,并被认为足够用于大多数应用场景。
国密算法
国密是中国的商用密码算法标准,全称为"中国商用密码算法"。它是由中国国家密码管理局制定的一套密码算法标准,用于保护国家信息安全和保密通信。国密标准主要包括对称密码算法、非对称密码算法和杂凑算法等。
国密标准采用了自主研发的密码算法,其中包括SM1、SM2、SM3和SM4等算法。
- SM1是对称密码算法,用于加密和解密数据;该算法不公开,需搭配加密芯片,调用加密芯片的接口进行加解密。
- SM2是非对称密码算法,用于数字签名、密钥交换和公钥加密;该算法已公开。
- SM3是杂凑算法,用于生成数据的哈希值;该算法已公开。
- SM4是对称密码算法,用于数据的分组加密。
数字证书、数字认证
数字证书包含了拥有者的域名和公钥。
证书分类
- EV 证书
- OV 证书
- DV 证书
SSL/TLS
TLS 是一个混合加密系统,使用了对称加密和非对称加密两种方式。
握手流程
- 客户端向服务端发送 TLS 版本信息和一个随机数 A。此时为明文传输。
- 服务端接受到消息后,向客户端发送 TLS 版本信息、数字证书和随机数 B。此时为明文传输。
- 客户端收到数字证书后,开始验证数字证书。数字证书验证后,生成一个pre-master key并使用数字证书中的公钥进行加密,然后发送到服务器。此时为非对称加密传输。
- 服务端收到消息后,对消息进行解密,获得pre-master key。
- 客户端和服务端使用随机数 A、随机数 B、pre-master key按照协商好的算法生成一个对称密钥 share secert
- 客户端计算出密钥后,使用该密钥进行对称加密通信,告知服务器之后使用该密钥同行。此时为对称加密传输。
- 服务端收到密文后,使用之前计算出的密钥进行对称解密。解密成功后,再使用该密钥进行对称加密通信。告知客户端密钥确认无误,可以使用该密钥进行同行。此时为对称加密传输。
- 到此,整个 TLS 的握手过程完成,之后就可以开始对称加密的通信了。

HTTPS 请求流程
