# KHÁI NIỆM
## CÁC HỆ SỐ
Các khái niệm base16 (hex), base32, base64, và base85 là các thuật toán mã hóa dữ liệu. Các thuật toán này được định nghĩa trong RFC 4648
1. **Base16 (hex)**: Mã hóa dữ liệu thành các ký tự trong bảng chữ cái hexa (16 ký tự)
2. **Base32**: Mã hóa dữ liệu thành các ký tự trong bảng chữ cái base32 (32 ký tự)
3. **Base64**: Mã hóa dữ liệu thành các ký tự trong bảng chữ cái base64 (64 ký tự)
4. **Base85**: Mã hóa dữ liệu thành các ký tự trong bảng chữ cái base85 (85 ký tự)
Mỗi thuật toán có cách mã hóa và giải mã dữ liệu khác nhau. Các thuật toán này thường được sử dụng để mã hóa các tệp tin nhị phân, email, hoặc các thông tin khác trước khi truyền đi qua mạng hoặc lưu trữ.
## DES, AES
**Data Encryption Algorithm (DES)** là một thuật toán khóa đối xứng được sử dụng để mã hóa.
Thuật toán DES bao gồm 16 vòng xử lý dữ liệu với 16 khóa vòng trung gian 48 bit được tạo từ khóa mật mã 56 bit bởi Bộ tạo khóa vòng. Tương tự, mật mã đảo ngược DES tính toán dữ liệu ở định dạng văn bản rõ ràng từ văn bản mật mã bằng cách sử dụng cùng một khóa mật mã.

**Advanced Encryption Standard (AES)** là một thuật toán đối xứng khóa riêng nhưng mạnh hơn và nhanh hơn Triple-DES. Nó có thể mã hóa dữ liệu 128 bit với khóa 128/192/256 bit.

## PYCRYPTODOME
Thư viện **PyCryptodome** là 1 package python chứa các yếu tố mã hóa low-level.
**Pycryptodome** là một phiên bản của PyCrypto. Nó mang lại nhiều cải tiến so với phiên bản chính thức cuối cùng của PyCrypto, ví dụ như:
1. Các chế độ mã hóa được xác thực (GCM, CCM, EAX, SIV, OCB)
1. Hỗ trợ AES được tăng tốc trên các nền tảng Intel thông qua AES-NI
1. Hỗ trợ đầu tiên cho PyPy
1. Mã hóa đường cong Elliptic (NIST P-curve; Ed25519, Ed448)
1. API tốt hơn và nhỏ gọn hơn
...
**PyCryptodome** không phải là một bao bọc cho một thư viện C riêng biệt như OpenSSL. Đến mức tối đa có thể, các thuật toán được thực hiện bằng Python thuần. Chỉ những phần rất quan trọng đối với hiệu suất (vd như block cipher) được triển khai dưới dạng C extension.
## OPENSSL, GPG
**OpenSSL** là một tiện ích nguồn mở được sử dụng để mã hóa dữ liệu. Nó cho phép tạo khóa RSA, DH, DSA,… và mã hóa dữ liệu với kết nối SSL/TLS. Đây là công cụ mã nguồn mở có sẵn trên Windows, Linux, Solaris, macOS, QNX và nhiều hệ điều hành khác
Bao gồm các phần mềm nguồn mở cho phép triển khai các giao thức mạng và mã hóa dữ liệu khác nhau như SSL và TLS. Thư viên gốc của phần mềm này được viết bằng ngôn ngữ lập trình C.Trong đó có sẵn những phần mềm cho phép người dùng sử dụng thư viện OpenSSL với nhiều nguôn ngữ khác nhau cùng với các chức năng mật mã tổng quát để có thể mã hóa và giải mã dữ liệu. OpenSSL cũng được sử dụng từ dòng lệnh để có thể yêu cầu, tạo và quản lý các chứng thực số.
**GPG** (hoặc **GNU Privacy Guard**), là một ứng dụng mã hóa khoá công khai, cho phép truyền tải thông tin giữa các bên an toàn và có thể được sử dụng để xác minh nguồn gốc của một thông điệp là chính chủ hay không
Cách thức làm việc của khóa công khai mã hóa (Public Key Encryption):
- `Đảm bảo rằng chỉ có người dùng được chỉ định mới có thể đọc`

Hệ thống này cho phép tạo và mã hóa thông điệp một chiều bằng bất kỳ khóa nào, nhưng chỉ có thể được giải mã bởi người dùng được chỉ định thông qua khóa giải mã riêng. Nếu cả hai bên tạo cặp khóa (công khai và riêng), và chia sẻ khóa mã hóa công khai của họ cho nhau, họ có thể mã hóa và truyền thông điệp an toàn.
- `Xác nhận tính xác thực của người gửi`
Hệ thống cũng cho phép người gửi ký thông điệp bằng khóa cá nhân của mình. Người nhận có thể sử dụng khóa công khai để xác minh chữ ký và đảm bảo rằng thông điệp được gửi bởi người dùng đã chỉ định
# CRYPTOHACK
## Finding flags
Flag bài này là `crypto{y0ur_f1rst_fl4g}`, chủ yếu giới thiệu format của flag ra sao.

## Great Snakes
Bài này chỉ cần mình run cái file py được cho sẵn thì tìm được flag là `crypto{z3n_0f_pyth0n}`

## ASCII

Mình dùng đoạn code dưới để chuyển từ ASCII -> Dec thì tìm được flag là `crypto{ASCII_pr1nt4bl3}`
```
A = [99, 114, 121, 112, 116, 111, 123, 65, 83, 67, 73, 73, 95, 112, 114, 49, 110, 116, 52, 98, 108, 51, 125]
for a in A:
x = chr(a)
print(x,end ='')
```
## Hex

Mình cùng dùng đoạn code dưới để decode hex thì được flag là `crypto{You_will_be_working_with_hex_strings_a_lot}`
```
hex = "63727970746f7b596f755f77696c6c5f62655f776f726b696e675f776974685f6865785f737472696e67735f615f6c6f747d"
x=bytes.fromhex(hex)
ascii=x.decode()
print(ascii)
```
## Base64

Dùng đoạn code dưới để decode base64 (đề gợi ý mình decode hex trước sau đó tới base64) và tìm được flag là `crypto/Base+64+Encoding+is+Web+Safe/`
```
import base64
h = "72bca9b68fc16ac7beeb8f849dca1d8a783e8acf9679bf9269f7bf"
x=bytes.fromhex(h)
flag = base64.b64encode(x).decode('utf-8')
print(flag)
```
## Bytes and Big Integers

Khóa RSA chỉ work với số. Bài này đề đã cung cấp cho mình messages sẵn dưới dạng số rồi nên chỉ cần apply vô.
Flag bài này là `crypto{3nc0d1n6_4ll_7h3_w4y_d0wn}`
```
from Crypto.Util.number import long_to_bytes
A = 11515195063862318899931685488813747395775516287289682636499965282714637259206269
flag = long_to_bytes(A).decode('utf-8')
print(flag)
```
## XOR Starter

Bài này là về XOR, với mỗi ký tự a trong chuỗi A, thực hiện phép XOR với số 13, sau đó chuyển kết quả thành ký tự tương ứng và thêm vào chuỗi flag.
Flag tìm được là `crypto{aloha}`
```
A = "label"
flag = ""
for a in A:
flag += chr(ord(a) ^ 13)
print(f"crypto{{{flag}}}")
```
## XOR Properties

Cứ lấy mấy key xor với nhau theo thứ tự thì tìm được flag. Hàm `unhexlify` từ thư viện` binascii` là dùng để chuyển đổi một chuỗi hex thành dạng nhị phân.
Flag bài này là `crypto{x0r_i5_ass0c1at1v3}`
```
#!/usr/bin/env python3
from binascii import unhexlify
def xor_two_str(s1,s2):
if len(s1) != len(s2):
raise "XOR EXCEPTION: Strings are not of equal length!"
return ''.join(format(int(a, 16) ^ int(b, 16), 'x') for a,b in zip(s1,s2))
KEY1 = "a6c8b6733c9b22de7bc0253266a3867df55acde8635e19c73313"
KEY2 = xor_two_str("37dcb292030faa90d07eec17e3b1c6d8daf94c35d4c9191a5e1e", KEY1)
print("[-] KEY2: {}".format(KEY2))
KEY3 = xor_two_str("c1545756687e7573db23aa1c3452a098b71a7fbf0fddddde5fc1", KEY2)
print("[-] KEY3: {}".format(KEY3))
KEY4 = xor_two_str(xor_two_str(KEY1, KEY2), KEY3)
print("[-] KEY4: {}\n".format(KEY4))
FLAG = xor_two_str("04ee9855208a2cd59091d04767ae47963170d1660df7f56f5faf", KEY4)
print("[*] FLAG: {}".format(unhexlify(FLAG)))
```
## Favourite byte

Bài này là single byte - xor, vậy nên mình phải xor từng byte với nhau, lặp đi lặp lại cho tới hết thì mới tìm được flag.
Flag bài này là`crypto{0x10_15_my_f4v0ur173_by7e}`
```
from binascii import unhexlify
import string
def single_byte_xor(input, key):
if len(chr(key)) != 1:
raise "KEY LENGTH EXCEPTION: In single_byte_xor key must be 1 byte long!"
output = b''
for b in input:
output += bytes([b ^ key])
try:
return output.decode("utf-8")
except:
return "Cannot Decode some bytes"
data = "73626960647f6b206821204f21254f7d694f7624662065622127234f726927756d"
decoded = unhexlify(data)
print("[-] HEX_DECODE: {}\n".format(decoded))
result = {}
for i in range(256):
result[i] = (single_byte_xor(decoded, i))
print("[*] FLAG: {}".format([s for s in result.values() if "crypto" in s]))
```
## You either know, XOR you don't

Bài này đề gợi ý mình nhớ lại format flag là `crypto{` (7 char). Vậy thì lấy nó đi xor với 7 char đầu trong cipher (data sau khi chuyển về nhị phân). Thì tìm được 1 cái key mới là `myXORke`, nhưng mà cái key này còn thiếu chữ **y** nên mình phải tự add vào. Sau đó mình lặp đi lặp cái key `myXORkey` sao cho nó dài bằng cái cipher, rồi đem đi xor với nhau thì tìm được flag.
Flag bài này là `crypto{1f_y0u_Kn0w_En0uGH_y0u_Kn0w_1t_4ll}`
```
from binascii import unhexlify
def brute(input, key):
if len(input) != len(key):
return "Failed!"
output = b''
for b1, b2 in zip(input, key):
output += bytes([b1 ^ b2])
try:
return output.decode("utf-8")
except:
return "Cannot Decode some bytes"
data = "0e0b213f26041e480b26217f27342e175d0e070a3c5b103e2526217f27342e175d0e077e263451150104"
cipher = unhexlify(data)
print("[-] CIPHER: {}".format(cipher))
# Buoc1
key_part = brute(cipher[:7], "crypto{".encode())
print("[-] PARTIAL KEY FOUND: {}".format(key_part))
# Buoc2
key = (key_part + "y").encode()
key += key * int((len(cipher) - len(key))/len(key))
key += key[:((len(cipher) - len(key))%len(key))]
print("[-] Decoding using KEY: {}".format(key))
plain = brute(cipher, key)
print("\n[*] FLAG: {}".format(plain))
```
# Challenges
## Challenge 1:
Giải mã đoạn ciphertext mã hoá bằng AES-128 mode CBC sau sử dụng CyberChef + Code (viết cả 2 cách giải):
```
cipher text: hf5lMhAM4ZGmYN44XXRElo0OMm+XGEsLAiCNwy3Twqg=
key: longphuckhanhquy
iv: trongquocduykhoa
```
Flag bài này là `KCSC{ma_hoa_hay_ko_e}`
**CyberChef:**

**Code**
Đầu tiên mình import thư viện Pycryptodome. Sau đó đổi chuỗi base64 kia thành bytes.
Tạo đối tượng `AES.new` với key và iv.
Sử dụng `cipher.decrypt` để giải mã và `unpad` để loại bỏ các bytes được thêm vào để đảm bảo kích thước block đúng. Cuối cùng nhập các info đã cho `key,iv,ciphertext` để decode.
```
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from Crypto.Util.strxor import strxor_c
import base64
def aes_128_cbc_decrypt(ciphertext_base64, key, iv):
ciphertext = base64.b64decode(ciphertext_base64)
cipher = AES.new(key, AES.MODE_CBC, iv)
flag = unpad(cipher.decrypt(ciphertext), AES.block_size)
return flag
ciphertext_base64 = "hf5lMhAM4ZGmYN44XXRElo0OMm+XGEsLAiCNwy3Twqg="
key = b'longphuckhanhquy'
iv = b'trongquocduykhoa'
flag = aes_128_cbc_decrypt(ciphertext_base64, key, iv)
print("Flag:", flag.decode('utf-8'))
```

## Challenge 2:
Trong tập tin "bai2.zip", đọc bash và kết hợp với những gì đã tìm hiểu về openssl, hãy giải mã flag.enc và phục hồi file gốc.
Đây là bash đã cho

Mình dùng openssl để decrypt
`openssl enc -aes-256-cbc -d -in flag.enc -out flag.xlsx -K $key2 -iv d14cc2932227ad3eb8354fc18057b292`
Thu được `flag.xlsx`, file này có PK nên đổi thành `.zip`. Sau đó unzip, vào `sharedStrings.xml` thì tìm được 1 chuỗi ngăn cách bằng tên Long, Quoc,Kiet,Phuc,Loi, ghép lại ta được `S0NTQ3tzYXVfbmF5X2Nob2lfZm9yX3NlX2dhcF9yYXRfbmhpZXVfbWFfaG9hX25odV90aGVfbmF5fQ==` và đem đi decode base64 thì được flag
Flag bài này là
`KCSC{sau_nay_choi_for_se_gap_rat_nhieu_ma_hoa_nhu_the_nay}`
## Challenge 3:
Trong tập tin "bai3.zip". Làm bằng CyberChef và sửa đổi source được cho để giải mã (hoặc tự code mới nếu thích hehe).
Mình thêm đoạn code decrypt vào source có sẵn
```
def decrypt(key, iv, ciphertext):
key = bytes.fromhex(key)
iv = ciphertext[:16]
ciphertext = ciphertext[16:]
cipher = AES.new(key, AES.MODE_CBC, iv)
pt = unpad(cipher.decrypt(ciphertext), 16)
return pt
```
Sau đó decrypt 2 file là `docvippro.docx.kcsc` và `hinhvippro.jpg.kcsc` lần lượt thành 2 file `output.txt` và `output1.txt`
```
with open("docvippro.docx.kcsc","rb") as file:
bytes_from_file = file.read()
bytes_from_file = bytes_from_file[16:]
key = bytes.fromhex("b78b4f82c24917cf740250da0f3c1bb7748c6c6c8f0df1f74948af97bebea675")
iv = bytes.fromhex("11b2e8dc1947c39260873cae34850eda")
cipher = AES.new(key,AES.MODE_CBC,iv)
with open("output.txt","wb") as file_out:
file_out.write(cipher.decrypt(bytes_from_file))
key = "b78b4f82c24917cf740250da0f3c1bb7748c6c6c8f0df1f74948af97bebea675"
iv = "11b2e8dc1947c39260873cae34850eda"
with open("hinhvippro.jpg.kcsc","rb") as file:
bytes_from_file = file.read()
bytes_from_file = bytes_from_file[16:]
key = bytes.fromhex("b78b4f82c24917cf740250da0f3c1bb7748c6c6c8f0df1f74948af97bebea675")
iv = bytes.fromhex("11b2e8dc1947c39260873cae34850eda")
cipher = AES.new(key,AES.MODE_CBC,iv)
with open("output1.txt","wb") as file_out:
file_out.write(cipher.decrypt(bytes_from_file))
```
File mở file `output.txt` có `PK` thì mình đổi đuôi thành zip, `output1.txt` có `jfif` thì đổi đuôi thành png, mình được tấm hình

Unzip file `output`, sau đó vào file `document.xml` cũng thấy chuỗi kí tự base85 `91)WFH['IHB4#ahF),-#@<l4%BPCgqBk;6jFD,6(?ZTdcCgg[m@<63kFDl&0?YF@s?Z'Og?Y+(]BOtjg/73:.DdRF#?XdGXI/` decode xong thì tìm được flag.
Flag bài này là
```
KCSC{xong_task_nay_thi_tiep_theo_se_la_task_tong_hop_nhe_em_hehe,_nho_on_bai}
```