TheAlchemist and Ragehottie asked me to create a zip cracker a while ago. I am sorry that it took so long, but I didn't forget your request. This program can actually crack other password protected archives too (i.e. rar).
This is a simple command line program by now. I commented the code so you can take it as example. The cracking is relatively slow, because I didn't use any threads. But I think this way it is more understandable for you.
I will add threads and a GUI later and make it a EZ release then. However, I attached the jar of this program too.
Don't forget to give credit if you use this code for your own programs.
Usage: java -jar archivecracker <archive> [<wordlist>]
wordlist is a file which contains passwords for a wordlist attack. If you don't give a wordlist, it will generate the words, but only a-z (you can change it, though).
Starting point of the program is the CLI.
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import net.sf.sevenzipjbinding.SevenZipException;
public class CLI {
private final static String USAGE = "usage: java -jar archivecracker <archive> [<wordlist>]";
private final static String VERSION = "ArchiveCracker v0.1 by Deque";
public static void main(String[] args) throws SevenZipException,
IOException {
System.out.println(VERSION);
System.out.println();
if (args.length == 0) {
System.out.println(USAGE);
} else {
char[] alphabet = WordlistGen.initAllowedCharacters('a', 'z');
ArchiveCracker cracker = new ArchiveCracker(alphabet);
String pass = crack(args, cracker);
printResult(cracker, pass);
}
}
private static void printResult(ArchiveCracker cracker, String pass) {
System.out.println();
if (pass != null) {
System.out.println("password found: " + pass);
System.out.println("words tried: " + cracker.getWordsTried());
} else {
System.out.println("no password found");
}
}
private static String crack(String[] args, ArchiveCracker cracker)
throws FileNotFoundException, SevenZipException, IOException {
String pass = null;
if (args.length == 1) {
if (new File(args[0]).exists()) {
pass = cracker.crack(args[0]);
} else {
System.err.println("file not found");
}
} else {
if (new File(args[0]).exists() && new File(args[1]).exists()) {
pass = cracker.crack(args[0], args[1]);
} else {
System.err.println("file not found");
}
}
return pass;
}
}
This class contains the main functionality, the ArchiveCracker.
Note that I had to use a little hack to get the functionality I wanted. The 7-Zip-JBinder library is not designed for checking passwords. It would actually try to extract the file if the password is correct, which I don't want. Because of that I throw a PasswordFoundException in the output stream instead of writing anything. This is not a good way, since exceptions are not there to define the program logic, but it is the only possible way with this library (and others too).
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.RandomAccessFile;
import net.sf.sevenzipjbinding.ISequentialOutStream;
import net.sf.sevenzipjbinding.ISevenZipInArchive;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.SevenZipException;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
import net.sf.sevenzipjbinding.simple.ISimpleInArchive;
import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem;
/**
*
* @author Deque
*
*/
public class ArchiveCracker {
private static final int MAX_WORDLENGTH = 6;
private static final int DOT_MARK = 100;
private final char[] alphabet;
private long words;
/**
* Prepares cracker with given alphabet.
* @param alphabet
*/
public ArchiveCracker(char[] alphabet) {
this.alphabet = alphabet;
}
/**
* Tries to crack the archive by generating words from the given alphabet.
*
* @param archivename
* @return password if found, null otherwise
* @throws FileNotFoundException
* @throws SevenZipException
*/
public String crack(String archivename) throws FileNotFoundException,
SevenZipException {
words = 0;
for (int wordlength = 0; wordlength <= MAX_WORDLENGTH; wordlength++) {
WordlistGen gen = new WordlistGen(alphabet, wordlength);
while (gen.hasNext()) {
String pass = gen.generateNext();
words++;
if (isValidPass(pass, archivename)) {
return pass;
}
if (words % DOT_MARK == 0) {
System.out.print(".");
}
}
}
return null;
}
/**
*
* @return number of passwords tried
*/
public long getWordsTried() {
return words;
}
/**
* Tries to crack the archive using the given wordlist.
*
* @param archivename
* @param wordlist
* @return password if found, null otherwise
* @throws SevenZipException
* @throws IOException
*/
public String crack(String archivename, String wordlist)
throws SevenZipException, IOException {
words = 0;
try (BufferedReader in = new BufferedReader(new FileReader(wordlist)) {
String pass;
while ((pass = in.readLine()) != null) { // read next line
words++; // count the passwords tried
if (isValidPass(pass, archivename)) { // validate password
return pass;
}
printDotIfMarkReached();
}
}
return null;
}
/**
* Prints a dot ever DOT_MARK words.
*/
private void printDotIfMarkReached() {
if (words % DOT_MARK == 0) {
System.out.println(".");
}
}
/**
* Checks wether the given password is the correct password of the archive.
*
* @param password
* @param filename
* @return true if password is valid, false otherwise
* @throws FileNotFoundException
* @throws SevenZipException
*/
private boolean isValidPass(String password, String filename)
throws FileNotFoundException, SevenZipException {
RandomAccessFile file = new RandomAccessFile(filename, "r");
// call with null to use autodetection of archive type
ISevenZipInArchive in = SevenZip.openInArchive(null,
new RandomAccessFileInStream(file));
ISimpleInArchive archiveInterface = in.getSimpleInterface();
ISequentialOutStream out = new ISequentialOutStream() {
@Override
public int write(byte[] data) throws SevenZipException {
// password was correct at this point
// throw exception to get back instead of extracting the archive
throw new PasswordFoundException();
}
};
try {
for (ISimpleInArchiveItem item : archiveInterface.getArchiveItems()) {
// try to open archive item with given password
// prepared out stream will throw PasswordFoundException instead
// of extracting the archive
item.extractSlow(out, password);
}
} catch (PasswordFoundException e) {
return true;
} finally {
close(file, in);
}
return false;
}
/**
* Closes the streams. Can't use try-with-resources statement here, because
* these Streams do not implement Closable.
*
* @param file
* @param in
*/
private void close(RandomAccessFile file, ISevenZipInArchive in) {
if (in != null) {
try {
in.close();
} catch (SevenZipException e) {
e.printStackTrace();
}
}
if (file != null) {
try {
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@SuppressWarnings("serial")
private class PasswordFoundException extends SevenZipException {}
}