Sinh không gian mật khẩu từ cấu trúc mật khẩu và từ điển

Một phần của tài liệu Thám mật khẩu các file word (Trang 44)

Trong phần này chúng tôi đề xuất giải thuật sinh không gian mật khẩu từ cấu trúc mật khẩu và tập từ điển đã được định nghĩa trước genpws(D,PP,P)

45 Đầu vào cho giải thuật bao gồm:

- Tập từ điển D = {D1,…,Dn}, với Di là một từ điển có dạng DNi = {wi

1,…,wi

ni) trong đó DNi là siêu ký hiệu đại diện cho từ điển Di và ni là số lượng từ trong từ điển Di.

- Tập mẫu định nghĩa trước PP = {PP1,…,PPm} với mẫu PPi có dạng PPNi = Si, trong đó PPNi là siêu ký tự đại diện của mẫu, Si là xâu ký tự biểu diễn mẫu. Để đơn giản cho việc nhập dữ liệu và chuyển đổi cấu trúc, chúng tôi đề xuất biển diễn một xâu mẫu theo định dạng như sau:

S = C1C2…Cn Trong đó: 𝐶𝑖 = { #{𝑤}𝑣ớ𝑖 𝑤 𝑙à 𝑐ℎ𝑢ỗ𝑖 𝑘ý 𝑡ự 𝑐𝑢ố𝑖 ${𝑁}𝑣ớ𝑖 𝑁 𝑙à 𝑡ê𝑛 𝑡ừ đ𝑖ể𝑛 %{𝑁}𝑣ớ𝑖 𝑁 𝑙à 𝑡ê𝑛 𝑚ẫ𝑢

- Cấu trúc mật khẩu là một danh sách có thứ tự P = {P1,…,Pk} các xâu mẫu với định dạng như mô tả bên trên.

Đầu ra cho giải thuật: là một danh sách có thứ tự mật khẩu phù hợp với các cấu trúc được định nghĩa trên đầu vào.

Thông thường danh sách mật khẩu này rất lớn, đôi khi không thể lưu trữ trong bộ nhớ của một máy tính. Hơn nữa, quá trình kiểm tra mật khẩu thường được thực hiện trên các hệ thống tính toán hiệu năng cao, phân tán. Do vậy, để thuận tiện cho việc phân chia công việc kiểm tra mật khẩu này, chúng tôi đề xuất một hàm sinh mật khẩu khác có dạng genpws_partial(D,PP,P, from, count) trong đó D, PP, P là tập từ điển, tập mẫu định nghĩa trước và cấu trúc mật khẩu như giải thuật genpws. fromcount là thứ tự bắt đầu của mật khẩu cần sinh và số lượng mật khẩu cần sinh.

Giải thuật được chia làm các pha sau:

Pha 1: Đọc dữ liệu đầu vào và phân tích chuyển đổi thành cấu trúc bên trong (parsing)

Pha 2: Chuẩn hóa cấu trúc mật khẩu Pha 3: Sinh mật khẩu theo thứ tự

1. Đọc dữ liệu đầu vào và phân tích chuyển đổi thành cấu trúc bên trong. Nhiệm vụ chính của pha này là chuyển đổi các dữ liệu đầu vào, thường biểu diễn dưới dạng xâu ký tự và tệp dữ liệu thành các cấu trúc bên trong, trong đó bao gồm:

- Tập từ điển D: là danh sách các từ điển {D1,…, Dn} với n là số lượng từ điển. Mỗi từ điển Di chứa một danh sách từ {wi

1,wi

ni} với ni là số lượng từ trong từ điển Di.

46

- Tập mẫu định nghĩa trước PP: với PPN là danh sách tên mẫu {PPN1,PPNm}, m là số lượng mẫu được định nghĩa trước và S là danh sách mẫu {S1,…Sm}. Mỗi mẫu S là một danh sách ký hiệu có định dạng:

o type: nhận một trong các giá trị {final, dic, pat} tương ứng với xâu ký tự cuối, ký hiệu đại diện từ điển; ký hiệu đại diện mẫu định nghĩa trước. o value: xâu ký tự cuối trong trường hợp type = final; tên/thứ tự từ điển

trong trường hợp type = dic; tên/thứ tự mẫu định nghĩa trước trong trường hợp type = pat.

- Cấu trúc mật khẩu P: {P1,…,Pk} trong đó Pi là mẫu mật khẩu theo khuôn dạng mô tả trên.

2. Chuẩn hóa cấu trúc mật khẩu

Giải thuật chuẩn hóa cấu trúc mật khẩu stdpat(P) được định nghĩa một cách đệ quy như sau:

- stdpat() =  :

- stdpat(#{w}S) = ${DN}stdpat(S) với DN là ký hiệu đại diện cho một từ điển mới có môt từ DN = {w} được bổ sung vào tập từ điển D

- stdpat(${N}S) = ${N}stdpat(S)

- stdpat(%{N}S)=stdpat(PP)stdpat(S) với PP là chuỗi biểu diễn mẫu định nghĩa trước tương ứng với tên N.

Sau quá trình chuẩn hóa, cấu trúc mật khẩu sẽ có dạng một danh sách mẫu chuẩn hóa {P’1,P’k} trong đó P’i là mẫu chuẩn hóa có bao gồm một danh sách ký hiệu đại diện từ điển có dạng D1…Dki.

Ngoài ra, để phục vụ cho việc sinh mật khẩu theo đúng thứ tự trong một khoảng cho trước, chúng tôi định nghĩa hàm numpws(S) với S = D1…Dl để tính số lương mật khẩu mật khẩu có thể sinh ra từ chuỗi S:

numpws(D1…DL) = size(D1) x … x size(DL) trong đó size(D) là hàm lấy kích thước của từ điển D. (adsbygoogle = window.adsbygoogle || []).push({});

Mỗi mẫu Pi trong danh sách mẫu {P1,…,Pk} thuộc cấu trúc mật khẩu được bổ sung thêm thong tin:

- start: thứ tự mật khẩu đầu tiên của mẫu - count: số lượng mật khẩu của mẫu Trong đó:

start(Pi) = count(P1) + … + count(Pi-1) count(Pi) = numpws(Pi)

3. Sinh mật khẩu theo thứ tự

47

Function genpws_partial(D,PP,P,start, count) Begin

// Đọc dữ liệu // Chuẩn hóa mẫu // tìm mẫu i đầu tiên I := 1;

while (start(Pi) + count(Pi) < start) i := i + 1;

s := start – start(Pi); c := min(count, count(Pi));

result := ;

repeat

result := result @ genpws_pat_partial(Pi,s, c); count := count – c; i := i +1; s := 0; c := min(count, count(Pi)); until c = 0; End

Trong đó genpws_pat_partial(P, start, count) là giải thuật sinh c mật khẩu từ vị trí s của mẫu P. Giả sử P là chuỗi D1…DL, việc sinh mật khẩu trong mẫu sẽ bắt đầu từ các từ trong từ điển Di tại vị trí posi như sau:

Với từ điển DL: posL = start mod size(DL)

Với từ điển Di: posi = (start div (size(Di+1) x ... x size(DL))) mod size(Di) Giải thuật genpws_pat_partial(P, start, count) được mô tả như sau:

Function genpws_pat_partial(D1…DL, start, count)

Begin

// Tính vị trí bắt đầu sinh của các từ trong từng từ điển

posL = start mod size(DL);

i = L - 1; While i >= 1 Begin

start = start div size(Di+1);

posi = start mod size(Di);

i = i -1 ; End; // Sinh từ điển Result = ; C = 0; While c < count Begin

Result = result @ D1[pos1]…DL[posL];

J = L; While j >= 1 Begin posj = posj + 1; If posj>= size(Dj) Begin posj = 0; j = j – 1; End Else break; End End return result; End

48

CHƯƠNG 4 –THỬ NGHIỆM VÀ ĐÁNH GIÁ 4.1. Các dữ liệu cần trích xuất

4.1.1. Sinh khóa Mã hóa Văn bản ECMA-376 (Mã hóa chuẩn)

Khóa mã cho Mã hóa Văn bản ECMA-376 phải được sinh bởi phương thức sau:

Cho H() là thuật toán băm được xác định bởi trường (adsbygoogle = window.adsbygoogle || []).push({});

EncryptionHeader.AlgIDHash, Hn là dữ liệu băm lần thứ n, và dấu "+" thể hiện sự móc nối. Thuật toán băm này phải là SHA-1. Mật khẩu phải được cung cấp như một mảng các ký tự Unicode. Giới hạn độ dài của mật khẩu và độ dài các ký tự được sử dụng bởi mật khẩu phụ thuộc vào việc thực hiện. Băm mật khẩu ban đầu được sinh ra như sau:

- H0 = H(salt + password)

Salt phải được sinh ngẫu nhiên và có kích thước 16 byte. Salt phải được lưu trong trường EncryptionVerifier.Salt được chứa cùng luồng \EncryptionInfo. Băm lại bằng kỹ thuật sau:

- Hn = H(iterator + Hn-1)

Với iterator là giá trị không dấu 32-bit mà lúc đầu được thiết lập là 0x00000000 và sau đó tăng dần mỗi lần lặp cho đến khi thực hiện đủ 50000 lần. Giá trị của iterator mỗi lần lặp phải là 49999.

Sau đó dữ liệu băm cuối cùng được thu lại, khóa mã phải được sinh bằng việc dùng dữ liệu băm cuối cùng, và số block phải là 0x00000000. Thuật toán mã hóa phải được chỉ định trong trường EncryptionHeader.AlgID. Thuật toán mã hóa phải sử dụng chế độ ECB. Phương thức được sử dụng để sinh dữ liệu băm là đầu vào trong thuật toán xác định khóa như sau:

- Hfinal = H(Hn + block)

Phương thức xác định khóa mã được chỉ ra theo các bước sau:

1.Cho cbRequiredKeyLength bằng với kích thước, tính theo byte, của độ dài khóa yêu cầu cho thuật toán mã hóa thích hợp như đã chỉ rõ trong cấu trúc EncryptionHeader. Lưu ý rằng cbRequiredKeyLength

phải nhỏ hơn hoặc bằng 40.

2.Cho cbHash là số các byte đầu ra của thuật toán băm H.

3.Tạo bộ đệm 64 byte bằng cách lặp hằng số 0x36 64 lần. XOR Hfinal vào các byte cbHash đầu tiên của bộ đệm này, và tính toán băm của bộ đệm kết quả trả về 64 byte bằng cách sử dụng thuật toán băm H. Việc này sẽ sinh ra một giá trị băm của độ dài cbHash. Gọi giá trị trả về là X1. 4.Tạo bộ đệm 64 byte khác bằng cách lặp hằng số 0x5C 64 lần. XOR

49

của bộ đệm kết quả trả về 64 byte bằng cách sử dụng thuật toán băm H. Việc này sẽ sinh ra một giá trị băm của độ dài cbHash. Gọi giá trị trả về là X2.

5.Kết hợp X1X2 thành X3, từ đó sẽ sinh ra một giá trị bằng 2 lần độ dài của cbHash.

6.Cho keyDerived bằng các byte cbRequiredKeyLength đầu tiên của

X3.

4.1.2. Sinh mật khẩu xác thực (Mã hóa chuẩn)

Mật khẩu xác thực sử dụng cấu trúc EncryptionVerifier. Trường Salt của mật khẩu xác thực phải bằng với salt được tạo trong suốt quá trình sinh khóa mật khẩu, như đã nêu ở mục trên. Một xác thực được sinh ngẫu nhiên sẽ được băm bằng thuật toán băm SHA-1 được chỉ định trong cấu trúc EncryptionHeader và được mã hóa bằng khóa đã sinh trước, với số của block 0x00000000.

4.1.3. Xác thực mật khẩu (Mã hóa chuẩn)

Mật khẩu phải được xác thực theo các bước sau: 1.Sinh một khóa mã như đã đã đề cập ở mục 4.1.1.

2.Giải mã trường EncryptedVerifier của cấu trúc EncryptionVerifier

để thu về giá trị Verifier. Giá trị Verifier trả về phải là một mảng 16 byte.

3.Giải mã trường EncryptedVerifierHash của cấu trúc

EncryptionVerifier để thu thập băm của giá trị Verifier. Số các byte được sử dụng bởi băm Verifier đã mã hóa phải là 32. Số các byte được sử dụng bởi băm Verifier đã giải mã được đưa ra bởi trường

VerifierHashSize, phải là 20.

4.Tính toán giá trị băm SHA-1 của giá trị Verifier đã tính ở bước 2. 5.So sánh kết quả của bước 3 và bước 4. Nếu hải giá trị băm không khớp

nhau, thì mật khẩu không chính xác.

4.1.4. Sinh khóa mã (Mã hóa nhanh)

Khóa mã cho Mã hóa Văn bản ECMA-376 sử dụng mã hóa nhanh phải được sinh theo phương thức sau. (adsbygoogle = window.adsbygoogle || []).push({});

Cho H() là một thuật toán băm được xác định bởi thành tố

PasswordKeyEncryptor.hashAlgorithm, Hn là dữ liệu băm của lần lặp thứ n, và một dấu "+" thể hiện sự móc nối. Mật khẩu phải được cung cấp dưới dạng một mảng các ký tự Unicode. Giới hạn độ dài của mật khẩu và các ký tự được dùng bởi mật khẩu phụ thuộc vào việc thực hiện. Băm mật khẩu ban đầu được sinh ra như sau:

50

Salt phải được sinh một cách ngẫu nhiên. Salt phải được lưu trong thành tố

PasswordKeyEncryptor.saltValue chứa cùng với luồng \EncryptionInfo như đã nêu ở mục 2.2.4.7. Băm sau đó được lặp theo kỹ thuật sau:

- Hn = H(iterator + Hn-1)

Với iterator là giá trị không dấu 32 bit được thiết lập ban đầu là 0x00000000 và tăng dần qua mỗi lần lặp cho đến khi tất cả các vòng lặp

PasswordKey.spinCount được thực hiện. Giá trị của iterator trong lần lặp cuối cùng phải là giá trị nhỏ hơn PasswordKey.spinCount.

Dữ liệu băm cuối cùng dùng cho khóa mã được sinh ra theo phương thức sau: - Hfinal = H(Hn + blockKey)

Với blockKey đại diện cho một mảng các byte được dùng để chặn hai block khác nhau mã hóa thành cùng bản mã.

Nếu kích thước của kết quả trả về Hfinal nhỏ hơn kích thước của

PasswordKeyEncryptor.keyBits, thì khóa phải được đệm thêm các byte có giá trị 0x36. Nếu giá trị băm lớn hơn kích thước PasswordKeyEncryptor.keyBits thì khóa được thu thập bằng việc cắt xén giá trị băm.

4.1.5. Sinh vectơ khởi tạo (Mã hóa nhanh)

Các vectơ khởi tạo được dùng trong tất cả các trường hợp của mã hóa nhanh. Một vectơ khởi tạo phải được sinh theo phương thức sau, với H() là hàm băm giống như đã nêu ở mục 4.1.4 và một dấu "+" thể hiện sự móc nối:

1. Nếu một blockKey được cung cấp, đặt IV là băm của KeySalt và giá trị như sau:

blockKey:IV = H(KeySalt + blockKey)

2. Nếu blockKey không được cung cấp, đặt IV bằng giá trị như sau: KeySalt:IV = KeySalt.

3. Nếu số các byte trong giá trị của IV nhỏ hơn giá trị của thuộc tính

blockSize tương ứng với thuộc tính cipherAlgorithm, đệm thêm các byte 0x36 cho đến khi nó trở thành mảng các byte blockSize. Nếu số các byte đệm thêmlớn hơn các byte blockSizethì cắt bớt để thành các byte blockSize.

4.1.6. Sinh PasswordKeyEncryptor (Mã hóa nhanh)

Với mã hóa nhanh, thành tố XML mã hóa khóa mật khẩu phải được tạo như sau:

saltSize: Thiết lập thuộc tính này thành số các byte được dùng bởi dạng nhị phân của thuộc tính saltValue. Nó phải phù hợp với kiểu SaltSize.

51

blockSize: Thiết lập thuộc tính này thành số các byte cần để chứa một block đã mã hóa của dữ liệu, đã định nghĩa bởi cipherAlgorithm. Nó phải phù hợp với kiểuBlockSize.

keyBits: Thiết lập thuộc tính này thành số các bit cần để chứa khóa mã, đã định nghĩa bởi thành tố cipherAlgorithm. Nó phải phù hợp với kiểu KeyBits.

hashSize: Thiết lập thuộc tính này thành số các byte cần để chứa đầu ra của thuật toán băm đã định nghĩa bởi thành tố hashAlgorithm. Nó phải phù hợp với kiểu HashSize.

cipherAlgorithm: Thiết lập thuộc tính này thành một chuỗi ký tự chứa thuật toán mật mã dùng để mã hóa encryptedVerifierHashInput,

encryptedVerifierHashValueencryptedKeyValue. Nó phải phù hợp với kiểu

CipherAlgorithm.

cipherChaining: Thiết lập thuộc tính này thành chế độ móc nối mật mã dùng để mã hóa encryptedVerifierHashInput, encryptedVerifierHashValue và (adsbygoogle = window.adsbygoogle || []).push({});

encryptedKeyValue. Nó phải phù hợp với kiểu CipherChaining.

hashAlgorithm: Thiết lập thuộc tính này thành thuật toán băm dùng để lấy khóa mã từ mật khẩu và nó cũng dùng để thu encryptedVerifierHashValue. Nó phải phù hợp với kiểu HashAlgorithm.

saltValue: Thiết lập thuộc tính này thành mã base 64, sinh một cách ngẫu nhiên mảng các byte. Nó phải phù hợp với kiểu SaltValue. Số các byte được yêu cầu bởi dạng giải mã của thành tố này phải là saltSize.

spinCount: Thiết lập thuộc tính này thành số lần lặp băm mật khẩu khi tạo khóa được sử dụng để mã hóa encryptedVerifierHashInput,

encryptedVerifierHashValueencryptedKeyValue. Nó phải phù hợp với kiểu

SpinCount.

encryptedVerifierHashInput: Thuộc tính này phải được sinh theo các bước sau:

1. Sinh ngẫu nhiên một mảng với các byte được dùng chỉ định bởi thuộc tính saltSize.

2. Sinh một khóa mã bằng mật khẩu người dung cung cấp, mảng các byte nhị phân dùng để tạo thuộc tính saltSize, và một mảng các byte

blockKey bao gồm các byte sau: 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e và 0x79.

3. Mã hóa mảng ngẫu nhiên các byte được sinh ở bước 1 bằng cách dùng dạng nhị phân của thuộc tính saltValue như một vectơ khởi tạo, đã nêu ở mục 4.1.5. Nếu mảng các byte không phải là bội số nguyên của các byte blockSize, thì đệm mảng với 0x00 để thành bội số nguyên tiếp theo của các byte blockSize.

52

4. Sử dụng base 64 để mã hóa kết quả ở bước 3.

encryptedVerifierHashValue: Thuộc tính này phải được sinh theo các bước sau:

1. Thu thập giá trị băm của mảng các byte ngẫu nhiên được sinh ở bước 1 của các bước sinh encryptedVerifierHashInput.

2. Sinh một khóa mã như đã nêu ở mục 4.1.4 bằng mật khẩu do người dùng cung cấp, mảng các byte nhị phân dùng để tạo thuộc tính

saltValue, và một mảng byte blockKey bao gồm các byte sau: 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34 và 0x4e.

3. Mã hóa giá trị băm thu được ở bước 1 bằng cách dùng dạng nhị phân của thuộc tính saltValue như một vectơ khởi tạo như đã nêu ở mục 4.1.5. Nếu hashSize không phải là bội số nguyên của các byte

blockSize, thì đệm giá trị băm với 0x00 để thành một bội số nguyên của các byte blockSize.

4. Sử dụng base 64 để mã hóa kết quả ở bước 3.

encryptedKeyValue: Thuộc tính này phải được sinh theo các bước sau: 1. Sinh một mảng ngẫu nhiên các byte mà có cùng kích thước như đã chỉ

ra bởi thuộc tính Encryptor.KeyData.keyBits của thành tố cha. 2. Sinh một khóa mã như đã nêu ở mục 4.1.4, sử dụng mật khẩu do

người dùng cung cấp, mảng các byte nhị phân dùng để tạo thuộc tính

saltValue, và một mảng byte blockKey bao gồm các byte sau: 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0 và 0xd6.

3. Mã hóa mảng ngẫu nhiên các byte được sinh ở bước 1 bằng cách dùng dạng nhị phân của thuộc tính saltValue như một vectơ khởi tạo, đã nêu ở mục 4.1.5. Nếu mảng các byte không phải là bội số nguyên của

Một phần của tài liệu Thám mật khẩu các file word (Trang 44)