在Java中使用AES以CBC模式进行对称加密

时间:2018-12-05 07:43:26

标签: java aes cbc-mode

我正在尝试使用CBC模式加密和解密数据。 在这里,我首先从plaintext.txt文件中读取数据,然后将输出作为plaintext.txt的数据写入另一个ciphertext.txt文件。尝试解密时,我正在将文件中的加密数据读取为字节,但是由于某种原因,这给了我一个错误。有人可以帮我解决这个问题吗?

这是我的加密功能

  // The encryption Function CBC MODE

public static byte[] encrypt(String plainText, String key) throws Exception
{

    // Loading the secret key from the Key.txt file
    String fileName="../data/key.txt";
    try
    {
        BufferedReader in = new BufferedReader(new FileReader(fileName));         // Initialize a Buffer reader
        key = in.readLine();                                                     // Reading the data from txt file

    }
    //error message if the file is not found
    catch(FileNotFoundException ex)
    {
        System.out.println("Unable to open file '" + fileName + "'");
    }
    catch(IOException ex)
    {
        System.out.println("Error reading file '" + fileName + "'");
    }

    byte[] clean = plainText.getBytes();                                     //Getting the data in bytes from the plain text

    // Generating IV.
    //From the initialization vector, we create an IvParameterSpec which is required when creating the Cipher.
    int ivSize = 16;
    byte[] iv = new byte[ivSize];
    SecureRandom random = new SecureRandom();
    random.nextBytes(iv);
    IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
    //System.out.println("The Iv is = "+ivParameterSpec);


    // Hashing key.
    MessageDigest digest = MessageDigest.getInstance("SHA-256");
    digest.update(key.getBytes("UTF-8"));
    byte[] keyBytes = new byte[32];
    System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
    SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");


    // Encrypt.
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
    byte[] encrypted = cipher.doFinal(clean);


    // Combine IV and encrypted part.
    byte[] encryptedIVAndText = new byte[ivSize + encrypted.length];
    System.arraycopy(iv, 0, encryptedIVAndText, 0, ivSize);
    System.arraycopy(encrypted, 0, encryptedIVAndText, ivSize, encrypted.length);

    try
    {
       PrintWriter writer = new PrintWriter("../data/ciphertext.txt");
       writer.println(encryptedIVAndText);
       writer.close();
    }
    catch(Exception ex)
    {
        System.out.println(ex);
        System.out.println("File is not there");
    }

    return encryptedIVAndText;
}

这是我的解密功能。

// Decrypting fucntion CBC mode
public static String decrypt(byte[] encryptedIvTextBytes, String key) throws Exception
{

        FileInputStream encryptedTextFis = new FileInputStream("../data/ciphertext.txt");
    byte[] encText = new byte[encryptedTextFis.available()];
        int lol = encryptedTextFis.available();
        System.out.println("lol "+ lol);
    encryptedTextFis.read(encText);
    encryptedTextFis.close();
    //  encrypted = readFile("../data/ciphertext.txt", StandardCharsets.UTF_8).getBytes();
        encryptedIvTextBytes =  encText;
        //System.out.println("..........??????");
    String fileName="../data/key.txt";
    String fileName2="../data/ciphertext.txt";
    try
    {
        BufferedReader in = new BufferedReader(new FileReader(fileName));
        BufferedReader in2 = new BufferedReader(new FileReader(fileName2));
        key = in.readLine();
       // byte[] array = Files.readAllBytes(new File("/path/to/file").toPath());

    }
  //error message if the file is not found
    catch(FileNotFoundException ex)
    {
        System.out.println("Unable to open file '" + fileName + "'");
    }
    catch(IOException ex)
    {
        System.out.println("Error reading file '" + fileName + "'");
    }

    int ivSize = 16;
    int keySize = 32;
            //System.out.println("..........??????");
    // Extract IV.
    byte[] iv = new byte[ivSize];
    System.arraycopy(encryptedIvTextBytes, 0, iv, 0, iv.length);
    IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            System.out.println("..........??????");
    // Extract encrypted part.
    int encryptedSize = encryptedIvTextBytes.length - ivSize;
    byte[] encryptedBytes = new byte[encryptedSize];
    System.arraycopy(encryptedIvTextBytes, ivSize, encryptedBytes, 0, encryptedSize);
            System.out.println("..........??????");
    // Hash key.
    byte[] keyBytes = new byte[keySize];
    MessageDigest md = MessageDigest.getInstance("SHA-256");
    md.update(key.getBytes());
    System.arraycopy(md.digest(), 0, keyBytes, 0, keyBytes.length);
    SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");

    // Decrypt.
    Cipher cipherDecrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipherDecrypt.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);              //Decrypting the encrypted data to a cipherblock data
    byte[] decrypted = cipherDecrypt.doFinal(encryptedBytes);                            // Decrypting the cipher dadat to Plaintext

    //Writing the output to a txt file
    try
    {
       PrintWriter writer = new PrintWriter("../data/result.txt");
       writer.println(new String(decrypted));
       writer.close();
    }
    catch(Exception ex)
    {
        System.out.println(ex);
        System.out.println("File is not there");
    }

    return new String(decrypted);                   //Returning the decrypted data to main function
}

加密文本文件的输出格式为[B @ 3159c4b8]。 我收到以下错误。 enter image description here

2 个答案:

答案 0 :(得分:0)

似乎例外:

System.arraycopy(encryptedIvTextBytes, 0, iv, 0, iv.length);

数组encryptedIvTextBytes的长度为11(如您所说,结果也显示)。现在,您要从encryptedIvTextBytes复制16个字节(作为iv的长度)。

但是主要是由于此注释,您用于保存加密数据的保存方法无效。加密的数据可能包含一些不是可读字符的字节。当您将加密数据另存为字符串时,将丢弃这些字节。要解决此问题,请参阅@Maarten和@ MS90注释。

答案 1 :(得分:0)

以下是适合您需求的代码:

/**
 * @param args the command line arguments
 */
public static void main(String[] args) throws Exception {
    String key = "abcdefghijklmop";// you could store it somewhere ...
    justToMakePlainTextFile();
    byte[] encrypted = encrypt("plaintext",key);
    decrypt(encrypted, key);

}


public static void justToMakePlainTextFile() {
    try {
        RandomAccessFile randomAccessFile = new RandomAccessFile("plaintext", "rw");
        FileChannel fileChannel = randomAccessFile.getChannel();
        String randomText = "Ho-ho-ho-ho! This is going to be a nice weekend and I am going to swim soon.";
        byte[] bytes = randomText.getBytes();
        ByteBuffer byteBuffer = ByteBuffer.allocate(randomText.length());//alocate new ByteBuffer of size randomeText.length
        byteBuffer.put(bytes);
        byteBuffer.flip();
        fileChannel.write(byteBuffer);
        randomAccessFile.close();
        fileChannel.close();

    } catch (IOException ioE) {
        System.err.println("JVM reported an error! Take a look: " + ioE);
    }
}


public static byte[] encrypt(String file, String key) throws Exception {

    RandomAccessFile reader = new RandomAccessFile(file, "r");
    FileChannel channel = reader.getChannel();

    int bufferSize = 1024;
    if (bufferSize > channel.size()) {
        bufferSize = (int) channel.size();
    }
    ByteBuffer buff = ByteBuffer.allocate(bufferSize);
    channel.read(buff);
    buff.flip();
    byte[] clean = buff.array();
    channel.close();
    reader.close();

    // Generating IV.
    int ivSize = 16;
    byte[] iv = new byte[ivSize];
    SecureRandom random = new SecureRandom();
    random.nextBytes(iv);
    IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

    // Hashing key.
    MessageDigest digest = MessageDigest.getInstance("SHA-256");
    digest.update(key.getBytes("UTF-8"));
    byte[] keyBytes = new byte[16];
    System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
    SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");

    // Encrypt.
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
    byte[] encrypted = cipher.doFinal(clean);

    // Combine IV and encrypted part.
    byte[] encryptedIVAndText = new byte[ivSize + encrypted.length];
    System.arraycopy(iv, 0, encryptedIVAndText, 0, ivSize);
    System.arraycopy(encrypted, 0, encryptedIVAndText, ivSize, encrypted.length);

    return encryptedIVAndText;
}

public static void decrypt(byte[] encryptedIvTextBytes, String key) throws Exception {
    int ivSize = 16;
    int keySize = 16;

    // Extract IV.
    byte[] iv = new byte[ivSize];
    System.arraycopy(encryptedIvTextBytes, 0, iv, 0, iv.length);
    IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

    // Extract encrypted part.
    int encryptedSize = encryptedIvTextBytes.length - ivSize;
    byte[] encryptedBytes = new byte[encryptedSize];
    System.arraycopy(encryptedIvTextBytes, ivSize, encryptedBytes, 0, encryptedSize);

    // Hash key.
    byte[] keyBytes = new byte[keySize];
    MessageDigest md = MessageDigest.getInstance("SHA-256");
    md.update(key.getBytes());
    System.arraycopy(md.digest(), 0, keyBytes, 0, keyBytes.length);
    SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");

    // Decrypt.
    Cipher cipherDecrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipherDecrypt.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
    byte[] decrypted = cipherDecrypt.doFinal(encryptedBytes);

      try {
        RandomAccessFile randomAccessFile = new RandomAccessFile("ciphertext", "rw");
        FileChannel fileChannel = randomAccessFile.getChannel();
        byte[] bytes = decrypted;
        ByteBuffer byteBuffer = ByteBuffer.allocate(decrypted.length);//alocate new ByteBuffer of size randomeText.length
        byteBuffer.put(bytes);
        byteBuffer.flip();
        fileChannel.write(byteBuffer);
        randomAccessFile.close();
        fileChannel.close();

    } catch (IOException ioE) {
        System.err.println("JVM reported an error! Take a look: " + ioE);
    }

}

密文和纯文本文件在您的项目主文件夹中创建。