java 使用 AES 加密和解密图像的正确方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26058823/
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
Correct way of Encrypting and Decrypting an Image using AES
提问by Vamsi Challa
EDIT ::: The code in the question works, but it takes around 10 seconds for getting back to the activity once the image is taken in camera. I gave up this approach and used Facebook's Conceal Library to encrypt and decrypt images. Link to Facebook's Solution : Facebook Conceal - Image Encryption and Decryption
编辑 ::: 问题中的代码有效,但是一旦在相机中拍摄图像,大约需要 10 秒才能返回活动。我放弃了这种方法,并使用 Facebook 的隐藏库来加密和解密图像。链接到 Facebook 的解决方案:Facebook Conceal - 图像加密和解密
I have looked at lot of examples, but still couldn't figure out a way to get Encryption and Decryption right. I thought i got it correct when I used some random code on the internet, but while decoding, i get a BadPadding Exception.
我看过很多例子,但仍然无法找到正确的加密和解密方法。当我在互联网上使用一些随机代码时,我认为我是正确的,但是在解码时,我得到了一个 BadPadding 异常。
So, i am trying to work it out. I am following the below question, as suggested by most people on SO (but this code shows how to encrypt a string). Can some one help me out in encrypting and decrypting the image? Will the code in the question work for images?
所以,我正在努力解决这个问题。我正在关注以下问题,正如大多数人所建议的那样(但此代码显示了如何加密字符串)。有人可以帮我加密和解密图像吗?问题中的代码适用于图像吗?
Link to the question : Java 256-bit AES Password-Based Encryption
问题链接:Java 256-bit AES Password-Based Encryption
Here is what i have done till now:
这是我到目前为止所做的:
//Global arraylist to store iv and cipher
//用于存储iv和密码的全局数组列表
static ArrayList<byte[]> ivandcipher = new ArrayList<byte[]>();
//Generating Key
//生成密钥
public static SecretKey generateKey() throws NoSuchAlgorithmException {
char[] password = { 'a', 'b', 'c', 'd', 'e' };
byte[] salt = { 1, 2, 3, 4, 5 };
SecretKeyFactory factory = SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = null;
try {
tmp = factory.generateSecret(spec);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
yourKey = new SecretKeySpec(tmp.getEncoded(), "AES");
return yourKey;
}
//Encoding File
//编码文件
//byte[] fileData, contains the bitmap(image) converted to byte[]
//byte[] fileData,包含转换为byte[]的位图(图像)
public static ArrayList<byte[]> encodeFile(SecretKey yourKey, byte[] fileData)
throws Exception {
byte[] encrypted = null;
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, yourKey);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
encrypted = cipher.doFinal(fileData);
ivandcipher.clear();
ivandcipher.add(iv);
ivandcipher.add(encrypted);
return ivandcipher;
}
Why am i adding iv and encrypted byte[]s to ivandcipher. Because, as the answer in the link suggests, that i should be using the same iv while decryption.
为什么我将 iv 和加密的 byte[]s 添加到 ivandcipher。因为,正如链接中的答案所暗示的那样,我应该在解密时使用相同的 iv。
//Decode file
//解码文件
//I call a overloaded decodeFile method inside this method.. please note
//我在这个方法中调用了一个重载的decodeFile方法..请注意
private Bitmap decodeFile(String filename) {
try {
yourKey = generateKey();
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
}
try {
byte[] decodedData = decodeFile(yourKey, readFile(filename));
Bitmap bitmap = bytesToBitmap(decodedData);
return bitmap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//overloaded decodeFile method
//重载的decodeFile方法
public static byte[] decodeFile(SecretKey yourKey, byte[] fileData)
throws Exception {
byte[] decrypted = null;
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, yourKey, new IvParameterSpec(ivandcipher.get(0)));
decrypted = cipher.doFinal(fileData);
return decrypted;
}
I guess the problem is with the fileData[], that i am not able to encrypt and decrypt correctly. For Strings as shown in the answer of the above link, i.e.,
我想问题出在 fileData[] 上,我无法正确加密和解密。对于上述链接的答案中所示的字符串,即,
byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes("UTF-8"));
byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes("UTF-8"));
what should be given as parameter for cipher.doFinal()?
应该给出什么作为 cipher.doFinal() 的参数?
Let me know if you need any other piece of code.
如果您需要任何其他代码,请告诉我。
采纳答案by Vamsi Challa
The code in the question works, but it takes around 10 seconds for getting back to the activity once the image is taken in camera. I gave up this approach and used Facebook's Conceal Library to encrypt and decrypt images. Link to Facebook's Solution : Facebook Conceal - Image Encryption and Decryption
问题中的代码有效,但是一旦在相机中拍摄图像,大约需要 10 秒才能返回活动。我放弃了这种方法,并使用 Facebook 的隐藏库来加密和解密图像。链接到 Facebook 的解决方案:Facebook Conceal - 图像加密和解密
回答by Khan Suhail Ahmad
Images can be easily encrypted and decrypted using Java libraries. I present to you two seperate codes using two different methods for encryption and decryption. The following codes can also be extended to use for pdf files.
可以使用 Java 库轻松加密和解密图像。我使用两种不同的加密和解密方法向您展示两个单独的代码。以下代码也可以扩展为用于 pdf 文件。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
public class ImageEncDec {
public static byte[] getFile() {
File f = new File("/home/bridgeit/Desktop/Olympics.jpg");
InputStream is = null;
try {
is = new FileInputStream(f);
} catch (FileNotFoundException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
byte[] content = null;
try {
content = new byte[is.available()];
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
is.read(content);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return content;
}
public static byte[] encryptPdfFile(Key key, byte[] content) {
Cipher cipher;
byte[] encrypted = null;
try {
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
encrypted = cipher.doFinal(content);
} catch (Exception e) {
e.printStackTrace();
}
return encrypted;
}
public static byte[] decryptPdfFile(Key key, byte[] textCryp) {
Cipher cipher;
byte[] decrypted = null;
try {
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
decrypted = cipher.doFinal(textCryp);
} catch (Exception e) {
e.printStackTrace();
}
return decrypted;
}
public static void saveFile(byte[] bytes) throws IOException {
FileOutputStream fos = new FileOutputStream("/home/bridgeit/Desktop/Olympics-new.jpg");
fos.write(bytes);
fos.close();
}
public static void main(String args[])
throws NoSuchAlgorithmException, InstantiationException, IllegalAccessException, IOException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
Key key = keyGenerator.generateKey();
System.out.println(key);
byte[] content = getFile();
System.out.println(content);
byte[] encrypted = encryptPdfFile(key, content);
System.out.println(encrypted);
byte[] decrypted = decryptPdfFile(key, encrypted);
System.out.println(decrypted);
saveFile(decrypted);
System.out.println("Done");
}
}
` this is the second code which generates the same output but with only the exception of generating the same key again and again.
` 这是第二个代码,它生成相同的输出,但只是一次又一次地生成相同的密钥。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class Trial {
public static byte[] getFile() {
File f = new File("/home/bridgeit/Desktop/Olympics.jpg");
InputStream is = null;
try {
is = new FileInputStream(f);
} catch (FileNotFoundException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
byte[] content = null;
try {
content = new byte[is.available()];
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
is.read(content);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return content;
}
public static byte[] encryptPdfFile(SecretKey secretKey, byte[] content) {
Cipher cipher;
byte[] encrypted = null;
try {
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
encrypted = Base64.encodeBase64(cipher.doFinal(content));
} catch (Exception e) {
System.out.println("Error while encrypting: " + e.toString());
}
return encrypted;
}
public static byte[] decryptPdfFile(SecretKey secretKey, byte[] textCryp) {
Cipher cipher;
byte[] decrypted = null;
try {
cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
decrypted = cipher.doFinal(Base64.decodeBase64(textCryp));
} catch (Exception e) {
System.out.println("Error while decrypting: " + e.toString());
}
return decrypted;
}
public static void saveFile(byte[] bytes) throws IOException {
FileOutputStream fos = new FileOutputStream("/home/bridgeit/Desktop/Olympics-new.jpg");
fos.write(bytes);
fos.close();
}
public static void main(String args[])
throws NoSuchAlgorithmException, InstantiationException, IllegalAccessException, IOException {
SecretKeySpec secretKey;
byte[] key;
String myKey = "ThisIsAStrongPasswordForEncryptionAndDecryption";
MessageDigest sha = null;
key = myKey.getBytes("UTF-8");
System.out.println(key.length);
sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit
System.out.println(key.length);
System.out.println(new String(key, "UTF-8"));
secretKey = new SecretKeySpec(key, "AES");
byte[] content = getFile();
System.out.println(content);
byte[] encrypted = encryptPdfFile(secretKey, content);
System.out.println(encrypted);
byte[] decrypted = decryptPdfFile(secretKey, encrypted);
System.out.println(decrypted);
saveFile(decrypted);
System.out.println("Done");
}
}
回答by rossum
You are trying to do too much at once, and are getting lost in all the details.
您试图一次做太多事情,并且迷失在所有细节中。
Start by simplifying your code to the bare minimum needed for encryption and decryption:
首先将您的代码简化为加密和解密所需的最低限度:
byte[] key = { 1, 2, 3, ... 14, 15, 16 };
byte[] IV = { 5, 5, 5, ... 5, 5, 5 };
String plaintext = "This is a secret message."
Now cut down your code to encrypt and decrypt that plaintext message back to a readable text string.
现在减少您的代码以将该明文消息加密和解密回可读的文本字符串。
When you have that small program working correctly, add back the other complications one at a time. At each stage, check again that your code can encrypt and decrypt successfully. I suggest that you start by adding back the SecretKeyFactory part, and finish with the file reading and writing part.
当您让那个小程序正常工作时,一次添加一个其他复杂功能。在每个阶段,再次检查您的代码是否可以成功加密和解密。建议你先把SecretKeyFactory部分加回来,再到文件读写部分结束。
By splitting your program up into smaller parts it will be easier for you to understand what each part of your program is doing, and make it easier for you to identify where you are making mistakes.
通过将您的程序分成更小的部分,您将更容易理解程序的每个部分在做什么,并让您更容易识别出哪里出错了。