Như đã giải thích ở trên, giải thuật kiểm tra mật khẩu ứng cử được thực hiện song song, theo độ dài của mật khẩu. Đầu tiên, giải thuật tính số lô cần thiết của một nhóm mật khẩu có độ dài xác định i. Sau đó, với mỗi một lô p mật khẩu, giải thuật tính số thứ tự của các mật khẩu trong lô đó làm đầu vào cho hàm kiểm tra mật khẩu được thực hiện trên một tiến trình. Mã giả của giải thuật như sau:
found = 0; //found là biến toàn cục, = 1 nếu tìm ra mật khẩu đúng for i = 1 to k //duyệt từng độ dài mật khẩu
{
m = |Si| ; // tổng số mật khẩu cần thử có độ dài i p = thread_numbers; // số tiến trình
l = CEIL(m/p); // Số lô của các mật khẩu có độ dài i /*duyệt song song từng lô, mỗi lô có p mật khẩu*/ for j = 0 to l - 1
{
base = j*p; // thứ tự mật khẩu đầu tiên của lô;
for id = 0 to p-1 in parallel
pw = GenPWi(base, id); //sinh mật khẩu
/*sinh AES tương ứng với mật khẩu*/
(TestVerifier, AesKey) = PBKDF2();
if (TestVerifier == Verifier)
{
/*giải mã dữ liệu data_compressed_encrypted độ dài CHUNK đọc
từ file nén sử dụng khóa AesKey*/
data_compressed = Aes_crt(AesKey, data_compressed_encrypted,
CHUNK);
/* giải nén dữ liệu vừa được giải mã */
data = inflate (data_compressed, CHUNK);
/* nhận dạng dựa vào extension của file gốc và một số header
của các định dạng thông dụng*/ boolean ok = 0; if (header(data) == headerPDF) ok = 1; if (ok) password[id] = guess_password; else password[id] = “”; } }
/* sau khi duyệt xong một lô mật khẩu thì kiểm tra kết quả trong lượt kiểm tra đó có mật khẩu đúng hay không, phần việc này thực hiện trên host*/
/* password là mảng chứa mật khẩu trả về, nếu khác kí tự “” thì có nghĩa nó là mật khẩu đúng*/ for id = 0 to p -1 { if (strcmp(password[id], “”) != 0) { found = 1; display password[id];
39
break;
}
}
/*nếu tìm thấy mật khẩu đúng thì dừng toàn bộ chương trình*/ if (found)
break;
}
Hàm sinh GenPWi nhận đầu vào là thứ tự của mật khẩu đầu tiên của lô trong nhóm i (base) cùng với thứ tự id trong lô của mật khẩu cần kiểm tra. Trong thực tế, thứ tự id được sinh ra một cách tự động khi kích hoạt kernel cho một lô, và tiến trình xử lý có thể lấy được giá trị này thông qua một số biến hệ thống của CUDA.
Hàm GenPWi(base, id) sẽ sinh ra mật khẩu tại vị trí base+id của nhóm, sau đó truyền mật khẩu vào hàm băm PBKDF2 để sinh giá trị AesKey. Giá trị khóa này được đem so sánh với giá trị kiểm tra mật khẩu lưu trong phần header của file nén để xác định xem mật khẩu vừa được sinh có phải là một mật khẩu ứng cử hay không.
Hàm GenPWi(base,id) được định nghĩa như sau: GenPWi(base, id) = xi-1… x0
xo = S[((base + id) div no) mod n] x1= S[((base + id) div n1) mod n] xi-1 = S[((base + id) div ni-1 ) mod n]