Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

Part I: Brute Force Attack

You have come across a password leak, where you have access to 100,000 SHA-256 hashed passwords. Now, the developers were not very smart and did not include any salt & pepper for the passwords when hashing them. What you’re going to do is iterate through all of the lowercase text passwords and try to find which ones match the list of hashed passwords.

In this case we have code in a class called BruteForceAttack that iterates through every lowercase password of length 5 to find matching passwords in the file hashedpassword.txt.

This takes about 21 seconds to run on my laptop (a 2GHz Quad-Core i5 2021 13” Macbook) . Extending this to passwords of length 6 will take 26 times as long. If I included passwords that contained numbers and uppercase letters, it would take almost 80 times as long and no one has time for that, so we will stick to lowercase passwords.

What you’re going to do is split this problem into several threads.

- Describe what kind of computer you’re running this code on

- How long does it take to do a brute force attack on 5 character passwords?

- How many passwords does it find?

- Split the problem into several threads

- What is the maximum number of threads that minimizes the time is takes to brute force all of the passwords?

- How fast can your computer process 6 character passwords using multithreading?

Part II: Understanding Synchronization

This assignment is a little different. Most of the code is already written. You have to understand it. We have three queues. A general purpose queue, and Integer Queue, and a String Queue.

At the start, you have a Producer, which randomly picks whether to put an Integer or a String on the general purpose queue. If it chooses to put an Integer on the queue, it picks a random Integer. If it chooses to put a String on the queue, it chooses a random String from the file in “data/words”. It runs very fast and stops putting data on the queue if there are 100 objects in the queue already but will start adding them again if the length of the queue falls beneath 100. The Producer puts data on the general purpose queue very fast.

The general purpose queue has four “middlemen” consumers: two Integer MiddleMan objects and two String MiddleMan objects, each of which polls the general purpose queue to see if their data type is available on the queue, and if it is, removes it from the queue and places it on their respective queue. However, it only places it on their respective queue if there are less than 10 objects in the queue already but will start adding them again if the length of the queue falls beneath 10. The MiddleMan objects get data off the General Purpose Queue and put it on their outgoings queues very fast, but not as fast as the Producer Object.

At the end we have two Consumer objects: one for the Integer queue and one for the String queue. Consumer objects will take two items off the queue and, if those items are numbers, add them together, and if those items are Strings (or another non-number), concatenate the String representations of those objects together. The Consumer objects consume very slowly

 

This is all put together in the class MonitorQueues which connects everything together, starts the Producer, Consumer, and MiddleMan threads, and then monitors the queue sizes for any errors. Note that the GeneralPurposeQueue is a LinkedList while the Integer Queue and String Queue are ConcurrentLinkedQueue objects.

Question 1: Go to MiddleMan.java, line 24. You can see I have commented out the synchronized(in) block. The code has an if statement on line 25 that checks if there is an object available on the queue and, if so, if the type of object on the queue is of the correct class for the MiddleMan, using the isInstance method, implemented in the StringMiddleMan and IntegerMiddleMan subclasses.

In MonitorQueues.java, Run the application. The first thing you will see will be a NoSuchElementException or a NullPointerException (or both!).  The compound conditional:

if ((in.peek() != null) && (isInstance(in.peek().getClass())))

Should return false immediately if in.peek() is null, and in.remove() should work fine as long as in.peek() shows there is something available on the queue.

In the absence of synchronization, why does this happen? What sequence of events is occurring that causes these errors to be raised?

Ok, now uncomment the synchronized(in) block before proceeding to question 2.

Question 2: Stop the program if it’s still running and restart it. What you will see is the output of the two consumers, which is either the addition of two numbers of the concatenation of two strings. However, every so often an alter comes up that either the Integer Queue or the String Queue is too long. However, the alert that the General Purpose Queue is too long never comes up. If we go to Producer.java, line 42, we see the place where it puts a new object on the queue only if the size is less than the maximum queue size of 100, and the block isn’t synchronized.

Even though the block isn’t synchronized, and even though the queue is a regular LinkedList that doesn’t support concurrency protection, why is there never a situation where the MAX_QUEUE_SIZE constraint is violated?

Now that this is done, you can choose to synchronize that block or not. It doesn’t matter too much, as you can see.

Question 3: We still get those messages “Alert. Queue [1 or 2] > 10. Shouldn’t Happen,” referring to the IntegerQueue and the StringQueue, however. We need to fix that. The MiddleMan objects put data on those Queues in the MiddleMan.run() method, once we have an outObj. Consumer objects get data off of those Queues in the code in Consumer.java in lines 26-44.

Write code to fix these overflows. You may NOT change the DELAY timings to do so, which influences the rate at which data is produced or consumed on the queues. Explain why your modifications work.