我尝试在使用套接字发送文件时使用加密和解密。我使用 AES/CBC/PKCS5Padding
算法并首先编写 IV
然后将文件发送到流。
问题是,循环不会在文件接收时结束。
我认为这是由于文件的大小和加密文件似乎比原始文件小,而我把原始文件的大小给了接收者。如果这个假设是正确的,有没有办法计算加密文件的大小?
文件发送者
SecretKey keySpec = new SecretKeySpec(key, "AES");
byte[] iv = AES.randomNonce(16);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec);
outputStream = socket.getOutputStream();
outputStream.write(iv);
outputStream.flush();
inputStream = context.getContentResolver().openInputStream(message.getUri());
cipherOutputStream = new CipherOutputStream(outputStream, cipher);
long size = message.getSize();
long written = 0;
byte[] buffer = new byte[8192];
int count;
int percent = 0;
while (!isStopped && (count = inputStream.read(buffer)) > 0) {
cipherOutputStream.write(buffer, 0, count);
written += count;
int p = (int) (((float) written / (float) size) * 100);
if (percent != p) {
percent = p;
if (onProgressListener != null) {
onProgressListener.onProgress(percent);
}
}
}
cipherOutputStream.flush();
if (onProgressListener != null) {
onProgressListener.onEnd(null);
}
文件接收器
inputStream = socket.getInputStream();
fileOutputStream = new FileOutputStream(file);
byte[] iv = new byte[16];
inputStream.read(iv);
SecretKey keySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);
cipherInputStream = new CipherInputStream(inputStream, cipher);
long size = message.getSize();
long read = size;
byte[] buffer = new byte[8192];
int count;
int percent = 0;
while (!isStopped && read > 0 && (count = cipherInputStream.read(buffer, 0, (int) Math.min(buffer.length, read))) != -1) {
fileOutputStream.write(buffer, 0, count);
read -= count;
int p = (int) (((float) read / (float) size) * 100);
if (percent != p) {
percent = p;
if (onProgressListener != null) {
onProgressListener.onProgress(100 - percent);
}
}
}
if (onProgressListener != null) {
onProgressListener.onEnd(Uri.fromFile(file));
}
2条答案
按热度按时间3mpgtkmj1#
这是一个android项目的问题。当我在androidstudio中运行此代码时,logcat没有显示任何异常。但当我使用eclipse在windows中运行此代码时,出现了以下异常:
所以,根据凯拉拉卡的回答,我意识到问题是
cipherInputStream
以及cipherOutputStream
未正确关闭。事实上,我先关门inputStream
以及outputStream
,然后加密流。所以我先关闭密码流,然后关闭其他流,现在加密工作正常。ltqd579y2#
错误代码
正如jamesk.polk主席所说,你需要关闭
CipherOutputStream
通过调用.close()
调用doFinal()
完成加密。填充大小
尽管 java 说
PKCS5Padding
实际上是的PKCS#7 Padding
.PKCS#5 Padding
为8个八位字节定义,即具有64位块大小(如des)的块密码。pkcs#7标准见rfc2315(10.3注2):
对于此类算法,该方法应使用k-(l mod k)八位字节填充尾端的输入,所有八位字节的值均为k-(l mod k),其中l是输入的长度。
八位字节是一个字节
k
以字节为单位的块大小16
对于aes。我们需要计算
IV_length + message_size_with_padding
如果我们假设你有l
字节进行加密,则输出大小为16 + l + 16 - (l mod 16)
因此,由于填充,最多扩展16字节。请注意,cbc模式在适用的情况下容易受到oracle攻击。cbc模式只提供机密性。如果您需要完整性和身份验证(您应该)或者将cbc与hmac一起使用,或者更好地使用像aes-gcm这样的身份验证加密模式,它根本不需要填充,但是,您也需要存储标记。如果您担心aes-gcm的nonce重用问题,那么您可以使用aes-gcm-siv,这是一种抗nonce误用的方案。如果您没有义务使用aes,您可以选择chacha20-poly1305,它可能比aes gcm更容易使用[1][2]。