[英]How to read an encrypted file which was encrypted using AES algorithm and decrypt it?
我試圖讀取普通的文本文件並使用AES算法對其進行加密,然后嘗試讀取該加密文件並對其進行解密。 加密工作正常。但是在解密時,出現錯誤消息“使用填充密碼解密時,輸入長度必須是16的倍數”。 我不知道我在做什么錯。任何建議都對我有幫助。 謝謝。
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class crypt {
public static void main(String args[]) throws Exception {
String keyString = "averylongtext!@$@#$#@$#&(&}{23432432432dsfsdf";
FileWriter fileWriter = null, fileWriter1 = null;
File enc = new File("C:\\test\\encrypted.txt");
File dec = new File("C:\\test\\decrypted.txt");
String path = "C:\\test\\normal_file.txt";
String path2 = "C:\\test\\encrypted.txt";
fileWriter = new FileWriter(enc);
fileWriter1 = new FileWriter(dec);
String input = readFile(path, StandardCharsets.UTF_8);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = new byte[cipher.getBlockSize()];
new SecureRandom().nextBytes(iv);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(keyString.getBytes());
byte[] key = new byte[16];
System.arraycopy(digest.digest(), 0, key, 0, key.length);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] encrypted = cipher.doFinal(input.getBytes());
System.out.println(new String(encrypted));
//writing encrypted information to a new file encrypted.txt
fileWriter.write(new String(encrypted));
fileWriter.close();
//reading encrypted information from the file encrypted.txt
//This part is where the error is
encrypted = readFile(path2, StandardCharsets.UTF_8).getBytes();
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] decrypted = cipher.doFinal(encrypted);
System.out.println("decrypted: \n" + new String(decrypted, "UTF-8"));
//writing the decrypted information to the file decrypted.txt
fileWriter1.write(new String(decrypted));
fileWriter1.close();
}
//method to read a file
static String readFile(String path, Charset encoding) throws IOException {
byte[] encoded = Files.readAllBytes(Paths.get(path));
return encoding.decode(ByteBuffer.wrap(encoded)).toString();
}
}
您的問題在這里:
fileWriter.write(new String(encrypted));
看起來您看過我關於讀取文件的文章,但是您尚未掌握字符編碼的概念。
好的密碼的輸出是不可預測的字節,范圍為0到255。
另一方面,文本包含字符。 為了在數字計算機中表示它們,每個字符字形分配了不同的數字。 由於不同的人使用不同的字符集,因此多年來已經創建了許多不同的編碼方案。 某些西方語言每個字符僅使用7位。 其他人使用8位,但是仍然沒有為每個8位代碼分配一個字符。 其他系統使用多個字節,但是僅某些字節序列表示有效字符。
我為什么要告訴你呢?
好吧,當您說new String(encrypted)
,您要獲取一堆偽隨機字節,並嘗試使用系統上的默認字符編碼將其轉換為字符。 通常,在這種編碼下,會有字節或字節序列無法轉換為字符。 這些字節將被替換為字符(U + FFFD,Unicode“替換字符”)。 這種替換會破壞密文; 不同的字節序列都用相同的符號替換。 當您嘗試解密時,此丟失的信息會導致錯誤的塊大小或填充錯誤。
密碼文字不是真正的文字。 不要將其轉換為String
,也不要將其作為文本寫入文件。 使用InputStream
, OutputStream
和byte[]
處理密文。 僅在加密之前和解密之后將信息視為文本。
您的密鑰派生也不安全。 閱讀如何使用PBKDF2從密碼安全地派生密鑰。
/* 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();
try (OutputStream fos = Files.newOutputStream(output, StandardOpenOption.CREATE_NEW);
CipherOutputStream os = new CipherOutputStream(fos, cipher);
InputStream is = Files.newInputStream(input)) {
byte[] buffer = new byte[4096];
while (true) {
int n = is.read(buffer);
if (n < 0)
break;
os.write(buffer, 0, n);
}
os.flush();
}
如果確實需要將密文轉換為String
,請使用Base-64或Base-85之類的編碼。 這些將允許您僅使用US-ASCII字符打印密文。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.