Я написал программу для назначения, которая взламывает пароли, используя атаку по словарю, и пытаюсь ускорить ее, используя Open MPI, но моя версия Open MPI медленнее, и я не уверен, почему или чего я не понимаю. Зашифрованные пароли генерируются с использованием соли и строки, передаваемой в unix-функцию «crypt».
Из того, что я узнал по просмотрам лекций в классе, я пришел к этому.
main.cc:
//****************************************************
// File: main.cc
// Author: Jordan Ward
// Purpose: Crack passwords in the form word+number
// or number+word where number can be at most
// three digits long using
// Open MPI to make it more efficient.
//*****************************************************
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <unistd.h>
#include <mpi.h>
using namespace std;
// Builds the list of encrypted passwords,
// list of dictionary words, and list of salts.
void file_IO(int argc, char *argv[], vector<string> &encPass, vector<string> &words,
vector<string> &salts);
// Builds the list of possible guesses.
void build_guesses(vector<string> &guesses, vector<string> &words);
// Tries each of the salts with each of
// the strings in the list of guesses to see
// if they match the ecrypted passwords.
void crack(string pass, vector<string> &salts, vector<string> &guesses);
// Broadcasts the vectors to all other processes.
void broadcast_receive(vector<string> &encPass, vector<string> &words,
vector<string> &salts, vector<string> &guesses);
// Converts a vector of strings to a vector of chars
vector<char> convert(vector<string> &strings);
int main(int argc, char *argv[]) {
vector<string> encPass;
vector<string> words;
vector<string> salts;
vector<string> guesses;
int numProcesses;
int procNum;
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &numProcesses); // Get the number of processes
MPI_Comm_rank(MPI_COMM_WORLD, &procNum); // Get the process number
if(procNum == 0) {
file_IO(argc, argv, encPass, words, salts);
build_guesses(guesses, words);
}
broadcast_receive(encPass, words, salts, guesses, numProcesses, procNum);
if(procNum != 0) {
for(size_t i = 0; i < encPass.size(); i++) {
if(i % procNum == 0) {
size_t del = encPass[i].rfind("$"); // Finds the last "$" in the string
string pass = encPass[i].substr(del); // Pass is a substring starting at the last "$"
crack(pass, salts, guesses);
}
}
}
MPI_Finalize();
return 0;
}
void file_IO(int argc, char *argv[], vector<string> &encPass, vector<string> &words,
vector<string> &salts) {
if(argc < 3) {
cout << "One or more files were not specified." << endl;
cout << "Correct format is 'mpiexec a.out file1 file2'" << endl;
exit(1);
}
ifstream secretPass(argv[1]);
string singlePass;
while(getline(secretPass, singlePass)) {
encPass.push_back(singlePass);
}
secretPass.close();
ifstream dictionary(argv[2]);
string word;
while(getline(dictionary, word)) {
words.push_back(word);
}
dictionary.close();
ifstream salt("salts");
string s;
while(getline(salt, s)) {
salts.push_back(s);
}
salt.close();
}
void build_guesses(vector<string> &guesses, vector<string> &words) {
//one word and one number
for(size_t i = 0; i < words.size(); i++) {
for(size_t j = 0; j < 10; j++) {
guesses.push_back(words[i] + to_string(j));
}
}
//one number and one word
for(size_t i = 0; i < 10; i++) {
for(size_t j = 0; j < words.size(); j++) {
guesses.push_back(to_string(i) + words[j]);
}
}
//one word and two numbers
for(size_t i = 0; i < words.size(); i++) {
for(size_t j = 0; j < 10; j++) {
for(size_t x = 0; x < 10; x++) {
guesses.push_back(words[i] + to_string(j) + to_string(x));
}
}
}
//two numbers and one word
for(size_t i = 0; i < 10; i++) {
for(size_t j = 0; j < 10; j++) {
for(size_t x = 0; x < words.size(); x++) {
guesses.push_back(to_string(i) + to_string(j) + words[x]);
}
}
}
//one word and three numbers
for(size_t i = 0; i < words.size(); i++) {
for(size_t j = 0; j < 10; j++) {
for(size_t x = 0; x < 10; x++) {
for(size_t y = 0; y < 10; y++) {
guesses.push_back(words[i] + to_string(j) + to_string(x) + to_string(y));
}
}
}
}
//three numbers and one word
for(size_t i = 0; i < 10; i++) {
for(size_t j = 0; j < 10; j++) {
for(size_t x = 0; x < 10; x++) {
for(size_t y = 0; y < words.size(); y++) {
guesses.push_back(to_string(i) + to_string(j) + to_string(x) + words[y]);
}
}
}
}
}
void crack(string pass, vector<string> &salts, vector<string> &guesses) {
for(size_t i = 0; i < salts.size(); i++) {
for(size_t j = 0; j < guesses.size(); j++) {
string ep = crypt(guesses[j].c_str(), salts[i].c_str());
if(ep.compare(salts[i] + pass) == 0) {
cout << "Password: " + guesses[j] << endl;
}
}
}
cout << "Password not found" << endl;
}
void broadcast_receive(vector<string> &encPass, vector<string> &words,
vector<string> &salts, vector<string> &guesses) {
int buffer[5];
buffer[0] = encPass.size();
buffer[1] = words.size();
buffer[2] = salts.size();
buffer[3] = guesses.size();
MPI_Bcast(buffer, 4, MPI_INT, 0, MPI_COMM_WORLD);
encPass.resize(buffer[0]);
words.resize(buffer[1]);
salts.resize(buffer[2]);
guesses.resize(buffer[3]);
vector<char> ep = convert(encPass);
vector<char> w = convert(words);
vector<char> s = convert(salts);
vector<char> g = convert(guesses);
MPI_Bcast(ep.data(), ep.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
MPI_Bcast(w.data(), w.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
MPI_Bcast(s.data(), s.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
MPI_Bcast(g.data(), g.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
}
vector<char> convert(vector<string> &strings) {
vector<char> cstrings;
cstrings.reserve(strings.size());
for(string s : strings) {
for(size_t i = 0; i < strlen(s.c_str()); i++) {
cstrings.push_back(s.c_str()[i]);
}
}
return cstrings;
}
Мой мыслительный процесс:
Если номер процесса равен 0, прочитайте файлы и постройте векторы со строками из файлов, а затем создайте список догадок.
В противном случае получите все списки, пройдите каждый зашифрованный пароль и посмотрите, соответствует ли какая-либо из солей в сочетании с какой-либо догадкой зашифрованному паролю.
Что я делаю неправильно или не понимаю, что делает это медленнее, чем оригинал без кода Open MPI? Исходный код будет просто одним и тем же файлом без функций broadcast_receive и convert и, очевидно, без вызовов MPI в основной функции.
Я компилирую с mpic++ -std=c++11 -Wall main.cc -lcrypt
, а затем запускаю с mpiexec a.out enc_passwords words
, где enc_passwords - это небольшой файл с некоторыми зашифрованными паролями, сгенерированными из функции crypt, а words - это небольшой список слов для построения догадок.