我正在尝试编写一个简单的程序来加密和解密使用AES算法的文件。之后的意图是在更复杂的程序中使用将简单程序拆分为加密和解密方法。他是程序的加密部分:
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128);
SecretKey key = kg.generateKey();
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE, key);
FileInputStream fis; FileOutputStream fos; CipherOutputStream cos;
fis = new FileInputStream("FileTo.encrypt");
fos = new FileOutputStream("Encrypted.file");
//write encrypted to file
cos = new CipherOutputStream(fos, c);
byte[] b = new byte[16];
int i = fis.read(b);
while (i != -1) {
cos.write(b, 0, i);
i = fis.read(b);
}
cos.close();
//write key to file
byte[] keyEncoded = key.getEncoded();
FileOutputStream kos = new FileOutputStream("crypt.key");
kos.write(keyEncoded);
kos.close();
下面是解密部分:
//Load Key
FileInputStream fis2= new FileInputStream("a.key");
File f=new File("a.key");
long l=f.length();
byte[] b1=new byte[(int)l];
fis2.read(b1, 0, (int)l);
SecretKeySpec ks2=new SecretKeySpec(b1,"AES");
Cipher c1 = Cipher.getInstance("AES");
c1.init(Cipher.DECRYPT_MODE, ks2);
FileInputStream fis1=new FileInputStream("Encrypted.file");
CipherInputStream in= new CipherInputStream(fis1,c1);
FileOutputStream fos0 =new FileOutputStream("decrypted.file");
byte[] b3=new byte[1];
int ia=in.read(b3);
while (ia >=0)
{
c1.update(b3); //<-------remove this
fos0.write(b3, 0, ia);
ia=in.read(b3);
}
in.close();
fos0.flush();
fos0.close();
现在的问题是解密部分没有解密最后的比特,有些比特丢失了。在我看来,它只解密每16个字节,但(cipherinputstream)中的变量返回-1时,它应该返回最后一个字节。我怎么得到最后的比特?
Thanks in advance
编辑:添加注释,指出必须删除的内容。这里有一些代码可以使用AES在java中正确地加密和解密文件(即,无需在java中加载整个文件)。可以添加额外的参数(填充等),但这里是基本代码:
你只需要在你的代码中删除这一行,它就会正常工作:
c1.update(b3);
由于您使用的是CipherInputStream
,您不需要手动更新Cipher
。它会为你处理这个问题,通过调用它,你就干扰了解密。
另一方面,为了提高效率,您应该增加byte[] b
和byte[] b3
数组的大小。通常8192是缓冲的好大小。
下面是我找到的一些DES示例代码,可能会有所帮助…特别是对doFinal的调用。
package forums;
import java.io.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
/**
This program tests the DES cipher. Usage:
java DESTest -genkey keyfile
java DESTest -encrypt plaintext encrypted keyfile
java DESTest -decrypt encrypted decrypted keyfile
*/
public class DESTest
{
private static void usage() {
System.err.print(
"This program tests the javax.crypto DES cipher package.n"
+ "usage: java DESTest -genkey keyfilen"
+ "java DESTest -encrypt plaintext encrypted keyfilen"
+ "java DESTest -decrypt encrypted decrypted keyfilen"
);
}
public static void main(String[] args) {
if ( args.length < 2 || args.length > 4
|| !args[0].matches("-genkey|-encrypt|-decrypt")
) {
usage();
return;
}
try {
if ("-genkey".equals(args[0])) {
KeyGenerator keygen = KeyGenerator.getInstance("DES");
SecureRandom random = new SecureRandom();
keygen.init(random);
SecretKey key = keygen.generateKey();
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(args[1]));
out.writeObject(key);
out.close();
} else {
int mode;
if ("-encrypt".equals(args[0])) {
mode = Cipher.ENCRYPT_MODE;
} else { //-decrypt
mode = Cipher.DECRYPT_MODE;
}
ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(args[3]));
Key key = (Key) keyIn.readObject();
keyIn.close();
InputStream in = new FileInputStream(args[1]);
OutputStream out = new FileOutputStream(args[2]);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(mode, key);
crypt(in, out, cipher);
in.close();
out.close();
}
} catch (IOException exception) {
exception.printStackTrace();
} catch (GeneralSecurityException exception) {
exception.printStackTrace();
} catch (ClassNotFoundException exception) {
exception.printStackTrace();
}
}
/**
Uses a cipher to transform the bytes in an input stream
and sends the transformed bytes to an output stream.
@param in the input stream
@param out the output stream
@param cipher the cipher that transforms the bytes
*/
public static void crypt(InputStream in, OutputStream out, Cipher cipher)
throws IOException, GeneralSecurityException
{
int blockSize = cipher.getBlockSize();
int outputSize = cipher.getOutputSize(blockSize);
byte[] inBytes = new byte[blockSize];
byte[] outBytes = new byte[outputSize];
int inLength = 0;;
boolean more = true;
while (more) {
inLength = in.read(inBytes);
if (inLength == blockSize) {
int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
out.write(outBytes, 0, outLength);
System.out.println(outLength);
} else {
more = false;
}
}
if (inLength > 0) {
outBytes = cipher.doFinal(inBytes, 0, inLength);
} else {
outBytes = cipher.doFinal();
}
System.out.println(outBytes.length);
out.write(outBytes);
}
}
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AESTest {
public static String asHex (byte buf[]) {
StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10)
strbuf.append("0");
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
}
public static void main(String[] args) throws Exception {
String keyString = "ssssssssssssssss";
// 546578746F2070617261207465737465 (Hex)
byte[] key = keyString.getBytes();
System.out.println(asHex(key).toUpperCase());
String clearText = "sdhhgfffhamayaqqqaaaa";
// ZXNzYXNlbmhhZWhmcmFjYQ== (Base64)
// 6573736173656E686165686672616361 (Hex)
byte[] clear = clearText.getBytes();
System.out.println(asHex(clear).toUpperCase());
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
// PKCS5Padding or NoPadding
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
System.out.println(asHex(encrypted).toUpperCase());
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original =
cipher.doFinal(encrypted);
System.out.println(original);
String originalString = new String(original);
System.out.println("Original string: " +
originalString + " " + asHex(original));
}
}