【问题标题】:Correct way of Encrypting and Decrypting an Image using AES使用 AES 加密和解密图像的正确方法
【发布时间】:2014-11-21 10:06:45
【问题描述】:

编辑 ::: 问题中的代码有效,但是一旦在相机中拍摄图像,返回活动大约需要 10 秒。我放弃了这种方法,使用 Facebook 的 Conceal Library 来加密和解密图像。链接到 Facebook 的解决方案:Facebook Conceal - Image Encryption and Decryption


我查看了很多示例,但仍然无法找到正确加密和解​​密的方法。当我在互联网上使用一些随机代码时,我认为我得到了正确的结果,但是在解码时,我得到了一个 BadPadding 异常。

所以,我正在努力解决它。正如大多数人在 SO 上所建议的那样,我正在关注以下问题(但此代码显示了如何加密字符串)。有人可以帮我加密和解密图像吗?问题中的代码是否适用于图片?

问题链接:Java 256-bit AES Password-Based Encryption

这是我到目前为止所做的:

//全局arraylist存储iv和cipher

static ArrayList<byte[]> ivandcipher = new ArrayList<byte[]>();

//生成密钥

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;
}

//编码文件

//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;
}

为什么我要在 ivandcipher 中添加 iv 和加密的字节 []。因为,正如链接中的答案所暗示的那样,我在解密时应该使用相同的 iv。

//解码文件

//我在这个方法里面调用了一个重载的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;
}

//重载的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;
}

我猜问题出在 fileData[] 上,我无法正确加密和解​​密。对于上面链接的答案中所示的字符串,即

byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes("UTF-8"));

cipher.doFinal() 的参数应该是什么?

如果您需要任何其他代码,请告诉我。

【问题讨论】:

  • 原因基本上是你复制了“互联网上的一些随机代码”,没有让它工作,现在我们应该修复它。
  • @ntoskrnl,我没有要求任何人修复它。我要求您帮助理解它并使其发挥作用。顺便说一句,我在问题中发布的代码不是随机的,它来自我在问题中发布的链接。
  • 您的代码应该可以工作。可能是 readFile(filename) 中的问题。它会返回任何东西吗?你如何保存到文件/从文件中读取?

标签: java android encryption cryptography


【解决方案1】:

可以使用 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");

    }

}

` 这是第二个生成相同输出的代码,但只是一次又一次生成相同的密钥。

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");

    }

}

【讨论】:

  • 嘿哇,糟糕的流处理,文件的完全缓冲,ECB 模式加密,PasswordBasedEncryption 的单一密码哈希。加密意义为零。 Find the penguin。而这一切都是从正确的原语开始的,例如 PBKDF2 和 CBC 模式。和 5 票。哇。哇。
【解决方案2】:

你试图一次做太多事情,而迷失在所有细节中。

首先将您的代码简化为加密和解密所需的最低限度:

byte[] key = { 1, 2, 3, ... 14, 15, 16 };
byte[] IV  = { 5, 5, 5, ... 5, 5, 5 };
String plaintext = "This is a secret message."

现在减少您的代码,将明文消息加密和解密为可读的文本字符串。

当您的小程序正常运行时,一次添加其他复杂性。在每个阶段,再次检查您的代码是否可以成功加密和解密。建议你先加回SecretKeyFactory部分,最后是文件读写部分。

通过将程序拆分成更小的部分,您可以更轻松地了解程序的每个部分在做什么,并让您更轻松地找出错误所在。

【讨论】:

    【解决方案3】:

    问题中的代码有效,但在相机拍摄图像后,大约需要 10 秒才能恢复活动。我放弃了这种方法,使用 Facebook 的 Conceal Library 来加密和解密图像。链接到 Facebook 的解决方案:Facebook Conceal - Image Encryption and Decryption

    【讨论】:

    • 我相信你的问题是你试图在 UI 线程中加密和解密,这可能解释了 10 秒的延迟。
    猜你喜欢
    • 1970-01-01
    • 2019-04-07
    • 2011-10-12
    • 1970-01-01
    • 2021-05-16
    • 1970-01-01
    • 2011-10-08
    • 2020-04-30
    • 1970-01-01
    相关资源
    最近更新 更多