This repository has been archived on 2022-08-01. You can view files and clone it, but cannot push or open issues or pull requests.
PcapCrack/src/Cracker.java

253 lines
10 KiB
Java
Executable File

/*
* PcapCrack 1.0
* Copyright © 2017 Ben Goldsworthy (rumperuu)
*
* A program to attempt to brute-force the key used to encrypt a file
* in an intercepted network packet.
*
* This file is part of PcapCrack.
*
* PcapCrack is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PcapCrack is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PcapCrack. If not, see <http://www.gnu.org/licenses/>.
*/
/**
** This class represents a password-cracking thread utilising a given
** method for generating possible passwords.
**/
import java.io.*;
import java.net.*;
import java.security.*;
import java.util.*;
import java.util.regex.*;
import javax.crypto.*;
import javax.crypto.spec.*;
/**
** @author Ben Goldsworthy (rumperuu) <me+pcapcrack@bengoldsworthy.net>
** @version 1.0
**/
public class Cracker implements Runnable {
private static final String ivVal = "1234567891011121";
private static final char[] leet = {'a', '4', 'e', '3', 'i', '1', 'o', '0', 'l', '|', 't' , '7'};
private static byte[] file;
private static boolean found = false;
private ArrayList<String> passwords;
private int mode;
MessageDigest digest;
Cipher cipher;
IvParameterSpec iv;
/**
** Constructor.
**
** @param mode The method of password generation the thread will
** utilise.
** @param file The encoded file to crack, encoded in Base64.
** @param dict The `ArrayList` of words from the chosen dictionary.
**/
public Cracker(int mode, String file, ArrayList<String> dict){
this.mode = mode;
this.file = Base64.getDecoder().decode(file);
// Initialises the dictionary to the passed file for all modes except
// 0...
if (this.mode > 2) {
this.passwords = dict;
// ...in which case, initialises the dictionary to the list of the
// 10,000 most common passwords included with the .jar.
} else {
ArrayList<String> commonPasswords = new ArrayList<String>();
try {
InputStream is = getClass().getResourceAsStream("/dat/10000-most-common-passwords.txt");
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) { commonPasswords.add(line); }
this.passwords = commonPasswords;
} catch (FileNotFoundException e) {
System.out.println("File `10000-most-common-passwords.txt` not found in directory `.\\dat`.");
System.exit(1);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
// If the cracker has an even mode, flips the order the password
// list.
if ((this.mode % 2)== 0) Collections.reverse(this.passwords);
// Halves the cracker's list, to avoid duplicating effort with its
// even twin.
this.passwords = new ArrayList<String>(this.passwords.subList(0, this.passwords.size()/2));
// Initialises as much of the crypto stuff as can be done at this
// stage.
try {
this.digest = MessageDigest.getInstance("SHA-256");
this.cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
this.iv = new IvParameterSpec(this.ivVal.getBytes());
} catch (Exception e) {
System.out.println(e);
}
}
/**
** Runs the cracker process on the thread, and alerts on end.
**/
@Override
public void run() {
processCommand();
}
/**
** Tests every key generated using the given method for the thread.
**
** Mode 1: 10,000 most common passwords.
** Mode 3: Dictionary words.
** Mode 5: Dictionary words, with each letter capitalised in turn.
** Mode 7: Dictionary words, with ASCII symbols {!-/} appended.
** Mode 9: Dictionary words, with 'leetspeek' replacements.
** Mode 11: Dictionary words, capitalised.
** Mode 13: Dictionary words, with numbers {0-9999} appended
** and prepended.
** Mode 15: Dictionary words, combined in pairs.
** Mode 17: Numbers {0-1,000,000}.
**
** Even-numbered modes are the previous mode, with a reversed
** list. Thus, all modes terminate when halfway through.
**/
private void processCommand() {
int j, k;
int tenth = (int)Math.ceil(this.passwords.size()/10);
int current = 0;
int percentage = 0;
// DEBUG: when using the test dictionary, avoids divide be zero
// exceptions later on.
if (this.passwords.size() < 10) tenth = 1;
for (String password : this.passwords) {
// If another cracker has found the correct password, stop.
if (this.found) return;
current++;
switch (this.mode) {
// Tests the unaltered dictionary word/common password.
case 1:case 2:case 3:case 4:
this.crack(password);
break;
// Capitalises each letter of each word in turn.
case 5:case 6:
for (j = 1; j < password.length() - 1; j++) {
password = password.substring(0,j) + password.substring(j,j+1).toUpperCase() + password.substring(j+1);
this.crack(password);
}
break;
// Appends the symbols represented by ASCII values 33-47.
case 7:case 8:
for (j = 33; j < 48; j++) {
password = password + (char)j;
this.crack(password);
}
break;
// Replaces each leet character in turn.
case 9:case 10:
for (j = 0; j < password.length() - 1; j++) {
for (k = 0; k < this.leet.length; k+=2) {
if (password.charAt(j) == this.leet[k]) {
StringBuilder newPassword = new StringBuilder(password);
newPassword.setCharAt(j, this.leet[k+1]);
this.crack(newPassword.toString());
}
}
}
break;
// Capitalises the first letter of every word.
case 11:case 12:
password = password.substring(0,1).toUpperCase() + password.substring(1);
this.crack(password);
break;
// Appends and prepends the numbers 1-9,999 to every word.
case 13:case 14:
for (j = 0; j < 9999 - 1; j++) {
this.crack(password + j);
this.crack(j + password);
}
break;
// Appends and prepends the next word.
case 15:case 16:
for (j = 0; j < this.passwords.size() - 1; j++) {
this.crack(password + this.passwords.get(j));
}
break;
// Attempts the numbers 0-1,000,000.
case 17:case 18:
for (j = k = 0; (j <= 500000) && (k >= 500000); j++, k--) {
this.crack(""+j);
this.crack(""+k);
}
break;
}
// Displays the current progress.
if ((current % tenth) == 0) {
tenth += tenth;
percentage += 10;
System.out.println("Cracker "+mode+" at "+percentage+"%");
}
}
// If there's been no return, none of the attempted passwords have
// worked.
System.out.println("Cracker " + this.mode + " end, no result.");
}
/**
** Tests a given password to see if it cracks the payload.
**
** @param password The given password.
** @return Whether the file was cracked or not.
**/
private boolean crack(String password) {
try {
// Sets up the cipher with the given password.
byte[] keyVal = digest.digest(password.getBytes("UTF-8"));
keyVal = Arrays.copyOfRange(keyVal, 0, keyVal.length/2);
SecretKeySpec key = new SecretKeySpec(keyVal, "AES");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
// Decrypts the file using the cipher.
String decryptedFile = new String(cipher.doFinal(this.file));
if (decryptedFile.startsWith("DECRYPTED:")) {
// Must be outputted in a single command, or lines will be
// broken up by output from other cracker threads.
System.out.println("Cracker "+this.mode+" end, successful crack!\n==========\nDecrypted file: " + decryptedFile.split(":",2)[1] + "\nPassword: " + password + "\n==========\n");
this.found = true;
return true;
}
} catch (BadPaddingException e) {
// If the password is incorrect, do nothing and move on to
// returning "false".
} catch (Exception e) {
System.out.println(e);
} finally {
return false;
}
}
}