Năm bài trước đều là mật mã đối xứng (AES, HMAC) hay một chiều (hash) — điểm chung: hai bên phải chia sẻ cùng một bí mật trước. Nhưng đây là bài toán con gà–quả trứng: làm sao trao khóa AES cho nhau qua mạng mà kẻ nghe lén không lấy được? Mã hóa bất đối xứng giải quyết, và RSA là cái tên kinh điển. Ý tưởng cách mạng: mỗi người có hai khóa — một công khai (chia cho cả thế giới) và một riêng (giữ kín). Bài này đo thật RSA bằng openssl, và làm rõ một giới hạn khiến RSA không dùng để mã dữ liệu lớn.
Hai khóa: công khai để mã, riêng để giải
RSA sinh ra một cặp khóa liên kết toán học:
- Khóa công khai: chia sẻ tự do. Ai cũng dùng nó để mã hóa dữ liệu gửi cho bạn.
- Khóa riêng: giữ bí mật tuyệt đối. Chỉ nó giải mã được thứ đã mã bằng khóa công khai tương ứng.
Nhờ vậy, ai muốn gửi bạn một bí mật chỉ cần khóa công khai của bạn (không cần thỏa thuận gì trước), và chỉ bạn — người giữ khóa riêng — mở được. Bài toán trao khóa được giải: không cần chia sẻ bí mật trước. (Ký số thì dùng cặp khóa ngược lại: ký bằng khóa riêng, ai cũng xác thực bằng khóa công khai — bài sau.)
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out priv.pem
openssl pkey -in priv.pem -pubout -out pub.pem
openssl pkeyutl -encrypt -pubin -inkey pub.pem -in secret.txt -out enc.bin
openssl pkeyutl -decrypt -inkey priv.pem -in enc.bin

Hình 1: RSA giải bài toán trao khóa — mỗi người một cặp khóa. Khóa công khai để mã (ai cũng dùng), khóa riêng để giải (chỉ chủ nhân). RSA chậm và chỉ mã được dữ liệu nhỏ nên thực tế dùng mã hóa lai.
Đo thật: mã bằng công khai, giải bằng riêng

Hình 2: Sinh cặp khóa 2048-bit. Mã "khoa AES phien..." bằng pub.pem → enc.bin 256 byte; giải bằng priv.pem → bản rõ gốc. Giải bằng khóa khác → Public Key operation error. Mã 500 byte cũng lỗi — RSA 2048 chỉ mã được vài trăm byte.
Kết quả xác nhận:
- Cặp khóa 2048-bit:
priv.pem(riêng) vàpub.pem(công khai) liên kết toán học với nhau. - Mã/giải đúng: mã "khoa AES phien: 7f3a9c..." bằng khóa công khai ra
enc.binđúng 256 byte (= 2048 bit, kích thước khóa); giải bằng khóa riêng ra lại bản rõ. Lưu ý bản mã luôn bằng kích thước khóa bất kể bản rõ ngắn cỡ nào. - Sai khóa: giải
enc.binbằng một khóa riêng khác →Public Key operation error. Chỉ đúng khóa riêng cặp đôi mới mở được. - Giới hạn cốt tử: mã 500 byte → lỗi. RSA chỉ mã được dữ liệu nhỏ hơn kích thước khóa trừ phần đệm (RSA 2048: PKCS#1 v1.5 ~245 byte, OAEP ~190 byte). Nghĩa là không thể dùng RSA mã một file hay một request lớn.
Vì sao thực tế dùng "mã hóa lai"
Vì RSA vừa chậm (chậm hơn AES hàng nghìn lần) vừa giới hạn kích thước, gần như không ai mã dữ liệu trực tiếp bằng RSA. Thay vào đó là mã hóa lai (hybrid): sinh một khóa AES ngẫu nhiên (32 byte), dùng AES-GCM mã hóa dữ liệu lớn (nhanh), rồi dùng RSA mã hóa (bọc) chỉ khóa AES 32 byte đó để gửi kèm. Người nhận dùng khóa riêng RSA mở lấy khóa AES, rồi giải dữ liệu bằng AES. Đây chính xác là cách TLS, PGP, và mọi hệ mã hóa thực tế hoạt động — RSA lo phần "trao khóa" nhỏ mà nó giỏi, AES lo phần "mã dữ liệu" lớn mà nó giỏi.
Đánh đổi và lưu ý
Luôn dùng padding an toàn (OAEP), đừng dùng RSA "thô" hay PKCS#1 v1.5. RSA không padding (textbook RSA) rò rỉ nghiêm trọng; PKCS#1 v1.5 dính padding oracle (Bleichenbacher). Khi mã hóa, dùng OAEP (-pkeyopt rsa_padding_mode:oaep); khi ký, dùng PSS. Thư viện cấp cao thường mặc định đúng.
RSA 2048 là tối thiểu; cân nhắc EC. RSA 1024 đã yếu; 2048 là mức tối thiểu hiện nay, 3072/4096 cho dài hạn. Nhưng khóa RSA càng dài càng chậm và to. Đường cong elliptic (EC — bài sau) cho cùng mức an toàn với khóa nhỏ hơn nhiều (EC 256-bit ≈ RSA 3072-bit) và nhanh hơn — nên nhiều hệ thống mới ưu tiên EC.
Bảo vệ khóa riêng là tất cả. Toàn bộ an toàn dựa vào việc khóa riêng không lộ. Lưu có mật khẩu bảo vệ (openssl genpkey ... -aes256), phân quyền file chặt, và với hệ thống quan trọng cân nhắc HSM/KMS. Lộ khóa riêng = mọi thứ mã cho bạn đều mở được.
Ba ý mang về
- RSA giải bài toán trao khóa bằng cặp khóa bất đối xứng: khóa công khai để mã (ai cũng dùng), khóa riêng để giải (chỉ chủ nhân) — đo thật, mã bằng
pub.pemgiải bằngpriv.pem, sai khóa thìPublic Key operation error; không cần chia sẻ bí mật trước. - RSA không mã được dữ liệu lớn: bản mã bằng kích thước khóa, chỉ chứa được vài trăm byte (đo thật 500 byte đã lỗi) và RSA rất chậm — nên thực tế dùng mã hóa lai: RSA bọc khóa AES, AES mã dữ liệu.
- Dùng đúng: luôn padding OAEP (mã)/PSS (ký), tránh RSA thô/PKCS#1 v1.5; RSA ≥ 2048 bit hoặc chuyển sang EC (nhỏ + nhanh hơn); và bảo vệ khóa riêng tuyệt đối.
Nguồn
- OpenSSL docs — openssl-pkeyutl / openssl-genpkey: https://docs.openssl.org/3.0/man1/openssl-pkeyutl/
- Cloudflare — A hybrid cryptosystem và RSA vs ECC: https://www.cloudflare.com/learning/ssl/what-is-asymmetric-encryption/
Phần sau ta xem vì sao khóa EC 256-bit mạnh ngang RSA 3072-bit mà nhỏ và nhanh hơn nhiều — đường cong elliptic, đo thật kích thước khóa và tốc độ sinh bằng openssl.