java 图像文件的加密和解密
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12136558/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Encryption and decryption of image file
提问by Twister
In conjunction from my another question, and after changing this small part of the codes
结合我的另一个问题,在更改了一小部分代码之后
FileOutputStream output = new FileOutputStream("sheepTest.png");
CipherOutputStream cos = new CipherOutputStream(output, pbeCipher);
ImageIO.write(input, "PNG", cos);
cos.close();
from the decrypt part, I've faced another error which is this
从解密部分,我遇到了另一个错误,就是这个
Exception in thread "main" java.lang.IllegalArgumentException: image == null!
at javax.imageio.ImageTypeSpecifier.createFromRenderedImage(Unknown Source)
at javax.imageio.ImageIO.getWriter(Unknown Source)
at javax.imageio.ImageIO.write(Unknown Source)
at encypt.com.trial.main(trial.java:82)
and when i click the sheepTest.png, the file is empty. Where is the mistake(s)? Can anyone help me to solve the error? Thank you.
当我点击sheepTest.png 时,文件是空的。错误在哪里?谁能帮我解决这个错误?谢谢你。
public class trial {
public static void main(String[] arg) throws Exception {
// Scanner to read the user's password. The Java cryptography
// architecture points out that strong passwords in strings is a
// bad idea, but we'll let it go for this assignment.
Scanner scanner = new Scanner(System.in);
// Arbitrary salt data, used to make guessing attacks against the
// password more difficult to pull off.
byte[] salt = { (byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c,
(byte) 0x7e, (byte) 0xc8, (byte) 0xee, (byte) 0x99 };
{
File inputFile = new File("sheep.png");
BufferedImage input = ImageIO.read(inputFile);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
// Get a password from the user.
System.out.print("Password: ");
System.out.flush();
PBEKeySpec pbeKeySpec = new PBEKeySpec(scanner.nextLine().toCharArray());
// Set up other parameters to be used by the password-based
// encryption.
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 20);
SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
// Make a PBE Cyhper object and initialize it to encrypt using
// the given password.
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);
FileOutputStream output = new FileOutputStream("sheepTest.png");
CipherOutputStream cos = new CipherOutputStream(
output, pbeCipher);
//File outputFile = new File("image.png");
ImageIO.write(input,"PNG",cos);
cos.close();
}
// Now, create a Cipher object to decrypt for us. We are repeating
// some of the same code here to illustrate how java applications on
// two different hosts could set up compatible encryption/decryption
// mechanisms.
{
File inputFile = new File("sheepTest.png");
BufferedImage input = ImageIO.read(inputFile);
// Get another (hopefully the same) password from the user.
System.out.print("Decryption Password: ");
System.out.flush();
PBEKeySpec pbeKeySpec = new PBEKeySpec(scanner.next().toCharArray());
// Set up other parameters to be used by the password-based
// encryption.
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 20);
SecretKeyFactory keyFac = SecretKeyFactory
.getInstance("PBEWithMD5AndDES");
SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
// Make a PBE Cyper object and initialize it to decrypt using
// the given password.
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec);
// Decrypt the ciphertext and then print it out.
/*byte[] cleartext = pbeCipher.doFinal(ciphertext);
System.out.println(new String(cleartext));*/
FileOutputStream output = new FileOutputStream("sheepTest.png");
CipherOutputStream cos = new CipherOutputStream(
output, pbeCipher);
ImageIO.write(input,"PNG", cos);
cos.close();
}
}
}
回答by MadProgrammer
Further to NateCK's insightful post (well done by the way), I've modified your decrypt section
除了 NateCK 有见地的帖子(顺便说一句做得好),我修改了你的解密部分
// Note that we are not reading the image in here...
System.out.print("Decryption Password: ");
System.out.flush();
PBEKeySpec pbeKeySpec = new PBEKeySpec(scanner.next().toCharArray());
// Set up other parameters to be used by the password-based
// encryption.
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 20);
SecretKeyFactory keyFac = SecretKeyFactory
.getInstance("PBEWithMD5AndDES");
SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
// Make a PBE Cyper object and initialize it to decrypt using
// the given password.
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec);
// We're now going to read the image in, using the cipher
// input stream, which wraps a file input stream
File inputFile = new File("sheepTest.png");
FileInputStream fis = new FileInputStream(inputFile);
CipherInputStream cis = new CipherInputStream(fis, pbeCipher);
// We then use all that to read the image
BufferedImage input = ImageIO.read(cis);
cis.close();
// We then write the dcrypted image out...
// Decrypt the ciphertext and then print it out.
FileOutputStream output = new FileOutputStream("sheepTest.png");
ImageIO.write(input, "PNG", output);
My example is based on NateCKs findings. If you find it useful, an upvote would be nice, but NateCK deserves the credit ;)
我的例子是基于 NateCKs 的发现。如果你觉得它有用,点个赞就好了,但 NateCK 值得称赞 ;)
回答by Nate C-K
I'd guess that this line is returning null:
我猜这一行返回空值:
BufferedImage input = ImageIO.read(inputFile);
The documentation for ImageIO.read
says:
的文档ImageIO.read
说:
"If no registered ImageReader claims to be able to read the resulting stream, null is returned."
“如果没有注册的 ImageReader 声称能够读取结果流,则返回 null。”
That null is passed on to this call, which results in the NPE:
这个空值被传递给这个调用,这导致了 NPE:
ImageIO.write(input,"PNG", cos);
I'm not familiar with this API, but from the documentation and what I see here, I think I can infer that the reason ImageIO.read
is returning null is because it's trying to interpret the image data in the file, but it can't because it's encrypted. You need to decrypt the data first before you can interpret it as an image.
我不熟悉这个 API,但是从文档和我在这里看到的,我想我可以推断ImageIO.read
返回 null的原因是因为它试图解释文件中的图像数据,但它不能,因为它是加密。您需要先解密数据,然后才能将其解释为图像。
You are doing the decryption, but your format conversion is using the original, encrypted file as its input, not the decrypted image data.
您正在进行解密,但您的格式转换使用原始的加密文件作为其输入,而不是解密的图像数据。