我正在创建一个程序,允许用户上传和下载加密文件,如果他们具有正确的权限,则解密它们。加密和上传很好,下载也是如此,但是当我尝试解密时,我收到“pad block corrupted”错误。
我要做的是获取加密文件,然后制作未加密的副本
我缩短了我的意思,所以请不要评论它看起来不完整。
注册机:
public static SecretKey genGroupSecretKey() {
try {
KeyGenerator keyGen = KeyGenerator.getInstance("AES", "BC");
keyGen.init(128);
return keyGen.generateKey();
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
System.err.println("Error: " + e.getMessage());
e.printStackTrace(System.err);
}
return null;
}
加密:
try (FileInputStream fis = new FileInputStream(sourceFile)) {
response = Utils.decryptEnv((byte[]) tempResponse.getObjContents().get(0), fsSecretKey, ivSpec);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
do {
byte[] buf = new byte[4096];
int n = fis.read(buf); // can throw an IOException
else if (n < 0) {
System.out.println("Read error");
fis.close();
return false;
}
byte[] cipherBuf = cipher.doFinal(buf);
// send through socket blah blah blah
} while (fis.available() > 0);
解密:
...
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, secKey, ivSpec);
File file = new File("D_" + filename); // D_ for decrypted
FileOutputStream fos = null;
if (!file.exists()) {
file.createNewFile();
fos = new FileOutputStream(file);
}
try (FileInputStream fis = new FileInputStream(filename)) {
do {
byte[] buf = new byte[4096];
int n = fis.read(buf);
if (n < 0) {
System.out.println("Read error");
fis.close();
return false;
}
byte[] cipherBuf = cipher.doFinal(buf); // ERROR HERE
System.out.println("IS THIS WORKING WTF: " + new String(cipherBuf));
fos.write(cipherBuf, 0, n);
} while (fis.available() > 0);
fis.close();
fos.close();
return true;
答案 0 :(得分:5)
您应该Cipher.doFinal()
仅针对最后一个数据块。您应修改加密和解密代码,以便对所有中间数据使用Cipher.update()
,并在最后使用Cipher.doFinal()
一次调用。允许对所有中间数据块使用Cipher.update()
,并在最后用空数组调用Cipher.doFinal()
。
此外,当您将从流中读取的数据传递给密码时,您忽略了fis.read(buf)
的返回值。
此外,您使用InputStream.available()
作为结束循环的条件。即使循环中的代码是正确的,由于循环条件的虚假触发,你也会得到不可预测的结果。
使用以下模式处理密码:
Cipher cipher = ...
InputStream in = ...
OutputStream out = ...
byte[] inputBuffer = new byte[ BUFFER_SIZE ];
int r = in.read(inputBuffer);
while ( r >= 0 ) {
byte[] outputUpdate = cipher.update( inputBuffer, 0, r );
out.write( outputUpdate );
r = in.read(inputBuffer);
}
byte[] outputFinalUpdate = cipher.doFinal();
out.write( outputFinalUpdate );
检查Cipher.update()
的其他变体 - 可以使用两个预先分配的缓冲区并最小化其他分配。
同时检查您是否可以重复使用javax.crypto.CipherInputStream
和javax.crypto.CipherOutputStream
类,这样您就不必直接使用密码。
答案 1 :(得分:0)
如果目标只是加密和解密文件,以下程序将有所帮助。
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import com.fiberlink.security.crypto.CryptoUtils;
public class DecryptDocsController {
static {
Security.addProvider(new BouncyCastleProvider());
}
public static final String PKCS7_PADDING = "AES/CBC/PKCS7Padding";
public static final int CHUNK_SIZE = 16;
public static final int STARTING_LOCATION = 0;
public static final int STREAM_FINISH_LOCATION = -1;
public void encryptFile() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IOException, IllegalBlockSizeException, BadPaddingException
{
FileInputStream fis = new FileInputStream(DECRYPTED_FILE_LOCATION_1);
FileOutputStream fos = new FileOutputStream(ENC_FILE_LOCATION_1);
Cipher cipher = Cipher.getInstance(PKCS7_PADDING);
SecretKeySpec skeySpec = new SecretKeySpec(getEcryptionByte(FILE_ENCRYPION_KEY), "AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
CipherInputStream inputStream = new CipherInputStream(fis, cipher);
int count =0;
byte[] data = new byte[CHUNK_SIZE];
while((count=(inputStream.read(data, STARTING_LOCATION, CHUNK_SIZE))) != STREAM_FINISH_LOCATION) {
fos.write(data, STARTING_LOCATION, count);
}
fis.close();
fos.close();
inputStream.close();
}
public void decryptFile() throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IOException, IllegalBlockSizeException, BadPaddingException
{
FileInputStream fis = new FileInputStream(ENC_FILE_LOCATION_2);
FileOutputStream fos = new FileOutputStream(DECRYPTED_FILE_LOCATION_2);
Cipher cipher = Cipher.getInstance(PKCS7_PADDING);
SecretKeySpec skeySpec = new SecretKeySpec(getEcryptionByte(FILE_ENCRYPION_KEY), "AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
CipherInputStream inputStream = new CipherInputStream(fis, cipher);
int count =0;
byte[] data = new byte[CHUNK_SIZE];
while((count=(inputStream.read(data, STARTING_LOCATION, CHUNK_SIZE))) != STREAM_FINISH_LOCATION) {
fos.write(data, STARTING_LOCATION, count);`enter code here`
}
fis.close();
fos.close();
inputStream.close();
}
}