我试图编写一个仅使用密码对象加密\ decrypts文件的函数,即CipherInputStream是不允许的(作业问题)。但经过一段时间的调试后,我无法解决错误的问题。
加密工作尽我所知(使用open-ssl加密并比较我的代码和open-ssl输出的sha1sums,但解密仅适用于前16个字节,然后提供错误的数据,导致结尾处的BadPaddingException。 / p>
代码分为两个函数和一个来自main的调用者:
private static void symetricKeyCriptographyHandler(final int opmode, final Path source,
final Path destination) {
try (InputStream in = new BufferedInputStream(Files.newInputStream(source),
BUFFER_BLOCK_SIZE);
OutputStream out = new BufferedOutputStream(Files.newOutputStream(destination),
BUFFER_BLOCK_SIZE);
BufferedReader scr = new BufferedReader(new InputStreamReader(System.in,
StandardCharsets.UTF_8))) {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
System.out
.format("Please provide password as hex-encoded text (16 bytes, i.e. 32 hex-digits):%n> ");
byte[] key = hexToByte(scr.readLine().trim());
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
System.out
.format("Please provide initialization vector as hex-encoded text (32 hex-digits):%n> ");
byte[] iv = hexToByte(scr.readLine().trim());
IvParameterSpec paramSpec = new IvParameterSpec(iv);
// Writing out key and iv as debugging tools. Checks out as far as I can tell.
for (byte b : key) {
System.out.format("%02x", b);
}
System.out.println();
for (byte b : iv) {
System.out.format("%02x", b);
}
System.out.println();
cipher.init(opmode, keySpec, paramSpec);
processCryptedData(cipher, in, out);
System.out.format("%s completed. Generated file %s based on file %s",
opmode == Cipher.ENCRYPT_MODE ? "Encryption" : "Decription",
destination.getFileName(), source.getFileName());
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
// Should never happen!!!
e.printStackTrace();
} catch (NoSuchFileException ex) {
System.err.println(ex.getFile() + " does not exist.");
} catch (AccessDeniedException ex) {
System.err.println(ex.getFile() + " access is denied.");
} catch (IOException | InvalidKeyException | InvalidAlgorithmParameterException
| ShortBufferException | IllegalBlockSizeException | BadPaddingException
| IllegalArgumentException e) {
System.err.println(e.getMessage());
}
}
Helper函数,它使用密码和输入\输出流来完成它的工作:
private static void processCryptedData(final Cipher cipher, final InputStream source,
final OutputStream destination) throws IOException, ShortBufferException,
IllegalBlockSizeException, BadPaddingException {
final int cipherBlockSize = cipher.getBlockSize();
// BUFFER_BLOCK_SIZE = 4096, chosen arbitrarily.
// I'm aware it isn't used in the fullest.
byte[] buff = new byte[BUFFER_BLOCK_SIZE];
int r;
while ((r = source.read(buff, 0, cipherBlockSize)) > 0) {
r = cipher.update(buff, 0, r, buff);
destination.write(buff, 0, r);
}
destination.write(cipher.doFinal());
}
最后来自main的来电者:
case "encrypt":
if (args.length != 3) {
System.err.println("Invalid number of command line arguments.");
System.exit(1);
}
symetricKeyCriptographyHandler(Cipher.ENCRYPT_MODE, Paths.get(args[1]),
Paths.get(args[2]));
break;
case "decrypt":
if (args.length != 3) {
System.err.println("Invalid number of command line arguments.");
System.exit(1);
}
symetricKeyCriptographyHandler(Cipher.DECRYPT_MODE, Paths.get(args[1]),
Paths.get(args[2]));
编辑(感谢@owlstead):
显然使用单独的输入\输出缓冲区可以解决问题,但我很困惑,因为在Cipher文档中注意到.update应该是安全的。
在我测试过的以下代码在processCryptedData:中工作正常
byte[] ibuff = new byte[cipher.getOutputSize(BUFFER_BLOCK_SIZE)];
byte[] obuff = new byte[cipher.getOutputSize(BUFFER_BLOCK_SIZE)];
int r;
while ((r = source.read(ibuff, 0, BUFFER_BLOCK_SIZE)) > 0) {
r = cipher.update(ibuff, 0, r, obuff);
destination.write(obuff, 0, r);
}