分段加解密的基本思路
分段加密:将要加密的数据分成多个小段,每段的长度不超过 RSA 加密允许的最大长度,然后对每段数据分别进行加密。
分段解密:将加密后的数据分成多个小段,每段的长度为 RSA 加密后的长度,然后对每段数据分别进行解密。
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import javax.crypto.Cipher;
public class RSAUtils {
private static final String RSA_ALGORITHM = "RSA";
private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding";
// 加密块大小 (密钥长度 / 8 - 11) - 这里以2048位密钥为例
private static final int ENCRYPT_BLOCK_SIZE = 2048 / 8 - 11;
// 解密块大小 (密钥长度 / 8) - 这里以2048位密钥为例
private static final int DECRYPT_BLOCK_SIZE = 2048 / 8;
// RSA 分段加密
public static List<byte[]> encryptData(byte[] data, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return splitData(data, cipher, ENCRYPT_BLOCK_SIZE);
}
// RSA 分段解密
public static byte[] decryptData(List<byte[]> encryptedData, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return joinData(encryptedData, cipher);
}
// 将数据分段加密
private static List<byte[]> splitData(byte[] data, Cipher cipher, int blockSize) throws Exception {
int inputLength = data.length;
List<byte[]> encryptedData = new ArrayList<>();
int offset = 0;
while (offset < inputLength) {
int length = Math.min(inputLength - offset, blockSize);
byte[] encryptedBlock = cipher.doFinal(data, offset, length);
encryptedData.add(encryptedBlock);
offset += length;
}
return encryptedData;
}
// 合并解密后的数据
private static byte[] joinData(List<byte[]> encryptedData, Cipher cipher) throws Exception {
List<byte[]> decryptedData = new ArrayList<>();
for (byte[] block : encryptedData) {
byte[] decryptedBlock = cipher.doFinal(block);
decryptedData.add(decryptedBlock);
}
// 合并所有解密后的数据
int totalLength = decryptedData.stream().mapToInt(b -> b.length).sum();
byte[] result = new byte[totalLength];
int currentPosition = 0;
for (byte[] block : decryptedData) {
System.arraycopy(block, 0, result, currentPosition, block.length);
currentPosition += block.length;
}
return result;
}
public static void main(String[] args) throws Exception {
// 示例:假设已经加载了 RSA 公钥和私钥
PublicKey publicKey = getPublicKeyFromBase64String("你的公钥Base64字符串");
PrivateKey privateKey = getPrivateKeyFromBase64String("你的私钥Base64字符串");
String originalText = "这是需要加密的非常长的数据...";
byte[] originalData = originalText.getBytes();
// 分段加密
List<byte[]> encryptedData = encryptData(originalData, publicKey);
// 分段解密
byte[] decryptedData = decryptData(encryptedData, privateKey);
String decryptedText = new String(decryptedData);
System.out.println("Decrypted Text: " + decryptedText);
}
// 加载公钥(Base64 字符串转 PublicKey 对象)
private static PublicKey getPublicKeyFromBase64String(String key) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(key);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
return keyFactory.generatePublic(keySpec);
}
// 加载私钥(Base64 字符串转 PrivateKey 对象)
private static PrivateKey getPrivateKeyFromBase64String(String key) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
return keyFactory.generatePrivate(keySpec);
}
}
使用 RSA 加密和解密大数据时,由于 RSA 本身的限制,无法一次性加密或解密大数据。RSA 加密的最大数据长度受到密钥长度和填充方式的限制。通常,为了加密和解密大数据,需要将数据分段处理。以下是实现分段加解密的基本思路和示例代码。
分段加解密的基本思路
分段加密:将要加密的数据分成多个小段,每段的长度不超过 RSA 加密允许的最大长度,然后对每段数据分别进行加密。
分段解密:将加密后的数据分成多个小段,每段的长度为 RSA 加密后的长度,然后对每段数据分别进行解密。
RSA 分段加密示例
java
复制代码
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import javax.crypto.Cipher;
public class RSAUtils {
private static final String RSA_ALGORITHM = "RSA";
private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding";
// 加密块大小 (密钥长度 / 8 - 11) - 这里以2048位密钥为例
private static final int ENCRYPT_BLOCK_SIZE = 2048 / 8 - 11;
// 解密块大小 (密钥长度 / 8) - 这里以2048位密钥为例
private static final int DECRYPT_BLOCK_SIZE = 2048 / 8;
// RSA 分段加密
public static List<byte[]> encryptData(byte[] data, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return splitData(data, cipher, ENCRYPT_BLOCK_SIZE);
}
// RSA 分段解密
public static byte[] decryptData(List<byte[]> encryptedData, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return joinData(encryptedData, cipher);
}
// 将数据分段加密
private static List<byte[]> splitData(byte[] data, Cipher cipher, int blockSize) throws Exception {
int inputLength = data.length;
List<byte[]> encryptedData = new ArrayList<>();
int offset = 0;
while (offset < inputLength) {
int length = Math.min(inputLength - offset, blockSize);
byte[] encryptedBlock = cipher.doFinal(data, offset, length);
encryptedData.add(encryptedBlock);
offset += length;
}
return encryptedData;
}
// 合并解密后的数据
private static byte[] joinData(List<byte[]> encryptedData, Cipher cipher) throws Exception {
List<byte[]> decryptedData = new ArrayList<>();
for (byte[] block : encryptedData) {
byte[] decryptedBlock = cipher.doFinal(block);
decryptedData.add(decryptedBlock);
}
// 合并所有解密后的数据
int totalLength = decryptedData.stream().mapToInt(b -> b.length).sum();
byte[] result = new byte[totalLength];
int currentPosition = 0;
for (byte[] block : decryptedData) {
System.arraycopy(block, 0, result, currentPosition, block.length);
currentPosition += block.length;
}
return result;
}
public static void main(String[] args) throws Exception {
// 示例:假设已经加载了 RSA 公钥和私钥
PublicKey publicKey = getPublicKeyFromBase64String("你的公钥Base64字符串");
PrivateKey privateKey = getPrivateKeyFromBase64String("你的私钥Base64字符串");
String originalText = "这是需要加密的非常长的数据...";
byte[] originalData = originalText.getBytes();
// 分段加密
List<byte[]> encryptedData = encryptData(originalData, publicKey);
// 分段解密
byte[] decryptedData = decryptData(encryptedData, privateKey);
String decryptedText = new String(decryptedData);
System.out.println("Decrypted Text: " + decryptedText);
}
// 加载公钥(Base64 字符串转 PublicKey 对象)
private static PublicKey getPublicKeyFromBase64String(String key) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(key);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
return keyFactory.generatePublic(keySpec);
}
// 加载私钥(Base64 字符串转 PrivateKey 对象)
private static PrivateKey getPrivateKeyFromBase64String(String key) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
return keyFactory.generatePrivate(keySpec);
}
}
说明:
块大小计算:
加密块大小:ENCRYPT_BLOCK_SIZE = (密钥长度 / 8) - 11。11 是 PKCS1 填充方式的开销。
解密块大小:DECRYPT_BLOCK_SIZE = 密钥长度 / 8。
加密过程:
数据被分成小块,每块的大小不超过 ENCRYPT_BLOCK_SIZE。
每个小块单独加密,并将结果保存到 List<byte[]> 中。
解密过程:
对加密后的数据分块解密,每个小块的大小为 DECRYPT_BLOCK_SIZE。
将解密后的数据块合并成完整的数据。
公钥和私钥加载:
通过 Base64 字符串加载公钥和私钥。
注意事项
分段处理:由于 RSA 的最大加密块长度受限于密钥长度和填充方式,务必确保每个数据块不超过允许的大小。
加密块顺序:加密和解密时必须保持相同的顺序,以确保数据正确性。
填充方式一致:确保加密和解密使用相同的填充方式。