在java中使用AES/CBC/PKCS5P加密后的文件大小是多少

在java中使用AES/CBC/PKCS5P加密后的文件大小是多少,java,android,sockets,encryption,aes,Java,Android,Sockets,Encryption,Aes,我尝试在使用套接字发送文件时使用加密和解密。我使用AES/CBC/PKCS5Padding算法,首先写入IV,然后将文件写入流 问题是循环在文件接收时不会结束 我认为这是由于文件大小和加密文件似乎比原始文件小,而我给接收者原始文件的大小。如果这个假设是正确的,有没有办法计算加密文件的大小 文件发送者 SecretKey keySpec = new SecretKeySpec(key, "AES"); byte[] iv = AE

我尝试在使用套接字发送文件时使用加密和解密。我使用
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));
            }
文件接收器

            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));
            }

不正确的代码

与主持人jamesk.Polk一样,您需要通过调用调用
doFinal()
以完成加密的
close()
函数来关闭发送方端的
CipherOutputStream

填充大小

尽管Java说的是
PKCS5Padding
,但实际上它是
PKCS#7 Padding
PKCS#5填充
是为8个八位字节定义的,即具有64位块大小(如DES)的块密码

PKCS#7标准见(10.3注2):

对于此类算法,该方法应使用k-(l mod k)八位字节填充尾端的输入,所有八位字节的值均为k-(l mod k),其中l是输入的长度

八位字节是一个字节,
k
是以字节为单位的块大小,AES是
16

我们需要使用填充计算
IV\u长度+消息大小

如果我们假设您有
l
字节要加密,则输出大小为

16+l+16-(l mod 16)
因此,由于填充,最多扩展16字节



请注意CBC模式在适用的情况下容易受到填充oracle攻击。CBC模式仅提供机密性。如果您需要完整性和身份验证(您应该)或者将CBC与HMAC一起使用,或者更好地使用AES-GCM这样的身份验证加密模式,它根本不需要填充,但是,您也需要存储标签。如果您担心AES-GCM的临时重用问题,那么您可以使用AES-GCM-SIV,这是一种临时防误用方案。如果您没有义务使用AES,您可以选择ChaCha20-Poly1305,它可能比AES-GCM更易于使用。

这是Android项目的一个问题。当我在Android Studio中运行这段代码时,Logcat没有向我显示任何异常。但是,当我在Windows中使用Eclipse运行此代码时,出现了以下异常:

java.io.IOException: javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.

因此,根据的答案,我意识到问题在于
cipherInputStream
cipherOutputStream
没有正确关闭。事实上,我首先关闭
inputStream
outputStream
,然后关闭密码流。因此,我先关闭了密码流,然后关闭了其他流,现在加密工作正常。

很抱歉代码不完整。我已经关闭了
cipherOutputStream
和我完整代码中的所有其他流。@HusseinYaqoobi您应该发布一个最小的、可验证的、完整的代码。我在几次测试后尝试了这一点:
long size=message.getSize()-16-(message.getSize()%16)并能够跳出环路。但是解密文件的大小比原始文件的大小稍大,加密也没有正确地进行。你考虑过BASE64编码解码吗?你能在没有填充错误的情况下解密吗?你能检查一下最后的块字节吗?