Java 如何加密分割文件的每个部分

Java 如何加密分割文件的每个部分,java,file,encryption,file-io,Java,File,Encryption,File Io,我有一个类可以将给定的文件拆分并合并为多个文件,但我想知道如何在拆分时加密每个文件,然后在再次合并时解密 这是用于文件拆分和合并的类 public void splitFile(File f) throws Exception { int partCounter = 1; int sizeOfFiles = (int) (f.length() / 3); byte[] buffer = new byte[sizeOfFiles]; String fileNam

我有一个类可以将给定的文件拆分并合并为多个文件,但我想知道如何在拆分时加密每个文件,然后在再次合并时解密

这是用于文件拆分和合并的类

public void splitFile(File f) throws Exception {
    int partCounter = 1;

    int sizeOfFiles = (int) (f.length() / 3);
    byte[] buffer = new byte[sizeOfFiles];

    String fileName = f.getName();
    String destFileName = fileName.substring(0, fileName.lastIndexOf('.')) + "." + FilenameUtils.getExtension(fileName);

    try (FileInputStream fis = new FileInputStream(f);
            BufferedInputStream bis = new BufferedInputStream(fis)) {

        int bytesAmount = 0;

        while ((bytesAmount = bis.read(buffer)) > 0) {

            String filePartName = String.format("%s.%03d", destFileName, partCounter++);
            File newFile = new File("D:\\FileTest\\", filePartName);
            try (FileOutputStream out = new FileOutputStream(newFile)) {
                //I think this is how you encrypt each split part before it gets written to a file?
                out.write(FileEncrypt.encrypt(buffer, encKey), 0, bytesAmount);
            }
        }
        bos.close();
    }
}

public List<File> listOfFilesToMerge(File oneOfFiles) throws IOException, Exception {
    String tmpName = oneOfFiles.getName();
    String destFileName = tmpName.substring(0, tmpName.lastIndexOf('.'));
    File[] files = oneOfFiles.getParentFile().listFiles((File dir, String name) -> name.matches(destFileName + "[.]\\d+"));
    Arrays.sort(files);
    for (File f : files) {
        //And this is how to decrypt the files before it gets merged?
        FileEncrypt.decrypt(Files.readAllBytes(f.toPath()), encKey);
    }
    return Arrays.asList(files);
}

public void mergeFiles(List<File> files, File into) throws Exception {
    try (FileOutputStream fos = new FileOutputStream(into);
            BufferedOutputStream mergingStream = new BufferedOutputStream(fos)) {
        for (File f : files) {
            Files.copy(f.toPath(), mergingStream);
        }
    }
}
public void splitFile(文件f)引发异常{
int partCounter=1;
int sizeofficeles=(int)(f.length()/3);
字节[]缓冲区=新字节[sizeOfFiles];
字符串文件名=f.getName();
String destFileName=fileName.substring(0,fileName.lastIndexOf('.')+“+”+FilenameUtils.getExtension(fileName);
try(FileInputStream fis=newfileinputstream(f);
BufferedInputStream bis=新的BufferedInputStream(fis)){
int字节数=0;
而((字节数=bis.read(buffer))>0){
String filePartName=String.format(“%s.%03d”,destFileName,partCounter++);
File newFile=新文件(“D:\\FileTest\\”,filePartName);
try(FileOutputStream out=newfileoutputstream(newFile)){
//我想这就是在写入文件之前加密每个分割部分的方法?
out.write(FileEncrypt.encrypt(buffer,encKey),0,bytesAmount);
}
}
bos.close();
}
}
公共列表ListOfficeStorege(文件oneOfFiles)引发IOException,Exception{
字符串tmpName=oneofiles.getName();
字符串destFileName=tmpName.substring(0,tmpName.lastIndexOf('.');
File[]files=oneofficefiles.getParentFile().listFiles((文件目录,字符串名称)->name.matches(destFileName+“[.]\\d+”);
数组。排序(文件);
用于(文件f:文件){
//这就是如何在文件合并之前解密文件?
FileEncrypt.decrypt(Files.readAllBytes(f.toPath()),encKey);
}
返回Arrays.asList(文件);
}
公共void合并文件(列出文件、文件到)引发异常{
try(FileOutputStream fos=新的FileOutputStream(into);
BufferedOutputStream mergingStream=新的BufferedOutputStream(fos)){
用于(文件f:文件){
copy(f.toPath(),mergingStream);
}
}
}
这是加密类

public static byte[] encrypt(byte[] bytes, String key) throws Exception {
    byte[] iv = new byte[ivSize];
    SecureRandom random = new SecureRandom();
    random.nextBytes(iv);
    IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

    MessageDigest digest = MessageDigest.getInstance("SHA-256");
    digest.update(key.getBytes("UTF-8"));
    byte[] keyBytes = new byte[keySize];
    System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
    SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
    byte[] encrypted = cipher.doFinal(bytes);

    byte[] encryptedIVAndFile = new byte[ivSize + encrypted.length];
    System.arraycopy(iv, 0, encryptedIVAndFile, 0, ivSize);
    System.arraycopy(encrypted, 0, encryptedIVAndFile, ivSize, encrypted.length);

    return encryptedIVAndFile;
}

public static byte[] decrypt(byte[] encryptedIvFileBytes, String key) throws Exception {
    byte[] iv = new byte[ivSize];
    System.arraycopy(encryptedIvFileBytes, 0, iv, 0, iv.length);
    IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

    int encryptedSize = encryptedIvFileBytes.length - ivSize;
    byte[] encryptedBytes = new byte[encryptedSize];
    System.arraycopy(encryptedIvFileBytes, ivSize, encryptedBytes, 0, encryptedSize);

    byte[] keyBytes = new byte[keySize];
    MessageDigest md = MessageDigest.getInstance("SHA-256");
    md.update(key.getBytes("UTF-8"));
    System.arraycopy(md.digest(), 0, keyBytes, 0, keyBytes.length);
    SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");

    Cipher cipherDecrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipherDecrypt.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
    byte[] decrypted = cipherDecrypt.doFinal(encryptedBytes);

    return decrypted;
}

public static String generateEncKey() {
    int strLen = 16;
    char[] chars = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789".toCharArray();
    StringBuilder sb = new StringBuilder();
    Random random = new SecureRandom();
    for (int i = 0; i < strLen; i++) {
        char c = chars[random.nextInt(chars.length)];
        sb.append(c);
    }
    return sb.toString();
}
公共静态字节[]加密(字节[]字节,字符串密钥)引发异常{
字节[]iv=新字节[ivSize];
SecureRandom=新的SecureRandom();
随机。下一字节(iv);
IvParameterSpec IvParameterSpec=新的IvParameterSpec(iv);
MessageDigest=MessageDigest.getInstance(“SHA-256”);
更新(key.getBytes(“UTF-8”);
byte[]keyBytes=新字节[keySize];
System.arraycopy(digest.digest(),0,keyBytes,0,keyBytes.length);
SecretKeySpec SecretKeySpec=新SecretKeySpec(keyBytes,“AES”);
Cipher Cipher=Cipher.getInstance(“AES/CBC/PKCS5Padding”);
cipher.init(cipher.ENCRYPT_模式、secretKeySpec、ivParameterSpec);
字节[]加密=cipher.doFinal(字节);
byte[]encryptedIVAndFile=新字节[ivSize+encrypted.length];
System.arraycopy(iv,0,EncryptedInvandFile,0,ivSize);
System.arraycopy(加密,0,EncryptedInvandFile,ivSize,encrypted.length);
返回加密文件;
}
公共静态字节[]解密(字节[]encryptedIvFileBytes,字符串密钥)引发异常{
字节[]iv=新字节[ivSize];
System.arraycopy(encryptedIvFileBytes,0,iv,0,iv.length);
IvParameterSpec IvParameterSpec=新的IvParameterSpec(iv);
int encryptedSize=encryptedIvFileBytes.length-ivSize;
字节[]encryptedBytes=新字节[encryptedSize];
System.arraycopy(encryptedIvFileBytes,ivSize,encryptedBytes,0,encryptedSize);
byte[]keyBytes=新字节[keySize];
MessageDigest md=MessageDigest.getInstance(“SHA-256”);
md.update(key.getBytes(“UTF-8”);
arraycopy(md.digest(),0,keyBytes,0,keyBytes.length);
SecretKeySpec SecretKeySpec=新SecretKeySpec(keyBytes,“AES”);
Cipher cipherDecrypt=Cipher.getInstance(“AES/CBC/PKCS5Padding”);
cipherDecrypt.init(Cipher.DECRYPT_模式,secretKeySpec,ivParameterSpec);
byte[]decrypted=cipherDecrypt.doFinal(encryptedBytes);
返回解密;
}
公共静态字符串generateEncKey(){
int strLen=16;
char[]chars=“abcdefghjkmnpqrstuvxyzabefghjkmnpqrstuvxyz23456789”。tocharray();
StringBuilder sb=新的StringBuilder();
Random Random=新的SecureRandom();
对于(int i=0;i
当我运行代码时,我得到了-javax.crypto.BadPaddingException错误:给定的最后一个块没有正确填充。如果在解密过程中使用了坏密钥,则可能会出现此类问题

然而,我可以加密和解密一个文件,而无需拆分和合并

public void splitFile(File f) throws Exception {
    int partCounter = 1;

    int sizeOfFiles = (int) (f.length() / 3);
    byte[] buffer = new byte[sizeOfFiles];

    String fileName = f.getName();
    String destFileName = fileName.substring(0, fileName.lastIndexOf('.')) + "." + FilenameUtils.getExtension(fileName);

    try (FileInputStream fis = new FileInputStream(f);
            BufferedInputStream bis = new BufferedInputStream(fis)) {

        int bytesAmount = 0;

        while ((bytesAmount = bis.read(buffer)) > 0) {

            String filePartName = String.format("%s.%03d", destFileName, partCounter++);
            File newFile = new File("D:\\FileTest\\", filePartName);
            try (FileOutputStream out = new FileOutputStream(newFile)) {
                //I think this is how you encrypt each split part before it gets written to a file?
                out.write(FileEncrypt.encrypt(buffer, encKey), 0, bytesAmount);
            }
        }
        bos.close();
    }
}

public List<File> listOfFilesToMerge(File oneOfFiles) throws IOException, Exception {
    String tmpName = oneOfFiles.getName();
    String destFileName = tmpName.substring(0, tmpName.lastIndexOf('.'));
    File[] files = oneOfFiles.getParentFile().listFiles((File dir, String name) -> name.matches(destFileName + "[.]\\d+"));
    Arrays.sort(files);
    for (File f : files) {
        //And this is how to decrypt the files before it gets merged?
        FileEncrypt.decrypt(Files.readAllBytes(f.toPath()), encKey);
    }
    return Arrays.asList(files);
}

public void mergeFiles(List<File> files, File into) throws Exception {
    try (FileOutputStream fos = new FileOutputStream(into);
            BufferedOutputStream mergingStream = new BufferedOutputStream(fos)) {
        for (File f : files) {
            Files.copy(f.toPath(), mergingStream);
        }
    }
}

所以我想知道我不能加密每个分割部分然后解密的代码有什么问题。

bis.read(buffer)
不能保证读取那么多字节,即使是可用的。如果先分割然后加密,那么最好先解密然后合并。第一次合并是可能的,但是您需要知道拆分发生在哪里,因为您只能解密在CBC模式下加密的相同部分。