当前位置: 首页 > 知识库问答 >
问题:

使用附加的初始化向量java加密和解密流文件

尹赞
2023-03-14

我已经编写了一个Java程序,它要求用户指定一个随机密钥(以base 64编码),指定要加密的纯文本文件,以及输出文件的名称(加密的文本文件)。

然后反向解密(密钥输入加密文件名输出解密文件)。

这遵循与OpenSSL提供的非常相似的行为。

我的java代码使用模式AES/CBC/PKCS5PADDING

我已经使用文件输出流事先将随机生成的初始化向量(16 字节 IV)附加到我的密文中。然后我相信密码输出流在 IV 之后写入密文。

我可以确认从encrypt和decrypt方法中生成和获取的IV是相同的(都可以用base64编码打印出来,并且会匹配)。

然而,问题在于试图解密加密的文本。解密后的文本能够显示加密文本的后半部分(与原始纯文本的后半部分相匹配)。

示例:

明文:<代码>我的秘密座右铭:我真棒

密文:

解密文本:

虽然前半部分似乎被覆盖或可能收集了一些奇怪的剩余加密文本。这让我相信我使用流加密/解密IV的方式有问题。

当布尔值<code>fileStoreIV</code>为true时,相关的执行代码。else代码用于用户同时提供按键和IV作为输入。

因此fout.write(initVector);encryptedData.read(fileIV);是代码的主要部分。

加密方法:

private static void encrypt(byte[] key, byte[] initVector, String inputFile, String outputFile) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IOException {
    //Initalisation for encryption
    Cipher cipher = Cipher.getInstance(CIPHER);
    if(fileStoreIV) {
        SecretKeySpec skeySpec = new SecretKeySpec(key, ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    }
    else {
        IvParameterSpec iv = new IvParameterSpec(initVector);
        SecretKeySpec skeySpec = new SecretKeySpec(key, ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
    }
    
    //File error checking
    File loadFile = new File(inputFile);
    Path saveFile = Paths.get(outputFile);
    
    Path loadFilePath = Paths.get(inputFile);
    if (!Files.exists(loadFilePath)){
        System.out.println("The inputFile you specified does not exist");
        return;
    }
    
    Path parentDir = saveFile.getParent();
    if (parentDir != null && !Files.exists(parentDir)) {
        System.out.println("The outputFile directory/s you specified does not exist");
        return;
    }
    
    System.out.println("Secret key is " + Base64.getEncoder().encodeToString(key));
    System.out.println("IV is " + Base64.getEncoder().encodeToString(initVector));

    //Special file reading and writing with 'Cipher Stream'
    try (InputStream fin = FileEncryptor.class.getResourceAsStream(loadFile.getName());
            OutputStream fout = Files.newOutputStream(saveFile);
            
            CipherOutputStream cipherOut = new CipherOutputStream(fout, cipher) {
    }) {
        final byte[] bytes = new byte[1024];
        for(int length=fin.read(bytes); length!=-1; length = fin.read(bytes)){
            
            
            if(fileStoreIV) {
                fout.write(initVector);
                fileStoreIV = false;
            }
            
            cipherOut.write(bytes, 0, length);
            
        }
    } catch (IOException e) {
        System.out.println("Something went wrong with reading and writing these files!");
        System.out.println("Please check you have the latest version of this program");
        System.out.println("Contact your IT admin to make sure you have sufficient privileges");
    }
    System.out.println("SUCCESS! Encryption finished, saved at specified location");

解密方法:

private static void decrypt(String inputKEY, String inputIV, String inputFile, String outputFile) throws NoSuchAlgorithmException, NoSuchPaddingException, IOException, InvalidKeyException, InvalidAlgorithmParameterException {
    //Initalisation for decryption
    Cipher cipher = Cipher.getInstance(CIPHER);
    if(!fileStoreIV) {
        IvParameterSpec iv = new IvParameterSpec(Base64.getDecoder().decode(inputIV));
        SecretKeySpec skeySpec = new SecretKeySpec(Base64.getDecoder().decode(inputKEY), ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
    }
    
    Path saveFile = Paths.get(outputFile);
    
    Path loadFilePath = Paths.get(inputFile);
    if (!Files.exists(loadFilePath)){
        System.out.println("The inputFile you specified does not exist");
        return;
    }
    
    Path parentDir = saveFile.getParent();
    if (parentDir != null && !Files.exists(parentDir)) {
        System.out.println("The outputFile directory/s you specified does not exist");
        return;
    }
    
    InputStream encryptedData = Files.newInputStream(loadFilePath);
    
    if(fileStoreIV) {
        {
            byte[] fileIV = new byte[16];
            encryptedData.read(fileIV);
            System.out.println(Base64.getEncoder().encodeToString(fileIV));
                SecretKeySpec skeySpec = new SecretKeySpec(Base64.getDecoder().decode(inputKEY), ALGORITHM);
                cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(fileIV));
                fileStoreIV = false;
        }
    }
    
        try (CipherInputStream decryptStream = new CipherInputStream(encryptedData, cipher);    
        OutputStream decryptedOut = Files.newOutputStream(saveFile)){
        final byte[] bytes = new byte[1024];
        for(int length=decryptStream.read(bytes); length!=-1; length = decryptStream.read(bytes)){
            decryptedOut.write(bytes, 0, length);
        }
    } catch (IOException e) {
        System.out.println("Something went wrong with reading and writing these files!");
        System.out.println("Please check you have the latest version of this program");
        System.out.println("Contact your IT admin to make sure you have sufficient privileges");
    }
    
    System.out.println("SUCESS! Decryption finished, saved at specified location");

附加说明:当我在纯文本文件之前和内部添加足够的空格时。我设法移动了足够的文本,以显示解密的文件:


共有1个答案

宣俊豪
2023-03-14
匿名用户

解密未成功运行的主要原因是加密方法中的这部分代码:

if(fileStoreIV) {
     SecretKeySpec skeySpec = new SecretKeySpec(key, ALGORITHM);
     cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
} else {
     IvParameterSpec iv = new IvParameterSpec(initVector);
     SecretKeySpec skeySpec = new SecretKeySpec(key, ALGORITHM);
     cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
}

fileStoreIV==true时,您没有为cipher.init函数指定IV。因为IV是错误的,解密明文的第一个块(AES为16个字节)被有效的随机垃圾替换;这可能是明文的一半、全部或一小部分,取决于它的长度(根据@dave_thompson_085的评论)。

我修改了您的代码,因为由于其他一些错误,它没有开箱即用,但我懒得纠正它们,相反,您可以在下面找到一个完整的运行示例代码。

下面是程序的输出,我的明文文件包含文本< code >敏捷的棕色狐狸跳过懒狗:

Secret key is S2guVMqVk8goYy3QsgBSMmjLLCyvoknprTGoFsxMZEo=
IV is VFIYWeCT6ixg/lwk9bBQ9g==
SUCCESS! Encryption finished, saved at specified location
SUCESS! Decryption finished, saved at specified location
Content of file decryptedtext.txt
The quick brown fox jumps over the lazy dog

代码:

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

public class FileEncryptorSo {
    static String ALGORITHM = "AES";
    static String CIPHER = "AES/CBC/PKCS5PADDING";
    static boolean fileStoreIV = true;

    public static void main(String[] args) throws IOException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
        System.out.println("");
        String plaintextFilename = "plaintext.txt";
        String ciphertextFilename = "ciphertext.enc";
        String decryptedFilename = "decryptedtext.txt";
        // random aes 256 key
        byte[] key = new byte[32];
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.nextBytes(key);
        // random iv
        byte[] iv = new byte[16];
        secureRandom.nextBytes(iv);
        encrypt(key, iv, plaintextFilename, ciphertextFilename);
        decrypt(Base64.getEncoder().encodeToString(key), Base64.getEncoder().encodeToString(iv), ciphertextFilename, decryptedFilename);
        printTextfile(decryptedFilename);
    }

    private static void encrypt(byte[] key, byte[] initVector, String inputFile, String outputFile)
            throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
        //Initalisation for encryption
        Cipher cipher = Cipher.getInstance(CIPHER);
        IvParameterSpec iv = new IvParameterSpec(initVector);
        SecretKeySpec skeySpec = new SecretKeySpec(key, ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        /* ### leave out this part !
        if (fileStoreIV) {
            SecretKeySpec skeySpec = new SecretKeySpec(key, ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        } else {
            IvParameterSpec iv = new IvParameterSpec(initVector);
            SecretKeySpec skeySpec = new SecretKeySpec(key, ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        }
         */
        //File error checking
        // ### not used File loadFile = new File(inputFile);
        Path saveFile = Paths.get(outputFile);
        Path loadFilePath = Paths.get(inputFile);
        if (!Files.exists(loadFilePath)) {
            System.out.println("The inputFile you specified does not exist");
            return;
        }
        Path parentDir = saveFile.getParent();
        if (parentDir != null && !Files.exists(parentDir)) {
            System.out.println("The outputFile directory/s you specified does not exist");
            return;
        }
        System.out.println("Secret key is " + Base64.getEncoder().encodeToString(key));
        System.out.println("IV is " + Base64.getEncoder().encodeToString(initVector));
        try (FileInputStream in = new FileInputStream(inputFile);
             FileOutputStream out = new FileOutputStream(outputFile);
             CipherOutputStream encryptedOutputStream = new CipherOutputStream(out, cipher);) {
            if (fileStoreIV) {
                out.write(initVector);
                // ### leave out this line fileStoreIV = false;
            }
            byte[] buffer = new byte[1024];
            int nread;
            while ((nread = in.read(buffer)) > 0) {
                encryptedOutputStream.write(buffer, 0, nread);
            }
            encryptedOutputStream.flush();
        } catch (IOException e) {
            System.out.println("Something went wrong with reading and writing these files!");
            System.out.println("Please check you have the latest version of this program");
            System.out.println("Contact your IT admin to make sure you have sufficient privileges");
        }
        System.out.println("SUCCESS! Encryption finished, saved at specified location");
    }

    private static void decrypt(String inputKEY, String inputIV, String inputFile, String outputFile)
            throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
        //Initalisation for decryption
        Cipher cipher = Cipher.getInstance(CIPHER);
        if (!fileStoreIV) {
            IvParameterSpec iv = new IvParameterSpec(Base64.getDecoder().decode(inputIV));
            SecretKeySpec skeySpec = new SecretKeySpec(Base64.getDecoder().decode(inputKEY), ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
        }
        Path saveFile = Paths.get(outputFile);
        Path loadFilePath = Paths.get(inputFile);
        if (!Files.exists(loadFilePath)) {
            System.out.println("The inputFile you specified does not exist");
            return;
        }
        Path parentDir = saveFile.getParent();
        if (parentDir != null && !Files.exists(parentDir)) {
            System.out.println("The outputFile directory/s you specified does not exist");
            return;
        }
        //byte[] fileIV = new byte[16];
        try (FileInputStream in = new FileInputStream(inputFile);
             CipherInputStream cipherInputStream = new CipherInputStream(in, cipher);
             FileOutputStream out = new FileOutputStream(outputFile))
        {
            byte[] buffer = new byte[1024];
            if (fileStoreIV) {
                byte[] fileIV = new byte[16];
                in.read(fileIV);
                SecretKeySpec skeySpec = new SecretKeySpec(Base64.getDecoder().decode(inputKEY), ALGORITHM);
                cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(fileIV));
                // ### leave out his line fileStoreIV = false;
            }
            int nread;
            while ((nread = cipherInputStream.read(buffer)) > 0) {
                out.write(buffer, 0, nread);
            }
            out.flush();
        } catch (IOException e) {
            System.out.println("Something went wrong with reading and writing these files!");
            System.out.println("Please check you have the latest version of this program");
            System.out.println("Contact your IT admin to make sure you have sufficient privileges");
        }
        System.out.println("SUCESS! Decryption finished, saved at specified location");
    }

    private static void printTextfile (String filename) throws IOException {
        File file = new File(filename);
        FileInputStream fis = new FileInputStream(file);
        byte[] data = new byte[(int) file.length()];
        fis.read(data);
        fis.close();
        String str = new String(data, "UTF-8");
        System.out.println("Content of file " + filename + "\n" + str);
    }
}

 类似资料:
  • 问题内容: 我有一个关于在AES加密中使用初始化向量的问题。我引用以下文章/帖子将加密功能构建到程序中: [1] 基于Java256位AES密码的加密 [2]http://gmailassistant.sourceforge.net/src/org/freeshell/zs/common/Encryptor.java.html 我最初从第一个链接开始关注erickson的解决方案,但是据我所知,我

  • 我在一个项目中工作,在这个项目中,我通过XML流向web服务发帖。在这种情况下,提供程序请求使用密码块链接(CBC)模式下的高级加密标准(AES)和128位初始化向量对路由xml进行加密。我是用VB.NET编码的,从我可以看出我已经满足了他们所有的加密要求,但当我提交帖子时,我总是得到一个“无效的路由输入加密”的错误响应。我没有做很多与加密,所以我希望有人与一些加密经验可以帮助我在这里。它失败是因

  • 我正在努力解决这个问题。所以我几乎编写了整个代码,但问题是我无法初始化监视器(我编写了伪代码,我用c重新编写),所以我无法测试程序。谁能帮我说说监视器/互斥体初始化有什么问题吗? 我在第18行得到错误,它是这样的:error:'intpthread\u mutex\u init'被重新声明为不同类型的符号 将其更改为int pthread_mutex_init( 通过添加int pthread_m

  • 我使用初始化向量和填充实现了AES 128位加密,如下面的代码所示。我碰巧使用了ColdFusion,但我认为这并不重要。加密结果显示了一些重复模式,这是我没有预料到的,但话说回来,我不知道正确输出的特征。我是否正确地进行了初始化向量和填充? 下面是示例输出: 每个加密字符串都以相同的21个字符结尾: 当原始字符串相同(第3和第4个示例中的“String3”)时,EncryptedString以相

  • 问题内容: 我想将加密的密码存储在Java文件中。我在使用 javax.crypto 的解决方案中看到了一个问题,但是问题在于密钥是动态生成的,并且是随机的。 然后将在运行时在Java程序中获取并解密该密码。鉴于我要在文件中存储一个已经加密的密码-解密时我想要正确的文本。 有没有办法告诉javax.crypto方法: 可以将其替换为基于某个私钥生成的我自己的密钥吗? 谁能指出一些有关执行此操作的资

  • 问题内容: 有没有一种方法可以解密Java中的密码。Java将算法实现为。我得到了创建密码哈希的代码。我在下面提到了哈希技术的链接: http://howtodoinjava.com/security/how-to-generate-secure-password-hash- md5-sha-pbkdf2-bcrypt-examples/ 我的要求是以加密格式存储第三方FTP服务器密码,并在需要登