我正在写某种生成加密日志文件的记录器。不幸的是,密码学不是我的强项。现在,我可以向文件写入几条消息,然后关闭文件。然后我可以打开它,附加一些消息,再次关闭,解密后,我在文件中间看到填充字节。有什么方法可以处理加密文件,而不必每次我想添加一些消息时都对其解密?
编辑 :更多细节。当前实现使用CipherOutputStream。据我了解,没有办法 寻求
使用它。如果我将控制输出数据大小可被块大小整除,是否可以使用“ NoPadding”选项?
如果您在CBC模式下使用AES
,则可以使用倒数第二个块作为IV来解密最后一个块(可能仅部分填充),然后再次加密最后一个块的明文,然后再加密新的明文。
这是概念证明:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AppendAES {
public static void appendAES(File file, byte[] data, byte[] key) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
RandomAccessFile rfile = new RandomAccessFile(file,"rw");
byte[] iv = new byte[16];
byte[] lastBlock = null;
if (rfile.length() % 16L != 0L) {
throw new IllegalArgumentException("Invalid file length (not a multiple of block size)");
} else if (rfile.length() == 16) {
throw new IllegalArgumentException("Invalid file length (need 2 blocks for iv and data)");
} else if (rfile.length() == 0L) {
// new file: start by appending an IV
new SecureRandom().nextBytes(iv);
rfile.write(iv);
// we have our iv, and there's no prior data to reencrypt
} else {
// file length is at least 2 blocks
rfile.seek(rfile.length()-32); // second to last block
rfile.read(iv); // get iv
byte[] lastBlockEnc = new byte[16];
// last block
// it's padded, so we'll decrypt it and
// save it for the beginning of our data
rfile.read(lastBlockEnc);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
lastBlock = cipher.doFinal(lastBlockEnc);
rfile.seek(rfile.length()-16);
// position ourselves to overwrite the last block
}
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
byte[] out;
if (lastBlock != null) { // lastBlock is null if we're starting a new file
out = cipher.update(lastBlock);
if (out != null) rfile.write(out);
}
out = cipher.doFinal(data);
rfile.write(out);
rfile.close();
}
public static void decryptAES(File file, OutputStream out, byte[] key) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
// nothing special here, decrypt as usual
FileInputStream fin = new FileInputStream(file);
byte[] iv = new byte[16];
if (fin.read(iv) < 16) {
throw new IllegalArgumentException("Invalid file length (needs a full block for iv)");
};
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
byte[] buff = new byte[1<<13]; //8kiB
while (true) {
int count = fin.read(buff);
if (count == buff.length) {
out.write(cipher.update(buff));
} else {
out.write(cipher.doFinal(buff,0,count));
break;
}
}
fin.close();
}
public static void main(String[] args) throws Exception {
byte[] key = new byte[]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
for (int i = 0; i<1000; i++) {
appendAES(new File("log.aes"),"All work and no play makes Jack a dull boy. ".getBytes("UTF-8"),key);
}
decryptAES(new File("log.aes"), new FileOutputStream("plain.txt"), key);
}
}
我想指出的是,输出与一次加密所有内容所产生的输出没有什么不同。这 不是 自定义的加密形式,而是标准的AES / CBC /
PKCS5Padding。唯一特定于实现的细节是,对于空白文件,我在开始数据之前已经编写了iv。
编辑:改进了(根据我的口味)使用的解决方案CipherOutputStream
:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AppendAES {
public static CipherOutputStream appendAES(File file, SecretKeySpec key) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
return appendAES(file, key, null);
}
public static CipherOutputStream appendAES(File file, SecretKeySpec key, SecureRandom sr) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
RandomAccessFile rfile = new RandomAccessFile(file,"rw");
byte[] iv = new byte[16];
byte[] lastBlock = null;
if (rfile.length() % 16L != 0L) {
throw new IllegalArgumentException("Invalid file length (not a multiple of block size)");
} else if (rfile.length() == 16) {
throw new IllegalArgumentException("Invalid file length (need 2 blocks for iv and data)");
} else if (rfile.length() == 0L) {
// new file: start by appending an IV
if (sr == null) sr = new SecureRandom();
sr.nextBytes(iv);
rfile.write(iv);
} else {
// file length is at least 2 blocks
rfile.seek(rfile.length()-32);
rfile.read(iv);
byte[] lastBlockEnc = new byte[16];
rfile.read(lastBlockEnc);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
lastBlock = cipher.doFinal(lastBlockEnc);
rfile.seek(rfile.length()-16);
}
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
byte[] out;
if (lastBlock != null) {
out = cipher.update(lastBlock);
if (out != null) rfile.write(out);
}
CipherOutputStream cos = new CipherOutputStream(new FileOutputStream(rfile.getFD()),cipher);
return cos;
}
public static CipherInputStream decryptAES(File file, SecretKeySpec key) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
FileInputStream fin = new FileInputStream(file);
byte[] iv = new byte[16];
if (fin.read(iv) < 16) {
throw new IllegalArgumentException("Invalid file length (needs a full block for iv)");
};
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
CipherInputStream cis = new CipherInputStream(fin,cipher);
return cis;
}
public static void main(String[] args) throws Exception {
byte[] keyBytes = new byte[]{
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
};
SecretKeySpec key = new SecretKeySpec(keyBytes,"AES");
for (int i = 0; i<100; i++) {
CipherOutputStream cos = appendAES(new File("log.aes"),key);
cos.write("All work and no play ".getBytes("UTF-8"));
cos.write("makes Jack a dull boy. \n".getBytes("UTF-8"));
cos.close();
}
CipherInputStream cis = decryptAES(new File("log.aes"), key);
BufferedReader bread = new BufferedReader(new InputStreamReader(cis,"UTF-8"));
System.out.println(bread.readLine());
cis.close();
}
}
我正在使用这样的代码来加密文件。 但是,尽管此代码成功加密。txt和。xml文件,它不适用于其他文件类型,例如。docx或图像文件格式。我可以对代码进行哪些更改以将功能扩展到所有此类文件类型?
我正在尝试构建一个程序,该程序接收一个文件(任意大小的EXE),对其进行加密并将其复制到一个结构中。然后稍后对其进行解密,并确保其与使用时相同。 我有一个艰难的时间加密,然后解密文件。它似乎没有正确加密,我不知道如何测试它。 以下是我的问题: 我在这里做错了什么? 是否有更好的库使用AES加密?或者我应该坚持openSSL 让我们说我想用另一个键说“你好世界”。我能不能用这个字符串作为加密算法的参
我试图在CBC模式下使用AES和Crypto++库加密(和解密)一个文件 以下是我已经做的: 为了加密文件,我以二进制模式打开它,并将内容转储为字符串: 当我将尝试解密此文件时,我如何分别提取iv和密文?IV是16字节长,但在这里我完全迷失了,我不知道如何做。
OpenSSL提供了一个流行的(但不安全-请参见下面!)AES加密的命令行界面: Python以PyCrypto包的形式支持AES,但它只提供了工具。如何使用Python/Pycrypto解密已经使用OpenSSL加密的文件? 这个问题过去也涉及使用相同方案在Python中进行加密。我已经删除了这部分,以阻止任何人使用它。不要再用这种方式加密任何数据,因为按照今天的标准,它是不安全的。您应该只使用
我试图解密AES-128加密的m3u8视频文件,例如: m3u8 文件 : 我尝试过使用openssl: 键.txt包含很长的键 - 我做错了什么?
我是加密新手。这个问题是我上一个问题的子问题。我有一个用OpenSSL util加密的文件: 我用这个代码来解密它: 而且很有效。但这是一个测试案例。实际情况是,我用以下参数对文件进行了加密: openssl aes-256-cbc-nosalt-in fileIn-out fileOUT-p-k KEY 请注意,出现了'-no盐'参数。问题是PBEKeySpec需要不为空,也不为空的和参数。它也