0

我正在制作密码破解程序(韦伯斯特词典比较和查找匹配项)作为学校作业。它是使用线程和有界缓冲区的管道架构。第一个问题是:

  1. 为什么即使它使用更多线程(一个用于从文件读取 - 因为它是快速的过程,一个用于进行变化 - 因为它仍然比 3x 加密线程快,3 个用于加密的线程 - 因为它比集中式密码破解器还要慢)这是一个非常缓慢的过程,最后只有一个线程进行比较)?

  2. 为什么当我添加第 4 个加密线程时,当线程完成时,程序末尾没有写入成功的构建。

非常感谢您的任何回答,如果需要一些东西,例如我的实验只是问。

代码:加密类

package passwordcracking;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Encrypt implements Runnable {

private static final Logger LOGGER = Logger.getLogger("passwordCracker");
private final Buffers<String> bufferTakeFrom;
private final Buffers<PairEncPWandClearPW> bufferPutTo;
String possiblePassword;
private MessageDigest messageDigest;

/**
 *
 * @param bufferTakeFrom
 */
public Encrypt(Buffers<String> bufferTakeFrom, Buffers<PairEncPWandClearPW>        

bufferPutTo) 
{
    this.bufferTakeFrom = bufferTakeFrom;
    this.bufferPutTo = bufferPutTo;
    try {
        messageDigest = MessageDigest.getInstance("SHA");
    } catch (NoSuchAlgorithmException ex) {
        LOGGER.log(Level.SEVERE, ex.getMessage());
        throw new RuntimeException(ex);
    }
}

@Override
public void run() {
    do {
        possiblePassword = bufferTakeFrom.take();
        EncryptSingleWord(possiblePassword);
    } while (!possiblePassword.equals("-1"));

}

private void EncryptSingleWord(final String possiblePassword) {
    byte[] digest = null;
    try {
        digest = messageDigest.digest(possiblePassword.getBytes());
        PairEncPWandClearPW pair = new PairEncPWandClearPW(digest, possiblePassword);
        bufferPutTo.put(pair);
    } catch (Exception ex) {
        System.out.println("Exception: " + ex);
        System.out.println("possible password bytes: " + possiblePassword.getBytes());
        System.out.println("password:" + possiblePassword);

    }

}}

制作变化类:

package passwordcracking;

import utilities.StringUtilities;

/**
 *
 * @author zatokar
 */
public class MakeVariations implements Runnable {

Buffers<String> bufferTakeFrom;
Buffers<String> bufferPutTo;
String dictionaryEntry;

public MakeVariations(Buffers<String> bufferTakeFrom, Buffers<String> bufferPutTo) {
    this.bufferTakeFrom = bufferTakeFrom;
    this.bufferPutTo = bufferPutTo;
}

@Override
public void run() {
    do {
        dictionaryEntry = bufferTakeFrom.take();
        makeVariations(dictionaryEntry);
        if (dictionaryEntry.equals("-1")) {
            System.out.println("Make variations thread finished.");
        }
    } while (!dictionaryEntry.equals("-1"));
}

public void makeVariations(final String dictionaryEntry) {
    final String possiblePassword = dictionaryEntry;
    bufferPutTo.put(dictionaryEntry);
    final String possiblePasswordUpperCase = dictionaryEntry.toUpperCase();
    bufferPutTo.put(possiblePasswordUpperCase);
    final String possiblePasswordCapitalized = StringUtilities.capitalize(dictionaryEntry);
    bufferPutTo.put(possiblePasswordCapitalized);
    final String possiblePasswordReverse = new StringBuilder(dictionaryEntry).reverse().toString();
    bufferPutTo.put(possiblePasswordReverse);
    for (int i = 0; i < 100; i++) {
        final String possiblePasswordEndDigit = dictionaryEntry + i;
        bufferPutTo.put(possiblePasswordEndDigit);
    }
    for (int i = 0; i < 100; i++) {
        final String possiblePasswordStartDigit = i + dictionaryEntry;
        bufferPutTo.put(possiblePasswordStartDigit);
    }
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 100; j++) {
            final String possiblePasswordStartEndDigit = i + dictionaryEntry + j;
            bufferPutTo.put(possiblePasswordStartEndDigit);
        }
    }
}
}

缓冲器类:

package passwordcracking;

import java.util.LinkedList;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author zatokar
 */
public class Buffers <T>{
final Queue<T> ll = new LinkedList<>();
int capacity=500000;
public synchronized T take(){

    while (ll.isEmpty()) {
        try {
//             System.out.println("empty");
            wait();
        } catch (InterruptedException ex) {
            Logger.getLogger(Buffers.class.getName()).log(Level.SEVERE, null, ex);
        }
        }
  T element = ll.remove();
  notifyAll();
  return element;

}

    public synchronized void put(T element) {
    while (isFull()) {
        try {

//            System.out.println("full "+element);
            wait();
        } catch (InterruptedException e) {
        }
    }

    ll.add(element);
    notifyAll();
}
  public boolean isFull(){
      return (ll.size()==capacity);
      }


    public boolean isEmpty(){
        if (ll.isEmpty()){
            return true;
        }
        else{
            return false;}
    }
}

类比:

包密码破解;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Compare implements Runnable {

Buffers<PairEncPWandClearPW> bufferTakeFrom;
final List<UserInfo> userInfos;
byte[] digest;
PairEncPWandClearPW pair;
String possiblePassword;

public Compare(Buffers<PairEncPWandClearPW> bufferTakeFrom) throws IOException {
    this.bufferTakeFrom = bufferTakeFrom;
    userInfos = PasswordFileHandler.readPasswordFile("passwords.txt");
}

@Override
public void run() {
    do {
        pair=bufferTakeFrom.take();
        possiblePassword = pair.getClearPW();
        digest = pair.getEncryptedPW();
        List<UserInfoClearText> list = checkSingleWord(userInfos, digest, 

possiblePassword);
        if (!list.isEmpty()) {
            System.out.println(list);
        }
        if (possiblePassword.equals("-1")) {
            System.out.println("Comparing thread finished.");
            final long endTime = System.currentTimeMillis();
            final long usedTime = endTime - PasswordCracking.startTime;
            System.out.println("Used time: " + usedTime / 1000 + " seconds = " +     

usedTime / 60000.0 + " minutes");
        }
    } while (!possiblePassword.equals("-1"));
}

private List<UserInfoClearText> checkSingleWord(final List<UserInfo> userInfos, final     

byte[] digest, final String possiblePassword) {
    final List<UserInfoClearText> results = new ArrayList<UserInfoClearText>();
    for (UserInfo userInfo : userInfos) {
        if (Arrays.equals(userInfo.getEntryptedPassword(), digest)) {
           results.add(new UserInfoClearText(userInfo.getUsername(),     

possiblePassword));
        }
    }
    return results;
}
}
4

2 回答 2

0

尝试使用SynchronousQueue而不是您自己的 Buffers 类。我很确定这也将是一个重大的速度改进(因为您的同步实现)。

除此之外,您的架构是有问题的。它需要 SynchroneousQueue 来防止生成线程溢出/下溢处理线程,为什么这些处理线程不生成自己的工作?

您可以编写一个 Runnable,从字典中提取一个单词,生成变体,然后根据真实密码测试这些变体。这不仅可以大大简化代码,还可以确保线程 100% 地解决实际问题,您不必担心要花多少线程在什么问题上。

于 2013-10-29T16:15:49.533 回答
0

好吧,多亏了 TwoThe,他几乎完全解决了我的问题。主要的加速是用 LinkedBlockingQueue 替换 LinkedList 队列(他回答我使用 SynchronousQueue 但它没有实现容量构造函数),它与容量构造函数一起使用是必要的,因为在做出变化并将其放入 LinkedList 之后,你肯定得到 OutOfMemoryException。非常感谢,速度降低了 3 倍。问题是我自己在缓冲区类中的同步。

于 2013-10-30T10:51:41.707 回答