# **TASK 3** # Lý thuyết ## DES ### Khái niệm DES (Data Encryption Standard) là một thuật toán mã hóa khóa đối xứng được phát triển bởi IBM vào những năm 1970 và sau đó được chính phủ Mỹ chấp nhận làm tiêu chuẩn mã hóa vào năm 1977. DES là một thuật toán mã hóa khối, có nghĩa là nó mã hóa dữ liệu thành các khối có kích thước cố định là 64 bit. ### Khóa của DES Kích thước khóa cho DES là 56 bit, có nghĩa là có 2^56 khóa có thể được sử dụng để mã hóa và giải mã dữ liệu. Khóa được tạo ra bằng cách lấy một khóa 64 bit ban đầu được cung cấp bởi người dùng hoặc hệ thống, và sau đó áp dụng một hoán vị gọi là "parity drop" để loại bỏ mỗi bit thứ tám từ khóa. Điều này dẫn đến một khóa 56 bit được sử dụng trong quá trình mã hóa DES. Khóa được coi là một thành phần quan trọng của bảo mật của thuật toán DES, vì nó được sử dụng để xác định chuỗi duy nhất các phép toán toán học chuyển đổi plaintext đầu vào thành ciphertext đã được mã hóa. Nếu không có khóa đúng, thì hầu như không thể đảo ngược quá trình này và khôi phục lại plaintext ban đầu từ ciphertext đã được mã hóa. Tuy nhiên, do sự tiến bộ về sức mạnh tính toán, DES không còn được coi là một thuật toán mã hóa an toàn trên riêng nó. #### Khóa yếu Có nhiều khóa được xem là khóa yếu trong thuật toán DES, đó là các khóa dễ có khả năng bị đối tượng phá khóa do một số bít của khóa lặp lại và dễ dự đoán trước. Việc sử dụng khóa yếu có thể làm giảm tính bảo mật của DES, do đó tránh sử dụng các khóa yếu này. Cụ thể các khóa yếu là: - 01010101 01010101 - FEFEFEFE FEFEFEFE - E0E0E0E0 F1F1F1F1 - 1F1F1F1F 0E0E0E0E ### Thuộc tính của DES - Hiệu ứng tuyết lở - Khi đầu vào thay đổi một chút (thậm chí bằng 1 bit), đầu ra có một sự thay đổi đáng kể (gần một nửa số bit đầu ra thay đổi). - Tính đầy đủ - Khi mỗi bit đầu ra phụ thuộc vào nhiều bit của đầu vào. ### Các bước hoạt động DES hoạt động theo các bước sau: 1. Ban đầu, khối plaintext 64 bit sẽ trải qua một bước hoán vị ban đầu IP(Initial Permutation), nơi các bit của plaintext được xáo trộn theo một cách cụ thể. Bước hoán vị ban đầu này được thực hiện để giúp tăng cường độ dài của chuỗi plaintext và tạo ra các bit khác nhau để các vòng lặp sau này có thể hoạt động hiệu quả hơn. 2. Sau đó, khối plaintext được chia thành hai khối con bằng nhau 32 bit (L0 và R0). 3. Tiếp theo, ta thực hiện 16 vòng lặp (rounds) theo cùng một cấu trúc. Với mỗi vòng lặp, khối R của vòng trước được sử dụng để tạo ra khối R mới và khối L của vòng trước được sử dụng để tạo ra khối L mới. 4. Trong mỗi vòng lặp, khối R sẽ trải qua một bước hoán vị mở rộng (Expansion Permutation) để tăng độ dài của khối R từ 32 bit lên 48 bit. 5. Tiếp theo, khóa chính của DES (K) được sử dụng để tạo ra một khóa con 48 bit tương ứng với vòng lặp hiện tại. Khóa K được chia thành 16 khóa con 48 bit (K1, K2, ..., K16) trước khi bắt đầu mã hóa. 6. Khối R 48 bit và khóa con 48 bit được thực hiện phép XOR với nhau. 7. Sau đó, khối 48 bit sẽ được chia thành tám khối con 6 bit. Mỗi khối con này được đưa qua một hộp S (S-box), được sử dụng để thực hiện một phép hoán vị, dịch bit và lựa chọn bit để tạo ra một khối con 4 bit mới. 8. Tám khối con 4 bit mới được ghép lại thành một khối 32 bit và trải qua một bước hoán vị khối 32 bit (P-box permutation). 9. Khối 32 bit mới được tạo ra bằng phép XOR giữa khối L của vòng trước và khối 32 bit mới tạo ra trong vòng lặp hiện tại. 10. Cuối cùng, khối L và khối R của vòng trước được đổi chỗ để chuẩn bị cho vòng lặp tiếp theo. 11. Sau khi hoàn tất 16 vòng lặp, hai khối con 32 bit sẽ được ghép lại theo thứ tự ngược lại và trải qua một bước hoán vị cuối cùng 12. Bước hoán vị cuối (Final Permutation) là bước cuối cùng trong quá trình mã hóa. Bước hoán vị cuối này được sử dụng để trộn các bit của hai khối con đã được ghép lại sau khi hoàn tất 16 vòng lặp. Bước hoán vị cuối này tạo ra khối ciphertext 64 bit. 13. Cuối cùng, khối ciphertext 64 bit được trả về là kết quả của quá trình mã hóa. Vì DES sử dụng khối plaintext có độ dài 64 bit, việc mã hóa các khối dữ liệu có độ dài khác 64 bit sẽ được thực hiện thông qua một số phương pháp như chia nhỏ các khối dữ liệu hoặc sử dụng chế độ mã hóa khối (block cipher mode). Hình ảnh minh họa: ![](https://i.imgur.com/4HjJ27n.png) Để giải mã ciphertext, quá trình trên sẽ được thực hiện ngược lại với việc sử dụng các khóa con theo thứ tự ngược lại. ### Điểm yếu Một trong những điểm yếu của DES là kích thước khóa nhỏ, dẫn đến việc dễ bị tấn công bằng phương pháp tấn công brute-force. Tấn công brute-force bao gồm thử tất cả các khóa có thể cho đến khi tìm thấy khóa đúng. Với kích thước khóa là 56 bit, chỉ có 2^56 khóa có thể được sử dụng, và chúng có thể được tìm kiếm trong một khoảng thời gian tương đối ngắn bằng cách sử dụng công nghệ tính toán hiện đại. Để giải quyết điểm yếu này, Triple DES (3DES) đã được phát triển như một cải tiến cho DES. 3DES sử dụng ba vòng DES với hai hoặc ba khóa để cung cấp một mức độ bảo mật mạnh hơn nhiều. Nó vẫn được sử dụng trong một số hệ thống cũ, nhưng cũng đã được thay thế phần lớn bởi AES. ### Nhận xét DES đã được sử dụng rộng rãi trong các ứng dụng khác nhau, bao gồm các hệ thống thanh toán điện tử, truyền thông trực tuyến và mã hóa tệp. Mặc dù có điểm yếu, nhưng nó được coi là một thuật toán mã hóa rất an toàn khi được phát triển lần đầu và được sử dụng rộng rãi trong nhiều năm. Ảnh hưởng của nó đến mật mã học hiện đại vẫn có thể thấy trong sự phát triển của các thuật toán mã hóa khác được phát triển sau đó. ## Triple DES ### Khái niệm 3DES (Triple DES) là một phiên bản được cải tiến của thuật toán mã hóa DES ban đầu cung cấp độ bảo mật cải thiện bằng cách sử dụng nhiều vòng mã hóa và độ dài khóa dài hơn. 3DES là một thuật toán mã hóa đối xứng, có nghĩa là cùng một khóa được sử dụng cho cả mã hóa và giải mã. Thuật toán 3DES sử dụng một nhóm khóa bao gồm 03 khóa DES K1, K2 và K3, mỗi khóa có giá trị 56 bít. ### Mã hóa $Ciphertext$ = $E_{K3}(D_{K2}(E_{K1}(Plaintext)))$ Trước tiên, thực hiện mã hóa DES với khóa $K1$, tiếp tục giải mã DES với khóa $K2$ và cuối cùng mã hóa DES với khóa $K3$ (E – Encryption: quá trình mã hóa; D - Decryption: quá trình giải mã; Plaintext: Dữ liệu đầu vào của phép mã hóa hoặc dữ liệu đầu ra của phép giải mã; Ciphertext: Dữ liệu đầu ra của phép mã hóa hoặc dữ liệu đầu vào của phép giải mã). ### Giải mã $Plaintext$ = $D_{K1}(E_{K2}(D_{K3}(Ciphertext))$ Quá trình giải mã với việc giải mã với khóa K3, sau đó mã hóa với khóa K2, và cuối cùng giải mã với khóa K1.. 3DES mã hóa một khối dữ liệu có giá trị 64 bít (bản rõ) thành một khối dữ liệu mới có giá trị 64 bít (bản mã). Các tiêu chuẩn chỉ ra phương thức lựa chọn nhóm khóa (K1, K2, K3) như sau: 1) Lựa chọn 1: K1, K2, K3 là các khóa độc lập 2) Lựa chọn 2: K1, K2 là hai khóa độc lập và K3 = K1 3) Lựa chọn 3: K1=K2=K3 Lựa chọn 1 là phương thức mã hóa mạnh nhất với 168 bít khóa độc lập (168=3x56). Lựa chọn 2 ít bảo mật hơn với 112 bít khóa ( 2x56=112 bít) và lựa chọn 3 chỉ tương đương với việc mã hóa DES 1 lần với 56 bít khóa. Mỗi khóa DES thông thường được lưu trữ và truyền đi trong 8 byte, vì vậy một nhóm khóa yêu cầu 8 hoặc 16, 24 byte cho việc lưu trữ khóa. ### Yêu cầu lưu trữ khóa Đối với một khóa riêng lẻ hay một nhóm khóa gồm 03 khóa sẽ phải: - Đảm bảo duy trì tính bảo mật; - Việc cấp phát khóa sử dụng một phương pháp đã được chấp thuận dựa trên việc sinh khóa ngẫu nhiên; - Nhóm khóa độc lập với các nhóm khóa khác; - Phải có tính toàn vẹn do mỗi khóa trong nhóm khóa không thể thay đổi theo thời gian trong quá trình sinh phát khóa, truyền tải và lưu trữ khóa; - Sử dụng một cách tuần tự theo thứ tự xác định trước; - Số lượng khóa là cố định với mỗi khóa đơn lẻ không thể làm sai lệch. Một số cặp khóa yếu nên tránh sử dụng: - 011F011F010E010E và 1F011F010E010E01 - 01E001E001F101F1 và E001E001F101F101 - 01FE01FE01FE01FE và FE01FE01FE01FE01 - 1FE01FE00EF10EF1 và E01FE01FF10EF10E - 1FFE1FFE0EFE0EFE và FE1FFE1FFE0EFE0E Ngoài ra còn có 48 khóa được coi là “có thể yếu” nên hạn chế sử dụng: ``` 01011F1F01010E0E 1F1F01010E0E0101 E0E01F1FF1F10E0E 0101E0E00101F1F1 1F1FE0E00E0EF1F1 E0E0FEFEF1F1FEFE 0101FEFE0101FEFE 1F1FFEFE0E0EFEFE E0FE011FF1FE010E 011F1F01010E0E01 1FE001FE0EF101FE E0FE1F01F1FE0E01 011FE0FE010EF1FE 1FE0E01F0EF1F10E E0FEFEE0F1FEFEF1 011FFEE0010EFEF1 1FE0FE010EF1FE01 FE0101FEFE0101FE 01E01FFE01F10EFE 1FFE01E00EFE01F1 FE011FE0FE010EF1 FE01E01FFE01F10E 1FFEE0010EFEF101 FE1F01E0FE0E01F1 01E0E00101F1F101 1FFEFE1F0EFEFE0E FE1FE001FE0EF101 01E0FE1F01F1FE0E E00101E0F10101F1 FE1F1FFEFE0E0EFE 01FE1FE001FE0EF1 E0011FFEF1010EFE FEE0011FFEF1010E 01FEE01F01FEF10E E001FE1FF101FE0E FEE01F01FEF10E01 01FEFE0101FEFE01 E01F01FEF10E01FE FEE0E0FEFEF1F1FE 1F01011F0E01010E E01F1FE0F10E0EF1 FEFE0101FEFE0101 1F01E0FE0E01F1FE E01FFE01F10EFE01 FEFE1F1FFEFE0E0E 1F01FEE00E01FEF1 E0E00101F1F10101 FEFEE0E0FEFEF1F1 ``` ### Nhận xét 3DES được coi là an toàn hơn so với thuật toán DES ban đầu, do ít dễ bị tấn công bằng brute-force. Tuy nhiên, 3DES cũng chậm hơn và tốn nhiều tài nguyên hơn so với thuật toán DES ban đầu do số vòng mã hóa và độ dài khóa tăng lên. Do đó, 3DES đã phần lớn được thay thế bởi các thuật toán mã hóa hiện đại hơn như AES, cung cấp độ bảo mật tương đương hoặc tốt hơn với hiệu suất nhanh hơn. ## AES ### Khái niệm AES (Advanced Encryption Standard) là một thuật toán mã hóa đối xứng được sử dụng rộng rãi trong bảo mật thông tin và truyền thông. AES được coi là một trong những thuật toán mã hóa đối xứng an toàn nhất và hiệu quả nhất hiện nay.AES đã được chính phủ Hoa Kỳ sử dụng trong việc bảo vệ thông tin nhạy cảm và được sử dụng rộng rãi trong các ứng dụng bảo mật khác nhau, bao gồm bảo vệ thông tin cá nhân trên Internet và các thiết bị di động. ### Đặc điểm Các đặc điểm của AES (Advanced Encryption Standard) bao gồm: - Mã hóa đối xứng: AES là một thuật toán mã hóa đối xứng, có nghĩa là nó sử dụng cùng một khóa để mã hóa và giải mã dữ liệu. - Khóa có độ dài khác nhau: AES hỗ trợ 3 loại khóa có độ dài khác nhau là 128 bit, 192 bit và 256 bit, tùy thuộc vào độ an toàn cần thiết và mục đích sử dụng. - Cấu trúc block cipher: AES sử dụng cấu trúc block cipher, có nghĩa là nó mã hóa dữ liệu theo các khối cố định có kích thước 128 bit. - Các vòng lặp mã hóa: AES sử dụng các vòng lặp mã hóa, mỗi vòng lặp được thực hiện trên một khối 128 bit của dữ liệu. - An toàn: AES được coi là một trong những thuật toán mã hóa đối xứng an toàn nhất và hiệu quả nhất hiện nay. - Hiệu suất tốt: AES có hiệu suất tốt với các bộ vi xử lý hiện đại và có thể được sử dụng để mã hóa và giải mã dữ liệu một cách nhanh chóng. - Sử dụng rộng rãi: AES được sử dụng rộng rãi trong bảo mật thông tin và truyền thông, bao gồm bảo vệ thông tin cá nhân trên Internet và các thiết bị di động, cũng như các ứng dụng bảo mật khác. ### Hoạt động #### Mã hóa **Chuẩn bị khóa**: Mã hóa AES sử dụng khóa có độ dài khác nhau để mã hóa dữ liệu. Trước khi mã hóa dữ liệu, khóa sẽ được chuẩn bị. Nếu khóa có độ dài 128 bit, nó sẽ được chia thành 4 `words`, mỗi `word` có độ dài 32 bit. Nếu khóa có độ dài 192 bit, nó sẽ được chia thành 6 `words`, mỗi từ có độ dài 32 bit. Nếu khóa có độ dài 256 bit, nó sẽ được chia thành 8 `words`, mỗi từ có độ dài 32 bit. **Dưới đây là giai đoạn mã hóa:** 1. Key expansion: Thuật toán AES lấy khóa mã hóa và mở rộng nó thành một tập hợp các `round key`, một khóa cho mỗi vòng của quy trình mã hóa.(Ví dụ từ khóa 128 bit tạo ra 11 `round key`) 2. Initial round: Thuật toán thực hiện một vòng thao tác đầu tiên theo thứ tự bao gồm a. AddRoundKey: `round key` đầu tiên được XOR với `plaintext`(bản rõ). b.Sau đó thực hiện 1 vòng đầu tiên gồm:`SubBytes`,`ShiftRows`,`MixColums`,`AddRoundKey` 3. Rounds: Sau đó, thuật toán thực hiện một tập hợp các vòng lặp, số vòng lặp phụ thuộc vào kích thước khóa.Đối với AES-128, có 10 vòng lặp,AES-192 có 12 vòng lặp,AES-256 có 14 vòng lặp (tính cả vòng ở bước 2). Mỗi vòng lặp bao gồm các hoạt động sau: a. `SubBytes`: Các byte của `state` được thay thế bằng bảng thay thế được gọi là `s_box`. ![](https://i.imgur.com/OHjZFlW.png) b. `ShiftRows`: Các hàng của `state` được dịch chuyển theo chu kỳ bằng một độ lệch nhất định. ![](https://i.imgur.com/9M7RycA.png) c. `MixColums`: Các cột của `state` được nhân với một ma trận cố định. ![](https://i.imgur.com/ip0O9n8.png) d. `AddRoundKey`: `round key` được XOR với `state` hiện tại. ![](https://i.imgur.com/1V3bdCZ.png) 4. Final round: Thuật toán thực hiện một vòng cuối cùng, bao gồm các thao tác sau(Bỏ qua `MixColums`): a. `SubBytes` b. `ShiftRows` c. `AddRoundKey` 5. Output: Bản mã 128/192/256-bit kết quả là đầu ra của quá trình mã hóa. #### Giải mã Để giải mã bản mã, quy trình về cơ bản giống như vậy nhưng theo thứ tự ngược lại. Đầu tiên, bản mã được biến đổi bằng cách sử dụng nghịch đảo của các thao tác vòng cuối cùng, sau đó mỗi vòng được thực hiện theo thứ tự ngược lại, sử dụng các khóa con giống như trong quy trình mã hóa nhưng theo thứ tự ngược lại. `Round key` ban đầu được thêm vào cuối để tạo ra bản rõ ban đầu. ![](https://i.imgur.com/pxJBSRu.png) ### Điểm yếu AES là một trong những thuật toán mã hóa phổ biến và được sử dụng rộng rãi, tuy nhiên nó cũng có một số điểm yếu như sau: - Đòi hỏi khối dữ liệu đầu vào phải có kích thước cố định: AES là một thuật toán mã hóa khối, nghĩa là nó mã hóa dữ liệu từng khối và yêu cầu kích thước khối dữ liệu phải cố định. Vì vậy, khi dữ liệu đầu vào không có kích thước khối cố định, cần phải sử dụng chế độ hoạt động phù hợp để điều chỉnh kích thước đầu vào, điều này có thể làm giảm hiệu suất hoặc làm tăng độ phức tạp của hệ thống. - Khả năng tấn công brute-force: Dù AES có khóa 128-bit, 192-bit hoặc 256-bit nhưng nếu bị tấn công brute-force, các khóa này đều có thể bị phá vỡ nếu kẻ tấn công có đủ thời gian và tài nguyên. - Có thể bị tấn công bằng side-channel: Kẻ tấn công có thể sử dụng các thông tin phụ như thời gian thực hiện, công suất tiêu thụ, tần số điện áp hoặc tia X để xác định khóa. - Khả năng bị tấn công bằng mã độc: Một số phần mềm độc hại có thể tấn công AES bằng cách truy cập vào bộ nhớ hoặc hệ thống để trộm khóa và dữ liệu đã được mã hóa. - Không thể chống lại tấn công về mặt logic: AES là một thuật toán mã hóa và không thể phát hiện được nếu dữ liệu đầu vào đã bị thay đổi bởi kẻ tấn công trước khi mã hóa. ### Nhận xét AES là một trong những thuật toán mã hóa đối xứng phổ biến nhất hiện nay. Nó có nhiều ưu điểm, bao gồm tính bảo mật cao, tốc độ xử lý nhanh, khả năng sử dụng trên nhiều nền tảng và hỗ trợ cho các khóa có độ dài lên đến 256 bit. Tuy nhiên, nhược điểm của AES là nó có thể bị tấn công bằng các phương pháp như tấn công dựa trên khóa và tấn công bằng phương pháp phân tích dữ liệu. Để đảm bảo an toàn cho hệ thống mã hóa, các chuyên gia bảo mật khuyên nên sử dụng các phiên bản AES mới nhất và sử dụng các phương pháp mã hóa hiện đại nhất để tăng cường tính bảo mật. ## PKCS7 Padding PKCS7 Padding (Padding Cryptographic Standard #7) là một phương pháp đệm dữ liệu được sử dụng trong các thuật toán mã hóa khối như AES, DES, RSA và Blowfish để thêm vào một số byte ở cuối dữ liệu để đảm bảo rằng kích thước của dữ liệu đầu vào phù hợp với kích thước của khối mã hóa. PKCS7 Padding hoạt động bằng cách thêm vào các byte có giá trị bằng với số byte còn thiếu trong khối để đạt được kích thước mong muốn. Ví dụ, nếu kích thước khối mã hóa là 8 byte và dữ liệu cần được mã hóa chỉ có 5 byte, thì 3 byte giá trị 03 sẽ được thêm vào cuối dữ liệu để đủ 8 byte. Nếu dữ liệu cần được mã hóa đã có đúng kích thước của khối mã hóa, thì không có byte đệm nào được thêm vào. PKCS7 Padding được sử dụng rộng rãi trong các ứng dụng bảo mật, đặc biệt là khi sử dụng các thuật toán mã hóa khối có độ dài khối như AES và DES. ## Block cipher modes of operation Block cipher modes of operation: Các chế độ hoạt động của mật mã khối đề cập đến các cách khác nhau trong đó mật mã khối, chẳng hạn như AES hoặc DES, có thể được sử dụng để mã hóa dữ liệu lớn hơn một khối. Các chế độ này xác định cách dữ liệu đầu vào được chia thành các khối, cách mỗi khối được mã hóa bằng cách sử dụng mật mã khối và cách các khối được mã hóa được kết hợp để tạo ra bản mã cuối cùng `ciphertext`. Có một số chế độ hoạt động cho mật mã khối, bao gồm: - Electronic Codebook (ECB): Trong chế độ ECB, mỗi khối văn bản gốc được mã hóa độc lập bằng cách sử dụng mật mã khối. Điều này có nghĩa là các khối bản rõ giống hệt nhau sẽ dẫn đến các khối bản mã giống hệt nhau. Chế độ ECB không an toàn để mã hóa lượng lớn dữ liệu hoặc mã hóa dữ liệu với các mẫu có thể dự đoán được. - Cipher Block Chaining (CBC): Trong chế độ CBC, mỗi khối bản rõ được XOR với khối bản mã trước đó trước khi mã hóa. Điều này giúp đảm bảo rằng các khối bản rõ giống hệt nhau không dẫn đến các khối bản mã giống hệt nhau. Chế độ CBC an toàn hơn chế độ ECB, nhưng nó có thể dễ bị tấn công nhất định, chẳng hạn như `padding oracle attacks`. - Cipher Feedback (CFB): Trong chế độ CFB, đầu ra của mật mã khối được XOR với bản rõ để tạo ra bản mã. Đầu ra của mật mã khối sau đó được đưa trở lại quy trình mã hóa để mã hóa khối văn bản gốc tiếp theo. Chế độ CFB tương tự như chế độ CBC, nhưng nó có thể được sử dụng để mã hóa dữ liệu trong thời gian thực. - Output Feedback (OFB): Trong chế độ OFB, mật mã khối được sử dụng để tạo ra một dòng khóa, dòng khóa này được XOR với bản rõ để tạo ra bản mã. Dòng khóa được tạo độc lập với bản rõ, vì vậy chế độ OFB không dễ bị `certain attacks` có thể được sử dụng để chống lại chế độ CBC. - Counter (CTR): Trong chế độ CTR, một bộ đếm được sử dụng để tạo ra một dòng khóa, được XOR với bản rõ để tạo ra bản mã. Chế độ CTR tương tự như chế độ OFB, nhưng nó có thể được sử dụng để mã hóa dữ liệu song song, điều này có thể cải thiện hiệu suất. Mỗi chế độ hoạt động đều có điểm mạnh và điểm yếu riêng, việc lựa chọn chế độ nào sẽ phụ thuộc vào yêu cầu cụ thể của ứng dụng. ## Meet in the middle với 2DES "Meet-in-the-middle" là một kỹ thuật tấn công được sử dụng để giảm đáng kể số lượng khóa có thể phải thử khi tấn công một hệ mã hóa. Đây là một phương pháp tấn công hiệu quả đối với các hệ mã hóa sử dụng khối mã hóa với khóa ngắn. Trong trường hợp của 2DES, "Meet-in-the-middle" sử dụng kỹ thuật phân tích tương tự để giảm số lượng khóa cần phải thử xuống còn 2^57^, đây là một con số có thể xử lý được với các phương tiện tính toán hiện đại. Tuy nhiên, để thực hiện tấn công "Meet-in-the-middle" đòi hỏi việc lưu trữ một lượng dữ liệu lớn tại hai vị trí khác nhau của hệ thống, do đó sẽ cần một lượng bộ nhớ lớn để thực hiện tấn công này. Cuộc tấn công bao gồm hai giai đoạn: - Giai đoạn tiền tính toán: Kẻ tấn công tạo ra một bảng chứa tất cả các tổ hợp có thể có của khóa đầu tiên và bản mã tương ứng, kết quả từ việc mã hóa bản rõ bằng khóa đầu tiên. - Giai đoạn tấn công: Kẻ tấn công mã hóa cùng một bản rõ với tất cả các tổ hợp có thể có của khóa thứ hai và so sánh bản mã kết quả với bảng được tạo trong giai đoạn đầu tiên. Khi tìm thấy một kết quả phù hợp, các khóa tương ứng là những khóa chính xác. Bằng cách sử dụng phương pháp này, kẻ tấn công giảm không gian tìm kiếm của các khóa từ 2^112^ xuống 2^56^+2^56^ = 2^57^, nhanh hơn đáng kể so với tấn công vét cạn. Cuộc tấn công này còn được gọi là cuộc tấn công "double-DES", vì nó liên quan đến việc khai thác việc sử dụng hai thao tác DES với các khóa khác nhau. # CryptoHack - SYMMETRIC CIPHERS ## HOW AES WORKS ### Keyed Permutations ``` AES, like all good block ciphers, performs a "keyed permutation". This means that it maps every possible input block to a unique output block, with a key determining which permutation to perform. A "block" just refers to a fixed number of bits or bytes, which may represent any kind of data. AES processes a block and outputs another block. We'll be specifically talking the variant of AES which works on 128 bit (16 byte) blocks and a 128 bit key, known as AES-128. Using the same key, the permutation can be performed in reverse, mapping the output block back to the original input block. It is important that there is a one-to-one correspondence between input and output blocks, otherwise we wouldn't be able to rely on the ciphertext to decrypt back to the same plaintext we started with. What is the mathematical term for a one-to-one correspondence? ``` Flag: `bijection` ### Resisting Bruteforce ``` If a block cipher is secure, there should be no way for an attacker to distinguish the output of AES from a random permutation of bits. Furthermore, there should be no better way to undo the permutation than simply bruteforcing every possible key. That's why academics consider a cipher theoretically "broken" if they can find an attack that takes fewer steps to perform than bruteforcing the key, even if that attack is practically infeasible. How difficult is it to bruteforce a 128-bit keyspace? Somebody estimated that if you turned the power of the entire Bitcoin mining network against an AES-128 key, it would take over a hundred times the age of the universe to crack the key. It turns out that there is an attack on AES that's better than bruteforce, but only slightly – it lowers the security level of AES-128 down to 126.1 bits, and hasn't been improved on for over 8 years. Given the large "security margin" provided by 128 bits, and the lack of improvements despite extensive study, it's not considered a credible risk to the security of AES. But yes, in a very narrow sense, it "breaks" AES. Finally, while quantum computers have the potential to completely break popular public-key cryptosystems like RSA via Shor's algorithm, they are thought to only cut in half the security level of symmetric cryptosystems via Grover's algorithm. This is one reason why people recommend using AES-256, despite it being less performant, as it would still provide a very adequate 128 bits of security in a quantum future. What is the name for the best single-key attack against AES? ``` Flag: `crypto{biclique}` ### Structure of AES Challenge cho file [matrix.py](https://cryptohack.org/static/challenges/matrix_e1b463dddbee6d17959618cf370ff1a5.py) ```python def bytes2matrix(text): """ Converts a 16-byte array into a 4x4 matrix. """ return [list(text[i:i+4]) for i in range(0, len(text), 4)] def matrix2bytes(matrix): """ Converts a 4x4 matrix into a 16-byte array. """ ???? matrix = [ [99, 114, 121, 112], [116, 111, 123, 105], [110, 109, 97, 116], [114, 105, 120, 125], ] print(matrix2bytes(matrix)) ``` Để lấy được flag ta cần viết nốt hàm `matrix2bytes()` ```python def matrix2bytes(matrix): return bytes(sum(matrix, [])) ``` Flag: `crypto{inmatrix}` ### Round Keys Challenge cho file [add_round_key.py](https://cryptohack.org/static/challenges/add_round_key_b67b9a529ae739156107a74b14adde98.py) ```python state = [ [206, 243, 61, 34], [171, 11, 93, 31], [16, 200, 91, 108], [150, 3, 194, 51], ] round_key = [ [173, 129, 68, 82], [223, 100, 38, 109], [32, 189, 53, 8], [253, 48, 187, 78], ] def add_round_key(s, k): ??? print(add_round_key(state, round_key)) ``` Ta cần viết nốt hàm `add_round_key()` sau đó dùng hàm `matrix2bytes()` ở bài trước để lấy flag.Trong hàm `add_round_key()` từng phần tử trong ma trận`state` sẽ được XOR với phần tử ở vị trí tương ứng trong ma trận `round_key` ![](https://i.imgur.com/1V3bdCZ.png) ```python state = [ [206, 243, 61, 34], [171, 11, 93, 31], [16, 200, 91, 108], [150, 3, 194, 51], ] round_key = [ [173, 129, 68, 82], [223, 100, 38, 109], [32, 189, 53, 8], [253, 48, 187, 78], ] def matrix_to_bytes(matrix): return bytes(sum(matrix, [])) def add_round_key(state, round_key): for i in range(len(state)): for j in range(len(state[0])): state[i][j] ^= round_key[i][j] return state print(matrix_to_bytes(add_round_key(state, round_key))) ``` Flag: crypto{r0undk3y} ### Confusion through Substitution Challenge cho file [sbox.py](https://cryptohack.org/static/challenges/sbox_8fc04ffb95faf5a5e6959195d5e2d94e.py) ```python s_box = ( 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16, ) inv_s_box = ( 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D, ) state = [ [251, 64, 182, 81], [146, 168, 33, 80], [199, 159, 195, 24], [64, 80, 182, 255], ] def sub_bytes(s, sbox=s_box): ??? print(sub_bytes(state, sbox=inv_s_box)) ``` Ta cần viết nốt hàm `sub_bytes()` sau đó truyền ma trận `state` , `inv_s_box` vào rồi chuyển ma trận nhận được thành bytes để lấy `flag`.Trong hàm `sub_bytes` từng phần tử của ma trận state được thay thế bằng giá trị tra cứu trong bảng `s_box` ![](https://i.imgur.com/PfIdmF3.png) ```python def sub_bytes(state, sbox=s_box): for i in range(len(state)): for j in range(len(state[i])): state[i][j] = sbox[state[i][j]] return state print(matrix_to_bytes(sub_bytes(state, sbox=inv_s_box))) ``` Flag: `crypto{l1n34rly}` ### Diffusion through Permutation Challenge cho file [diffusion.py](https://cryptohack.org/static/challenges/diffusion_ee6215282094b4ae8cd1b20697477712.py) ```python def shift_rows(s): s[0][1], s[1][1], s[2][1], s[3][1] = s[1][1], s[2][1], s[3][1], s[0][1] s[0][2], s[1][2], s[2][2], s[3][2] = s[2][2], s[3][2], s[0][2], s[1][2] s[0][3], s[1][3], s[2][3], s[3][3] = s[3][3], s[0][3], s[1][3], s[2][3] def inv_shift_rows(s): ??? # learned from http://cs.ucsb.edu/~koc/cs178/projects/JT/aes.c xtime = lambda a: (((a << 1) ^ 0x1B) & 0xFF) if (a & 0x80) else (a << 1) def mix_single_column(a): # see Sec 4.1.2 in The Design of Rijndael t = a[0] ^ a[1] ^ a[2] ^ a[3] u = a[0] a[0] ^= t ^ xtime(a[0] ^ a[1]) a[1] ^= t ^ xtime(a[1] ^ a[2]) a[2] ^= t ^ xtime(a[2] ^ a[3]) a[3] ^= t ^ xtime(a[3] ^ u) def mix_columns(s): for i in range(4): mix_single_column(s[i]) def inv_mix_columns(s): # see Sec 4.1.3 in The Design of Rijndael for i in range(4): u = xtime(xtime(s[i][0] ^ s[i][2])) v = xtime(xtime(s[i][1] ^ s[i][3])) s[i][0] ^= u s[i][1] ^= v s[i][2] ^= u s[i][3] ^= v mix_columns(s) state = [ [108, 106, 71, 86], [96, 62, 38, 72], [42, 184, 92, 209], [94, 79, 8, 54], ] ``` Đoạn mã còn trống hàm `inv_shift_rows()` để lấy được flag ta tiến hành chạy hàm `inv_mix_colums()` trước, sau đó chạy hàm `inv_shift_rows()` rồi chuyển ma trận nhận được sang bytes ```python def shift_rows(s): s[0][1], s[1][1], s[2][1], s[3][1] = s[1][1], s[2][1], s[3][1], s[0][1] s[0][2], s[1][2], s[2][2], s[3][2] = s[2][2], s[3][2], s[0][2], s[1][2] s[0][3], s[1][3], s[2][3], s[3][3] = s[3][3], s[0][3], s[1][3], s[2][3] return s def inv_shift_rows(s): s[1][1], s[2][1], s[3][1], s[0][1] = s[0][1], s[1][1], s[2][1], s[3][1] s[2][2], s[3][2], s[0][2], s[1][2] = s[0][2], s[1][2], s[2][2], s[3][2] s[3][3], s[0][3], s[1][3], s[2][3] = s[0][3], s[1][3], s[2][3], s[3][3] return s # learned from http://cs.ucsb.edu/~koc/cs178/projects/JT/aes.c xtime = lambda a: (((a << 1) ^ 0x1B) & 0xFF) if (a & 0x80) else (a << 1) def mix_single_column(a): # see Sec 4.1.2 in The Design of Rijndael t = a[0] ^ a[1] ^ a[2] ^ a[3] u = a[0] a[0] ^= t ^ xtime(a[0] ^ a[1]) a[1] ^= t ^ xtime(a[1] ^ a[2]) a[2] ^= t ^ xtime(a[2] ^ a[3]) a[3] ^= t ^ xtime(a[3] ^ u) def mix_columns(s): for i in range(4): mix_single_column(s[i]) def inv_mix_columns(s): # see Sec 4.1.3 in The Design of Rijndael for i in range(4): u = xtime(xtime(s[i][0] ^ s[i][2])) v = xtime(xtime(s[i][1] ^ s[i][3])) s[i][0] ^= u s[i][1] ^= v s[i][2] ^= u s[i][3] ^= v mix_columns(s) def matrix_to_bytes(matrix): return bytes(sum(matrix, [])) state = [ [108, 106, 71, 86], [96, 62, 38, 72], [42, 184, 92, 209], [94, 79, 8, 54], ] inv_mix_columns(state) print(matrix_to_bytes(inv_shift_rows(state))) ``` Flag: `crypto{d1ffUs3R}` ### Bringing It All Together Challenge cho 2 file [aes_decrypt.py](https://cryptohack.org/static/challenges/aes_decrypt_f491744105801ec03d6a6f7a0e7f8101.py) và [LICENSE](https://cryptohack.org/static/challenges/LICENSE_651b0602addd2b4bfa5d69ad7fca2dd5) aes_decrypt.py ```python N_ROUNDS = 10 key = b'\xc3,\\\xa6\xb5\x80^\x0c\xdb\x8d\xa5z*\xb6\xfe\\' ciphertext = b'\xd1O\x14j\xa4+O\xb6\xa1\xc4\x08B)\x8f\x12\xdd' def expand_key(master_key): """ Expands and returns a list of key matrices for the given master_key. """ # Round constants https://en.wikipedia.org/wiki/AES_key_schedule#Round_constants r_con = ( 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, 0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, 0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, 0x39, ) # Initialize round keys with raw key material. key_columns = bytes2matrix(master_key) iteration_size = len(master_key) // 4 # Each iteration has exactly as many columns as the key material. i = 1 while len(key_columns) < (N_ROUNDS + 1) * 4: # Copy previous word. word = list(key_columns[-1]) # Perform schedule_core once every "row". if len(key_columns) % iteration_size == 0: # Circular shift. word.append(word.pop(0)) # Map to S-BOX. word = [s_box[b] for b in word] # XOR with first byte of R-CON, since the others bytes of R-CON are 0. word[0] ^= r_con[i] i += 1 elif len(master_key) == 32 and len(key_columns) % iteration_size == 4: # Run word through S-box in the fourth iteration when using a # 256-bit key. word = [s_box[b] for b in word] # XOR with equivalent word from previous iteration. word = bytes(i^j for i, j in zip(word, key_columns[-iteration_size])) key_columns.append(word) # Group key words in 4x4 byte matrices. return [key_columns[4*i : 4*(i+1)] for i in range(len(key_columns) // 4)] def decrypt(key, ciphertext): round_keys = expand_key(key) # Remember to start from the last round key and work backwards through them when decrypting # Convert ciphertext to state matrix # Initial add round key step for i in range(N_ROUNDS - 1, 0, -1): pass # Do round # Run final round (skips the InvMixColumns step) # Convert state matrix to plaintext return plaintext # print(decrypt(key, ciphertext)) ``` Ở challenge này là tổng hợp của các challenge bên trên ta tận dụng các hàm đã có ở trên để solve.Trình tự giải mã diễn ra như hình bên dưới ![](https://i.imgur.com/oy7uYRh.png) Đàu tiên chuyên `ciphertext` thành ma trận `state` sau đó `add_round_key` lần 1 với round_key cuối cùng là round_key[10] vì đây là AES - 128 bit .Tiếp theo là 9 vòng lặp gồm các bước `inv_shift_row`,`inv_sub_bytes`,`add_round_key` và `inv_mix_columns`.Cuối cùng chạy vòng cuối gồm `invShiftRows`,`invSubBytes`,`AddRoundKey` ```python import numpy as np from diffusion import inv_mix_columns,inv_shift_rows from sub_bytes import sub_bytes,s_box,inv_s_box,matrix_to_bytes,bytes2matrix,add_round_key N_ROUNDS = 10 key = b'\xc3,\\\xa6\xb5\x80^\x0c\xdb\x8d\xa5z*\xb6\xfe\\' ciphertext = b'\xd1O\x14j\xa4+O\xb6\xa1\xc4\x08B)\x8f\x12\xdd' def expand_key(master_key): """ Expands and returns a list of key matrices for the given master_key. """ # Round constants https://en.wikipedia.org/wiki/AES_key_schedule#Round_constants r_con = ( 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, 0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, 0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, 0x39, ) # Initialize round keys with raw key material. key_columns = bytes2matrix(master_key) iteration_size = len(master_key) // 4 # Each iteration has exactly as many columns as the key material. i = 1 while len(key_columns) < (N_ROUNDS + 1) * 4: # Copy previous word. word = list(key_columns[-1]) # Perform schedule_core once every "row". if len(key_columns) % iteration_size == 0: # Circular shift. word.append(word.pop(0)) # Map to S-BOX. word = [s_box[b] for b in word] # XOR with first byte of R-CON, since the others bytes of R-CON are 0. word[0] ^= r_con[i] i += 1 elif len(master_key) == 32 and len(key_columns) % iteration_size == 4: # Run word through S-box in the fourth iteration when using a # 256-bit key. word = [s_box[b] for b in word] # XOR with equivalent word from previous iteration. word = bytes(i^j for i, j in zip(word, key_columns[-iteration_size])) key_columns.append(word) # Group key words in 4x4 byte matrices. return [key_columns[4*i : 4*(i+1)] for i in range(len(key_columns) // 4)] def decrypt(key, ciphertext): round_keys = expand_key(key) # Remember to start from the last round key and work backwards through them when decrypting # Convert ciphertext to state matrix state = bytes2matrix(ciphertext) # Initial add round key step state = add_round_key(state,round_keys[10]) for i in range(N_ROUNDS - 1, 0, -1): pass # Do round inv_shift_rows(state) state = sub_bytes(state,inv_s_box) state = add_round_key(state, round_keys[i]) inv_mix_columns(state) # Run final round (skips the InvMixColumns step) inv_shift_rows(state) state = sub_bytes(state, inv_s_box) state = add_round_key(state, round_keys[0]) # Convert state matrix to plaintext plaintext = matrix_to_bytes(state) return plaintext print(decrypt(key, ciphertext)) ``` Flag: `crypto{MYAES128}` ## SYMMETRIC STARTER ### Modes of Operation Starter Challenge này chỉ giới thiệu về Modes of Operation https://aes.cryptohack.org/block_cipher_starter Đầu tiên click ENCRYPT_FLAG sau đó lấy ciphertext nhận được dán vào phần DECRYPT để giải mã : ![](https://i.imgur.com/dVri94l.png) Dán plaintext dạng hex vào decode hex bên dưới sẽ lấy được flag: ![](https://i.imgur.com/RMfk2Fk.png) Dưới đây là script bằng python: ```python import requests url = "https://aes.cryptohack.org/block_cipher_starter/" r = requests.get(url + 'encrypt_flag/') cipher_hex = r.json()['ciphertext'] print(cipher_hex) r = requests.get(url+'decrypt/'+cipher_hex) pt = r.json()['plaintext'] print(bytes.fromhex(pt)) ``` ### Passwords as Keys https://aes.cryptohack.org/passwords_as_keys/ ![](https://i.imgur.com/gnkxnEG.png) Đọc đoạn mã ta thấy `KEY` là mã băm của 1 từ được chọn ngẫu nhiên từ file [words](https://gist.githubusercontent.com/wchargin/8927565/raw/d9783627c731268fb2935a731a618aa8e95cf465/words) sau đó cipher được mã hóa theo mode ECB,để giải mã ta phải có `PASSWORD_HASH`. ```python from Crypto.Cipher import AES import requests import hashlib res = requests.get('https://aes.cryptohack.org/passwords_as_keys/encrypt_flag') ciphertext_hex = res.json()["ciphertext"] with open('words', 'r') as f: for word in f: word = word.strip() attempted_key = hashlib.md5(word.encode()).hexdigest() ciphertext = bytes.fromhex(ciphertext_hex) key = bytes.fromhex(attempted_key) cipher = AES.new(key, AES.MODE_ECB) try: decrypted = cipher.decrypt(ciphertext) result = bytes.fromhex(decrypted.hex()) if result.startswith('crypto{'.encode()): print("KEY : %s" % word) print(result.decode()) exit(0) except ValueError as e: continue ``` KEY : `bluebell` Flag: `crypto{k3y5__r__n07__p455w0rdz?}` ## BLOCK CIPHERS ### ECB CBC WTF https://aes.cryptohack.org/ecbcbcwtf SOURE ```python from Crypto.Cipher import AES KEY = ? FLAG = ? @chal.route('/ecbcbcwtf/decrypt/<ciphertext>/') def decrypt(ciphertext): ciphertext = bytes.fromhex(ciphertext) cipher = AES.new(KEY, AES.MODE_ECB) try: decrypted = cipher.decrypt(ciphertext) except ValueError as e: return {"error": str(e)} return {"plaintext": decrypted.hex()} @chal.route('/ecbcbcwtf/encrypt_flag/') def encrypt_flag(): iv = os.urandom(16) cipher = AES.new(KEY, AES.MODE_CBC, iv) encrypted = cipher.encrypt(FLAG.encode()) ciphertext = iv.hex() + encrypted.hex() return {"ciphertext": ciphertext} ``` Chế độ CBC lấy đầu ra từ khối trước đó và XOR nó với văn bản gốc. $ciphertext$ = $IV$ + $ciphertext_{real}$ IV dài 32 kí tự(16 byte) ,ciphertext mã hóa theo từng khối 32 kí tự Để lấy được flag ta tiến hành XOR từng khối 32 kí tự của ciphertext với từng khối plaintext decrypt bằng mode ECB ![](https://i.imgur.com/tgUxi1s.png) ```python import requests from pwn import xor def get_ciphertext(): url = "http://aes.cryptohack.org/ecbcbcwtf/encrypt_flag/" r = requests.get(url) data = r.json() ct = data['ciphertext'] return ct def decrypt_ecb(ct): url = "http://aes.cryptohack.org/ecbcbcwtf/decrypt/"+ct r = requests.get(url) data = r.json() pt = data['plaintext'] return pt ciphertext = get_ciphertext() split_ciphertext = [ciphertext[i:i+32] for i in range(0, len(ciphertext), 32)] # [0] is the IV, [1] and subsequent are the encryptions of the plaintext blocks. plaintext = [0]*(len(split_ciphertext) - 1) for i in range(len(plaintext)): pi = bytes.fromhex(decrypt_ecb(split_ciphertext[i+1])) ci = bytes.fromhex(split_ciphertext[i]) plaintext[i] = ''.join(map(chr, xor(pi, ci))) print(f"Flag: {''.join(plaintext)}") ``` Flag: `crypto{3cb_5uck5_4v01d_17_!!!!!}` ### ECB Oracle https://aes.cryptohack.org/ecb_oracle SOURCE ```python from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad KEY = ? FLAG = ? @chal.route('/ecb_oracle/encrypt/<plaintext>/') def encrypt(plaintext): plaintext = bytes.fromhex(plaintext) padded = pad(plaintext + FLAG.encode(), 16) cipher = AES.new(KEY, AES.MODE_ECB) try: encrypted = cipher.encrypt(padded) except ValueError as e: return {"error": str(e)} return {"ciphertext": encrypted.hex()} ``` Dưới đây là script brute-force attack vòng lặp while đoán từng kí tự tiếp theo và so sánh mã hex với cipher của payload nếu chính xác thì thêm kí tự đó vào flag.Tiếp tục như vậy đến khi khôi phục được flag Script ```python from binascii import hexlify import requests import json from string import printable def encrypt(pt): p = hexlify(pt).decode() url = "http://aes.cryptohack.org/ecb_oracle/encrypt/"+p r = requests.get(url) ct = (json.loads(r.text))['ciphertext'] return ct flag = "crypto{" n = 31 while 1: payload = b'1'*(n-len(flag)) comp = encrypt(payload) for i in printable: enc = encrypt(payload + flag.encode() + i.encode()) if comp[32:64] == enc[32:64]: flag += i print("flag letter: ", i) break if flag[-1] == '}': break print(flag) ``` Flag: `crypto{p3n6u1n5_h473_3cb}` ### Flipping Cookie https://aes.cryptohack.org/flipping_cookie/ ```python from Crypto.Cipher import AES import os from Crypto.Util.Padding import pad, unpad from datetime import datetime, timedelta KEY = ? FLAG = ? @chal.route('/flipping_cookie/check_admin/<cookie>/<iv>/') def check_admin(cookie, iv): cookie = bytes.fromhex(cookie) iv = bytes.fromhex(iv) try: cipher = AES.new(KEY, AES.MODE_CBC, iv) decrypted = cipher.decrypt(cookie) unpadded = unpad(decrypted, 16) except ValueError as e: return {"error": str(e)} if b"admin=True" in unpadded.split(b";"): return {"flag": FLAG} else: return {"error": "Only admin can read the flag"} @chal.route('/flipping_cookie/get_cookie/') def get_cookie(): expires_at = (datetime.today() + timedelta(days=1)).strftime("%s") cookie = f"admin=False;expiry={expires_at}".encode() iv = os.urandom(16) padded = pad(cookie, 16) cipher = AES.new(KEY, AES.MODE_CBC, iv) encrypted = cipher.encrypt(padded) ciphertext = iv.hex() + encrypted.hex() return {"cookie": ciphertext} ``` Đọc soure code ta thấy IV được random dài 32 kí tự (16byte) cookie được đệm thêm để dài bằng IV, sau đó được mang đi mã hóa. Hàm `check_admin()` kiểm tra "admin=True" mới trả về flag. IV là 32 kí tự đầu tiên của ciphertext Trong khối đầu tiên, pt = iv ^ dec, trong đó dec được giải mã khối đầu tiên Muốn thay đổi admin=False; thành admin=True;e IV^dec = False x^dec=True =>$IV_{new}$ = x = IV ^ False ^ True ![](https://i.imgur.com/eg3wVKE.png) c = `8b5f2c0cf68d40108e63a864fb8c18a8e53f4d0c467f2a4df25ef4f9345691a23e6790ea6a6291f7b78d51ace1a59d37` iv = c[:32] = `8b5f2c0cf68d40108e63a864fb8c18a8` ct = c[32:] = `e53f4d0c467f2a4df25ef4f9345691a23e6790ea6a6291f7b78d51ace1a59d37` 'admin=False;expi' to hex = False = `61646d696e3d46616c73653b65787069` 'admin=True;expir' to hex = True = `61646d696e3d547275653b6578706972` $IV_{new}$ = IV ^ False ^ True = `8b5f2c0cf68d52039775f63ae68401b3` ![](https://i.imgur.com/6GjJvrV.png) flag: `crypto{4u7h3n71c4710n_15_3553n714l}` Script.py ```python from Crypto.Util.number import * import requests import json from pwn import xor def get_ciphertext(): url = "http://aes.cryptohack.org/flipping_cookie/get_cookie/" r = requests.get(url) ct = (json.loads(r.text))['cookie'] return ct def check_cookie(cookie, iv): url = "http://aes.cryptohack.org/flipping_cookie/check_admin/"+cookie+"/"+iv r = requests.get(url) try: flag = (json.loads(r.text))['flag'] except: flag = (json.loads(r.text))['error'] return flag c = get_ciphertext() iv = bytes.fromhex((c[:32])) ct = c[32:] print("iv = %s" % iv.hex()) print("ct = %s" % ct) iv1 = xor(iv,b'admin=False',b'admin=True;').hex() print("iv1 = %s" % iv1) flag = check_cookie(ct, iv1) print(flag) ``` ### Lazy CBC https://aes.cryptohack.org/lazy_cbc/ SOURCE ```python from Crypto.Cipher import AES KEY = ? FLAG = ? @chal.route('/lazy_cbc/encrypt/<plaintext>/') def encrypt(plaintext): plaintext = bytes.fromhex(plaintext) if len(plaintext) % 16 != 0: return {"error": "Data length must be multiple of 16"} cipher = AES.new(KEY, AES.MODE_CBC, KEY) encrypted = cipher.encrypt(plaintext) return {"ciphertext": encrypted.hex()} @chal.route('/lazy_cbc/get_flag/<key>/') def get_flag(key): key = bytes.fromhex(key) if key == KEY: return {"plaintext": FLAG.encode().hex()} else: return {"error": "invalid key"} @chal.route('/lazy_cbc/receive/<ciphertext>/') def receive(ciphertext): ciphertext = bytes.fromhex(ciphertext) if len(ciphertext) % 16 != 0: return {"error": "Data length must be multiple of 16"} cipher = AES.new(KEY, AES.MODE_CBC, KEY) decrypted = cipher.decrypt(ciphertext) try: decrypted.decode() # ensure plaintext is valid ascii except UnicodeDecodeError: return {"error": "Invalid plaintext: " + decrypted.hex()} return {"success": "Your message has been received"} ``` Encrypt ![](https://i.imgur.com/H7MfeYX.png) `6161616161616161616161616161616161616161616161616161616161616161` Nhận được cipher ![](https://i.imgur.com/Zjp8Zc5.png) `339451173da40bb3f2599e0adcb474759c89a29d7eb5ece460037fd4158c3cd8` Trong đó IV là 32 kí tự đầu còn lại là ciphertext IV = `339451173da40bb3f2599e0adcb47475` ct = `9c89a29d7eb5ece460037fd4158c3cd8` p1 = `61616161616161616161616161616161` p2 = receive(ct) = `f6816e90865301708207c24521ea0e61` KEY = IV ^ p1 ^ = `a4745ee6da966ba2113f3d2e9c3f1b75` ![](https://i.imgur.com/uNmU04v.png) script.py ```python import requests import json from pwn import * def encrypt(pt_hex): url = f"http://aes.cryptohack.org/lazy_cbc/encrypt/{pt_hex}/" r = requests.get(url) enc = (json.loads(r.text))['ciphertext'] return enc def check(ct_hex): url = f"http://aes.cryptohack.org/lazy_cbc/receive/{ct_hex}/" r = requests.get(url) try: p = json.loads(r.text)['error'].split(": ")[-1] return p except: return "nothing useful" def get_flag(key_hex): url = f"http://aes.cryptohack.org/lazy_cbc/get_flag/{key_hex}/" r = requests.get(url) try: flag = (json.loads(r.text))['plaintext'] return bytes.fromhex(flag).decode() except: return "flag not found" #p1 = a*16, p2 = a*16 p = (b'a'*32).hex() ct = encrypt(p) c0 = ct[:32] c1 = ct[32:] p2 = b'a'*16 p21 = check(c1) iv = xor(p2, bytes.fromhex(p21), bytes.fromhex(c0)).hex() print(get_flag(iv)) ``` Flag: `crypto{50m3_p30pl3_d0n7_7h1nk_IV_15_1mp0r74n7_?}` ### Triple DES https://aes.cryptohack.org/triple_des/ SOURE ```python from Crypto.Cipher import DES3 from Crypto.Util.Padding import pad IV = os.urandom(8) FLAG = ? def xor(a, b): # xor 2 bytestrings, repeating the 2nd one if necessary return bytes(x ^ y for x,y in zip(a, b * (1 + len(a) // len(b)))) @chal.route('/triple_des/encrypt/<key>/<plaintext>/') def encrypt(key, plaintext): try: key = bytes.fromhex(key) plaintext = bytes.fromhex(plaintext) plaintext = xor(plaintext, IV) cipher = DES3.new(key, DES3.MODE_ECB) ciphertext = cipher.encrypt(plaintext) ciphertext = xor(ciphertext, IV) return {"ciphertext": ciphertext.hex()} except ValueError as e: return {"error": str(e)} @chal.route('/triple_des/encrypt_flag/<key>/') def encrypt_flag(key): return encrypt(key, pad(FLAG.encode(), 8).hex()) ``` Ở challenge này ta khai thác bằng cách sử dụng các cặp khóa yếu của DES - 0101010101010101 FEFEFEFEFEFEFEFE - 0000000000000000 FFFFFFFFFFFFFFFF - 0000000000000000 FEFEFEFEFEFEFEFE - 0101010101010101 FFFFFFFFFFFFFFFF Nhập key và encrypt_flag ![](https://i.imgur.com/16CdHYy.png) Lấy cipher nhận được dán lên trên để encrypt ,đầu ra chính là flag ![](https://i.imgur.com/mMB1biw.png) ![](https://i.imgur.com/083NLPb.png) Sau đó decode hex kết quả nhận được ![](https://i.imgur.com/SRB0Rt4.png) Dưới đây là script bằng python: ```python import requests import json def encrypt(pt_hex, key_hex): url = f"http://aes.cryptohack.org/triple_des/encrypt/{key_hex}/{pt_hex}/" r = requests.get(url) try: enc = (json.loads(r.text))['ciphertext'] return enc except: enc = (json.loads(r.text)) return enc def encrypt_flag(key_hex): url = f"http://aes.cryptohack.org/triple_des/encrypt_flag/{key_hex}/" r = requests.get(url) try: enc = (json.loads(r.text))['ciphertext'] return enc except: enc = (json.loads(r.text)) return enc key = (b'\x00'*8 + b'\xff'*8).hex() print(key) print(len(key)) ct_flag = (encrypt_flag(key)) try: ct = encrypt(ct_flag,key) print(bytes.fromhex(ct)) except: print(ct) ``` Flag: `crypto{n0t_4ll_k3ys_4r3_g00d_k3ys}` ## STREAM CIPHERS ### Symmetry https://aes.cryptohack.org/symmetry/ SOURCE ```python from Crypto.Cipher import AES KEY = ? FLAG = ? @chal.route('/symmetry/encrypt/<plaintext>/<iv>/') def encrypt(plaintext, iv): plaintext = bytes.fromhex(plaintext) iv = bytes.fromhex(iv) if len(iv) != 16: return {"error": "IV length must be 16"} cipher = AES.new(KEY, AES.MODE_OFB, iv) encrypted = cipher.encrypt(plaintext) ciphertext = encrypted.hex() return {"ciphertext": ciphertext} @chal.route('/symmetry/encrypt_flag/') def encrypt_flag(): iv = os.urandom(16) cipher = AES.new(KEY, AES.MODE_OFB, iv) encrypted = cipher.encrypt(FLAG.encode()) ciphertext = iv.hex() + encrypted.hex() return {"ciphertext": ciphertext} ``` Đọc source ta thấy IV dài 16 byte(32 kí tự ),32 kí tự đầu tiên của ciphertext chính là IV còn lại là ciphertext thật Bài này là AES - OFB ![](https://i.imgur.com/YqEjuk4.png) plaintext = IV ^ ciphertext Encrypt_flag() ![](https://i.imgur.com/ikUUlm5.png) Thu được ciphertext = `c09bccb83ba8e53fe6db4b025391edd2147fd0e5f198760496ed9c4d46b3d8d595aa1894a85c2c64e68f251fb75f7be5b2` Trong đó IV = `c09bccb83ba8e53fe6db4b025391edd2` ,ct = `147fd0e5f198760496ed9c4d46b3d8d595aa1894a85c2c64e68f251fb75f7be5b2` Dán lên trên để giải mã ![](https://i.imgur.com/Geuak7c.png) ![](https://i.imgur.com/npsGkW6.png) ![](https://i.imgur.com/UmT7lZB.png) Dưới đây là script bằng python ```python import requests r = requests.get('http://aes.cryptohack.org/symmetry/encrypt_flag/').json() ciphertext = r['ciphertext'] iv = ciphertext[:32] ciphertext = ciphertext[32:] r = requests.get('http://aes.cryptohack.org/symmetry/encrypt/'+ciphertext+'/'+iv+'/').json() plaintext = r['ciphertext'] plaintext = bytes.fromhex(plaintext) print(plaintext) ``` Flag: `crypto{0fb_15_5ymm37r1c4l_!!!11!}`