Imagine I own a web-store. I am a smart guy, so I do not store my passwords plaintext, rather I salt them first, then store the salt and the hash. However, I am not that smart, and I use a very sad 16-bit hashing function.
Tragedy strikes, and my full DB of salts and hashes leaks to you.
Your assignment is to brute-force your own valid passwords that, using the same salt, result in the same hash as my original passwords.
Of course you are also smart, so you will solve this using multiple processors, for faster cracking. To do this, you will design a system where producer threads will keep on generating random Strings to serve as inputs for the hashing function. Consumer threads will now continuously read these Strings, and test whether, using String + Salt, it results in the same hash that you want to break / find a collision for. When all hashes are broken, the system will shut down, as its work is now over. At the very end you will return a list of equally valid passwords (Note, passwords, not hashes, not salted passwords, just passwords).
To score the maximum points:
- Follow all requirements below
- Make the single test pass, it verifies if you indeed found hash collisions
- Use a fixed nr of producer threads: 2 to be precise
- Use a fixed nr of consumer threads: 4 of them
- A producer's job is to keep producing, in a Thread-Safe way, Random inputs, ad infinitum, until asked to shutdown
- A consumer's job is to keep taking in random inputs, checking if they produce a hash collision, and if so, record which input triggered the collision
- Do not manually manage your threads, recall Executors from previous lectures
- Keep the concurrent collections, and the synchronisers in mind discussed this lecture, and use them appropriately
- Absolutely do not use the following: any form of
Lock
,synchronized
,volatile
or any other form of creative low-level locking (e.g. usingSemaphore(1)
) - Unless really needed, try to avoid using the
Atomic\*
classes - Implement a clean shutdown mechanism, after all 10 passwords are cracked, cleanly signal all consumers and producers to end their jobs, then cleanly wait for the executor(s) to properly shut down
- Use the
Salt
andHash
classes to find the data you need to break - Return a list of passwords, in the same order, so they correspond to the data in
Salt
andHash
- Do not add any new libraries, the ones in
pom.xml
will certainly suffice to solve this - Be absolutely completely positively Thread Safe in all your operations (and look up the definition in doubt)
- Only store the very first valid password guess: if another consumer finds another valid hash, discard it
- Make an efficient program, at least make sure your implementation is faster than a single-threaded implementation
- Read up yourself on how to properly do consumer-producer design, and handle clean shutdowns, if needed. You are all University students, and do not need handholding for every single detail. "It was not covered in the lecture" is not a valid excuse
In the package org.zeroturnaround.jf.lecture8
all code examples shown in class can be found.
A lot (most?) of this code originates from the excellent read Java Concurrency in Practice by Brian Goetz, read this book.
- Run
./mvnw clean deploy
- Send your solution to [email protected]