我正在用eclipse上的Java语言编写一个程序,该程序使用AES算法查找消息的解密密钥,该算法由16位数字组成,该数字由0到MAX_VALUE组成,其余数字均为0。稍后我提出了代码。
private String name;
private int in;
private int end;
private final String FORMAT = String.format("%%0%dd", 16);
private final String KEYWORD = "come";
public Soldier(String name, int in, int end) {
super(name);
this.name = name;
this.in = in;
this.end = end;
}
private boolean found(File f) {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
String line = null;
line = br.readLine();
while(line!=null) {
if(line.contains(KEYWORD)) {
br.close();
return true;
}
line = br.readLine();
}
br.close();
return false;
} catch(Exception e) {
return false;
}
}
public void run() {
File encryptedFile = new File("document.encrypted");
File decryptedFile = new File(nome+".decrypted");
for(int i=in;i<end;i++) {
if(this.isInterrupted())
break;
String key = String.format(FORMAT, i);
try {
CryptoUtils.decrypt(key, encryptedFile, decryptedFile);
try {
if(found(decryptedFile)) {
System.out.println("Key found: "+ key + " Thread: "+name);
this.interrupt();
break;
}
} catch(NumberFormatException e) {
e.printStackTrace();
}
} catch(Exception ex) {
System.out.println("Tested key: "+ key + "Thread n: "+ name);
continue;
}
}
}
这是包含run方法的类。
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES";
public static void encrypt(String key, File inputFile, File outputFile) throws CryptoException {
doCrypto(Cipher.ENCRYPT_MODE, key, inputFile, outputFile);
}
public static void decrypt(String key, File inputFile, File outputFile) throws CryptoException {
doCrypto(Cipher.DECRYPT_MODE, key, inputFile, outputFile);
}
private static void doCrypto(int cipherMode, String key, File inputFile, File outputFile) throws CryptoException {
try {
Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(cipherMode, secretKey);
try (CipherOutputStream out = new CipherOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile)), cipher)) {
Files.copy(inputFile.toPath(), out);
}
} catch(Exception ex) {
throw new CryptoException("Error encrypting/decrypting file", ex);
}
}
这是解密类。
private static final long serialVersionUID = 2850972529362612601L;
public CryptoException(String message, Throwable throwable) {
super(message, throwable);
}
这是在解密中出现错误时引发的异常。但是,可以通过在屏幕上打印测试的键号来管理此异常,如运行方法所示。然后显示错误的堆栈跟踪。
decrittazione.CryptoException: Error encrypting/decrypting file
at decrittazione.CryptoUtils.doCrypto(CryptoUtils.java:42)
at decrittazione.CryptoUtils.decrypt(CryptoUtils.java:23)
at decrittazione.Soldier.run(Soldato.java:50)
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at java.base/com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975)
at java.base/com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1056)
at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)
at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2208)
at decrittazione.CryptoUtils.doCrypto(CryptoUtils.java:36)
... 2 more
Soldier s1 = new Soldier("1", 0, /*endNumber*/);
Soldier s2 = new Soldier("2", /*inNumber*/, /*endNumber*/);
Soldier s3 = new Soldier("3", /*inNumber*/, /*endNumber*/);
Soldier s4 = new Soldier("4", /*inNumber*/, /*endNumber*/);
Soldier s5 = new Soldier("5", /*inNumber*/, /*endNumber*/);
Soldier s6 = new Soldier("6", /*inNumber*/, /*endNumber*/);
Soldier s7 = new Soldier("7", /*inNumber*/, /*endNumber*/);
Soldier s8 = new Soldier("8", /*inNumber*/, /*endNumber*/);
Soldier s9 = new Soldier("9", /*inNumber*/, /*endNumber*/);
Soldier s10 = new Soldier("10", /*inNumber*/, /*endNumber*/);
Soldier s11 = new Soldier("11", /*inNumber*/, /*endNumber*/);
Soldier s12 = new Soldier("12", /*inNumber*/, /*endNumber*/);
Soldier s13 = new Soldier("13", /*inNumber*/, /*endNumber*/);
Soldier s14 = new Soldier("14", /*inNumber*/, /*endNumber*/);
Soldier s15 = new Soldier("15", /*inNumber*/, 2147483647);
s1.start();
s2.start();
s3.start();
s4.start();
s5.start();
s6.start();
s7.start();
s8.start();
s9.start();
s10.start();
s11.start();
s12.start();
s13.start();
s14.start();
s15.start();
while(true) {
if(s1.isInterrupted() || s2.isInterrupted() || s3.isInterrupted() || s4.isInterrupted() || s5.isInterrupted() || s6.isInterrupted() || s7.isInterrupted() || s8.isInterrupted() || s9.isInterrupted() || s10.isInterrupted() || s11.isInterrupted() || s12.isInterrupted() || s13.isInterrupted() || s14.isInterrupted() || s15.isInterrupted()) {
s1.interrupt();
s2.interrupt();
s3.interrupt();
s4.interrupt();
s5.interrupt();
s6.interrupt();
s7.interrupt();
s8.interrupt();
s9.interrupt();
s10.interrupt();
s11.interrupt();
s12.interrupt();
s13.interrupt();
s14.interrupt();
s15.interrupt();
break;
}
}
}
最后,这是主要方法。
此代码使用我选择的密钥和我在Windows上选择的消息执行测试,没有问题。通过始终在Eclipse(相同版本,相同的JDK等)上切换到MacOS来代替,当需要测试密钥时,程序将无法解密消息并继续后续的密钥,直到没有穷尽它们,因此就没有期望的结果。
如果我不能很好地解释自己,我表示歉意,但我不知道该如何解释。我很抱歉,即使它不是世界上最好的代码,但我还是一个初学者。
最佳答案
我不确定是什么引起了您的问题,但我知道不能保证inputStream.read(inputBytes);
填充inputBytes数组。这就是为什么该方法返回一个计数来告诉您实际读取了多少字节的原因。
如果使用Java 9或更高版本,最好使用inputBytes = inputStream.readAllBytes();
。
如果文件很大,则将全部内容读入内存将损害性能。大于2 GB的文件根本无法放入字节数组。
解决方案是使用CipherOutputStream:
Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(cipherMode, secretKey);
try (CipherOutputStream out = new CipherOutputStream(
new BufferedOutputStream(
new FileOutputStream(outputFile)), cipher)) {
Files.copy(inputFile.toPath(), out);
}