简体   繁体   English

如何在Java中AES256加密/解密PKCS#12存档文件?

[英]How to AES256 encrypt/decrypt a PKCS#12 archive file in Java?

My application needs to encrypt a PKCS#12 archive file which is already encrypted with the passphrase notasecret . 我的应用程序需要加密一个已经使用密码notasecret加密的PKCS#12存档文件 The file should be AES256 encrypted. 该文件应该是AES256加密的。

I tried using this solution for the encryption itself. 我尝试将这种解决方案用于加密本身。 My idea is to encrypt the string of characters read from file and writing that to a new file and then later decrypt it when I need it. 我的想法是对从文件读取的字符串进行加密,然后将其写入新文件,然后在需要时对其进行解密。

Right now I'm testing whether the string is encrypted and decrypted back correctly (whether the new file that is created is identical to the original). 现在,我正在测试字符串是否正确加密和解​​密(创建的新文件是否与原始文件相同)。 This is not the case. 不是这种情况。

Problem 问题

My code below is supposed to create an identical file by encrypting and decrypting a .p12 file, but the resulting file is bigger (original: 1.7KB, new: 2.5KB) and it's unreadable as a PKCS#12 archive. 我下面的代码应该通过加密和解密.p12文件来创建一个相同的文件,但是生成的文件更大(原始文件:1.7KB,新文件:2.5KB),不能作为PKCS#12存档读取。 The string length test in the middle displays identical lengths. 中间的字符串长度测试显示相同的长度。

Any clues? 有什么线索吗? Does it matter if the file is in one format or the other (PKCS#12 archive, binary, plaintext)? 文件是一种格式还是另一种格式(PKCS#12存档,二进制,明文)是否重要? The below code works great if the file to encrypt is in plaintext. 如果要加密的文件为纯文本格式,则以下代码非常有用。

Code

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.security.AlgorithmParameters;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class FileEncryptionTest {
  public static void main(String[] args) throws Exception {

    char[] password = "password".toCharArray();
    byte[] salt = new byte[8];

    /* Derive the key, given password and salt. */
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
    SecretKey tmp = factory.generateSecret(spec);
    SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

    /* Encrypt the message. */
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secret);
    AlgorithmParameters params = cipher.getParameters();
    byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();

    String file = "someprivatekey.p12";
    String keyFileText = readFile(file);

    byte[] ciphertext = cipher.doFinal(keyFileText.getBytes("UTF-8"));

    Cipher otherCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    otherCipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));

    String plaintext = new String(otherCipher.doFinal(ciphertext), "UTF-8");

    if (plaintext.equals(keyFileText))
      System.out.println("decrypted plaintext same as plaintext");
    System.out.println("plaintext length: " + plaintext.length() + " keyFileText length: " + keyFileText.length());

    writeFile(plaintext, "new-" + file);
  }

  private static void writeFile(String contents, String filePath) {
    PrintWriter out = null;
    try {
      out = new PrintWriter(new FileOutputStream(filePath));
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }
    out.write(contents);
    out.close();
  }

  private static String readFile(String filePath) {
    FileInputStream fis = null;
    int buf;
    StringBuilder contents = null;
    try {
      fis = new FileInputStream(filePath);
      contents = new StringBuilder();
      while ((buf = fis.read()) != -1) {
        contents.append((char) buf);
      }
      fis.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return contents.toString();
  }
}

You are treating a binary file as a String. 您正在将二进制文件视为字符串。 A binary file will contain many characters that cannot be treated as a character. 二进制文件将包含许多不能视为字符的字符。 Please rewrite your code and assume the PKCS#12 file is binary (using eg a FileInputStream / FileOutputStream combination or - for not such a big file - use readAllBytes instead of the input stream. 请重写您的代码,并假定PKCS#12文件是二进制文件(例如,使用FileInputStream / FileOutputStream组合,或者-对于不那么大的文件,请使用readAllBytes而不是输入流。

Thanks to @owlstead 's tip about using the data wrong, I managed to encrypt and decrypt the file correctly by treating the data as a byte[] , not a String . 感谢@owlstead提出的有关错误使用数据的提示,通过将数据视为byte[]而不是String ,我设法正确地加密和解密了文件。 These are the relevant changes: 这些是相关的更改:

private static void writeFile(byte[] contents, String filePath) {
  FileOutputStream out = null;
  try {
    out = new FileOutputStream(filePath);
    out.write(contents);
    out.close();
  } catch (Exception e) {
    e.printStackTrace();
  }
}

private static byte[] readFile(String filePath) {
  FileInputStream fis = null;
  File f = new File(filePath);
  int buf, i = 0;
  byte[] array = null;
  try {
    fis = new FileInputStream(f);
    array = new byte[(int) f.length()];
    while ((buf = fis.read()) != -1) {
      array[i++] = (byte) buf;
    }
    fis.close();
  } catch (Exception e) {
    e.printStackTrace();
  }
  return array;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM