在 AES GCM 模式下使用 CipherOutputStream 时出现 ShortBufferException

问题描述 投票:0回答:1

我正在尝试编写一个加密和解密文件的加密器/解密器类。我的服务器以

InputStream
的形式接收文件,我想将其存储在特定路径中,因此这些是我的
encrypt()
方法的输入。出于测试目的,
encrypt()
为每个文件生成一个新密钥,并将其与文件路径一起存储在映射中。我的
decrypt()
方法仅获取文件名并尝试将文件内容打印为字符串。
encrypt()
似乎工作正常。我遇到的问题是,当我使用文件名调用
decrypt()
时,我得到一个 ShortBufferException。我尝试更改 BufferedReader 中的缓冲区大小,但无济于事。我认为我遗漏了一些关于
CipherInputStream
InputStream
在一般工作中如何工作的基本知识。任何想法将不胜感激!这是我的
FileEncrypterDecrypter
课程:

public class FileEncrypterDecrypter {
    private static final int ALGORITHM_NONCE_SIZE = 12;
    private static final String ALGORITHM_NAME = "AES/GCM/NoPadding";
    private final static int ALGORITHM_TAG_SIZE = 128;
    private final static HashMap<String, SecretKey> fileToKey = new HashMap<>();

    FileEncrypterDecrypter() {}

    public static void encrypt(InputStream plaintext, String filePath) throws IOException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException {
        // Generate a new SecretKey for this file
        SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
        fileToKey.put(filePath, secretKey);

        // Generate a 96-bit nonce using a CSPRNG.
        SecureRandom rand = new SecureRandom();
        byte[] nonce = new byte[ALGORITHM_NONCE_SIZE];
        rand.nextBytes(nonce);
        System.out.println(Arrays.toString(nonce));

        // Create the cipher instance and initialize.
        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(ALGORITHM_TAG_SIZE, nonce));

        // Write to the file using a CipherOutputStream
        FileOutputStream fileOut = new FileOutputStream(filePath);
        CipherOutputStream cipherOut = new CipherOutputStream(fileOut, cipher);
        fileOut.write(nonce);
        plaintext.transferTo(cipherOut);
    }

    public static String decrypt(String filePath) throws InvalidKeyException, IOException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
        // Get the SecretKey for this file
        SecretKey secretKey = fileToKey.get(filePath);

        // Read nonce from the file
        FileInputStream fileIn = new FileInputStream(filePath);
        byte[] nonce = new byte[ALGORITHM_NONCE_SIZE];
        fileIn.read(nonce);
        System.out.println(Arrays.toString(nonce));
        fileIn = new FileInputStream(filePath);
        // Create the cipher instance and initialize
        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, nonce));

        CipherInputStream cipherIn = new CipherInputStream(fileIn, cipher);
        InputStreamReader inputReader = new InputStreamReader(cipherIn);
        BufferedReader reader = new BufferedReader(inputReader);

        // Decrypt and return result.
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
        return sb.toString();
    }
}

我的错误输出:

Exception in thread "main" java.io.IOException: javax.crypto.ShortBufferException: Output buffer invalid
    at java.base/javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:148)
    at java.base/javax.crypto.CipherInputStream.read(CipherInputStream.java:261)
    at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:270)
    at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:313)
    at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:188)
    at java.base/java.io.InputStreamReader.read(InputStreamReader.java:177)
    at java.base/java.io.BufferedReader.fill(BufferedReader.java:162)
    at java.base/java.io.BufferedReader.readLine(BufferedReader.java:329)
    at java.base/java.io.BufferedReader.readLine(BufferedReader.java:396)
    at FileEncrypterDecrypter.decrypt(FileEncrypterDecrypter.java:64)
    at Main.main(Main.java:22)
Caused by: javax.crypto.ShortBufferException: Output buffer invalid
    at java.base/com.sun.crypto.provider.GaloisCounterMode$GCMDecrypt.doFinal(GaloisCounterMode.java:1366)
    at java.base/com.sun.crypto.provider.GaloisCounterMode.engineDoFinal(GaloisCounterMode.java:432)
    at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2152)
    at java.base/javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:145)
    ... 10 more

这是我的主要方法:

public static void main (String[] args) throws BadPaddingException, IllegalBlockSizeException, IOException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException {
        InputStream is = new ByteArrayInputStream(Charset.forName("UTF-8").encode("HELLO WORLD").array());
        FileEncrypterDecrypter encrypterDecrypter = new FileEncrypterDecrypter();
        encrypterDecrypter.encrypt(is, "./message");
        encrypterDecrypter.decrypt("./message");
    }

我在 Stack Overflow 上发现了类似的问题,但没有一个完全适合我的情况。

java encryption aes aes-gcm
1个回答
0
投票

您没有关闭加密代码中的 OutputStream,这会阻止加密最终代码运行。

© www.soinside.com 2019 - 2024. All rights reserved.