我正在尝试编写一个加密和解密文件的加密器/解密器类。我的服务器以
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 上发现了类似的问题,但没有一个完全适合我的情况。
您没有关闭加密代码中的 OutputStream,这会阻止加密最终代码运行。