Bảo mật và mật mã học
Phần học này vào năm ngoái đã giới thiệu cho các bạn cách sử dụng máy tính một cách an toàn và bảo mật hơn. Năm nay, chúng tôi sẽ tập trung vào các khái niệm an toàn thông tin (security) và mật mã học (cryptography). Chúng sẽ giúp ta hiểu rõ thêm về các công cụ được giới thiệu trước đây trong khóa học, ví dụ như việc dùng hàm băm (hash functions) trong Git hoặc trong hàm tạo khóa (Key Derivation Functions), hoặc áp dụng các hệ thống mã hóa đối xứng (symmetric) và bất đối xứng (asymmetric) trong trình SSH.
Cần lưu ý rằng phần học này không thể thay thế cho một khóa học đầy đủ và toàn diện về an toàn máy tính (6.858) hay mã hóa học(6.857 và 6.875). Đừng bao giờ đụng đến an toàn thông tinh nếu như bạn chưa hiểu về nó. Đặc biệt cần lưu ý đến việc tự tạo các hàm mã hóa nếu như bạn không phải là một chuyên gia!
Phần học này sẽ cho bạn cái nhìn đơn giản hóa (nhưng theo tôi là thực dụng) về các khái niệm mật mã học. Phần học này là chắc chắn không đủ kiến thức để bạn có thể tư thiết kế các hệ thống bảo mật và giao thức mật mã học.Tuy nhiên, chúng tôi hy vọng sẽ cho bạn kiến thức bao quát nhất về các chương trình và giao thức mà bạn đã và đang sử dụng.
Entropy
Entropy là một đơn vị đo độ hỗn độn (randomness). Nó rất hữu dụng trong việc đo lường độ mạnh của mật khẩu của bạn.
Như bạn thấy trong truyện tranh ở trên XKCD comic, mật khẩu “correcthorsebatterystaple” an toàn hơn mật khẩu “Tr0ub4dor&3”. Làm sao ta khẳng định được điều này?
Entropy được đo theo đơn vị bits, và khi được lựa một kết quả ngẫu nhiên trong phân phối đồng nhất (uniformly random), thì entropy sẽ bằng log_2(# số kết quả có thể)
. Tung một đồng xu cho ta 1 bit entropy. Tung xúc xắc (6 mặt) cho ta khoản ~2.58 bits entropy
Chúng ta có thể giả định rằng kẻ xấu biết về mô hình (model - ý nói về ký tự hợp thành mật khẩu) của mật khấu, nhưng không hề biết gì về độ ngẫu nhiên dùng để chọn mật khẩu đó.
Bao nhiêu bits entropy thì là đủ? Đó hoàn toàn tùy theo mô hình mối nguy (threat model) của bạn. Đối với việc tấn công mật khẩu online (Online guessing - việc đoán mật khẩu ngay tại giao diện đăng nhập), như truyện tranh XKCD đã chỉ ra, tầm 40 bits entropy là rất tốt. Còn để phòng ngừa việc bị tấn công offline (Offline guessing - khi hacker có được một chuỗi băm của password của bạn và tìm cách giải mã nó), một mật khẩu mạnh hơn (tầm 80 bits hay hơn) là cần thiết
Hàm băm (Hash functions)
Hàm băm mật mã học (cryptographic hash function) là một hàm toán học để chuyển đổi một dữ liệu với kíck cỡ bất kỳ thành một kích cỡ được quy đinh. Hàm băm được mô tả khái quát như sau:
hash(value: array<byte>) -> vector<byte, N> (với một N đã được định trước)
Một ví dụ về hàm băm là SHA1, được dùng trong Git.
Nó có thể băm nhỏ thông tin thành một chuỗi 160 bit thông tin (40 kí tự thập lục phân).
Ta có thể thử băm SHA1 bằng câu lệnh sha1sum
:
$ printf 'hello' | sha1sum
aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
$ printf 'hello' | sha1sum
aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
$ printf 'Hello' | sha1sum
f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0
Một cách khái quát hơn, hàm băm là một hàm rất khó để đảo ngược (hard-to-invert), nhìn rất ngẫu nhiên (vì thêm một chữ vào chuỗi cần mã hóa sẽ tạo ra một chuỗi băm hoàn toàn khác) tuy nhiên lại tất định (deterministic). Đây là những mô tả về mô hình hoàn hảo của hàm băm. Hàm băm có những đặc tính:
- Tính tất tính (Deterministic): nếu input giống nhau thì kết quả output của hàm băm phải giống nhau.
- Tính không đảo ngược (Non-invertible): khó có thể tìm input
m
sao chohash(m) = h
với một kết quả hàm bămh
mà ta có. - Tính khó trùng (collision resistant): Cho input
m_1
, sẽ rất khó tìmm_2
sao chohash(m_1) = hash(m_2)
.
Lưu ý: mặc dù hữu dụng nhưng SHA-1 không còn là một hàm băm tốt. Bạn cũng có thể tham khảo về vòng đời của các hàm băm ở đây. Tuy vậy, việc lựa chọn một hàm băm tốt là hoàn toàn ngoài mục đích của phần học này. Nếu bạn muốn hiểu thêm điều này, bạn cần phải học mật mã học hay an toàn thông tinh một cách chính quy hơn.
Ứng Dụng
- Dùng trong Git để lưu trữ dữ liệu bằng địa chỉ (content-addressed storage). Ý tưởng về hàm băm là một khái niệm tương đối bao quát (vì có những hàm băm không phải là hàm băm mã hóa). Vậy tại sao Git lại cần một hàm băm mã hóa?
- Dùng để rút gọn nội dung của một file. Phần mềm có thể được tải xuống từ những nguồn (nhiều khả năng là không an toàn) song song (mirrors). Ví dụ là các file ảnh Linux ISOs. Thật tốt nếu có thể kiểm chứng những file này và nguồn của chúng. Vì vậy, các trang chủ chính thức thường sẽ cung cấp các chuỗi băm (của nội dung file) cùng đường dẫn để tải chúng. Nhờ đó, ta có thể kiểm chứng sau khi đã tải các file này về.
- Dùng làm Hệ thống chấp thuận, ủy nhiệm. Đây là khi bạn chắc chắn muốn ủy nhiệm một giá trị nào đó và chỉ cho người khác biết một khoảng thời gian sau đó. Ví dụ khi bạn lật đồng xu “trong tâm trí” mà không có đồng xu thật được nhìn thấy và kiểm chứng bởi bạn và một bên khác. Bạn có thể lấy một giá trị
r = random()
, và chia sẻ kết quả hàm bămh=sha256(r)
. Người thứ hai có thể sẽ đoán kết quả của việc lật đồng xu là mặt sấp (tail) hay mặt ngửa (head) (giữa hai người, có thể quy ước nếu số r là chẵn thì là mặt ngửa và lẻ thì là mặt sấp). Sau khi họ đã chọn kết quả thì bạn có thể cho họ biết giá trị đồng xu sau khi lật (trong đầu bạn)r
. Người chơi cùng bạn có thể chắc chắn rằng bạn không khai gian bằng cách dùng hàm bămsha256(r)
đề kiểm chứng kết quả bạn vừa nói và kết quả lúc nãy sau khi tung đồng xu là giống nhau (nếu kết quả hàm băm này và giá trị băm ủy nhiệm lúc nạy là giống nhau).
Hàm tạo khóa (Key derivation functions)
Một khái niệm liên quan đến các hàm băm mật mã là các hàm tạo khóa (gọi tắt là KDF). Các hàm này được dùng trong nhiều ứng dụng như tạo các kết quả với cùng kich cỡ để làm khóa (key) dùng trong các thuật toán mật mã khác. Thường thì các hàm KDF được thiết kể rất tốn thời gian và điều này giúp làm chậm hơn các cuộc tấn công offline, thử hết (brute-force). <!–
Key derivation functions
A related concept to cryptographic hashes, key derivation functions (KDFs) are used for a number of applications, including producing fixed-length output for use as keys in other cryptographic algorithms. Usually, KDFs are deliberately slow, in order to slow down offline brute-force attacks. –>
Ứng Dụng
- Tạo khóa từ mật mã để dùng trong các hàm mật mã khác (ví dụ như trong mật mã đối xứng, xem phía dưới).
- Dùng trong lưu trữ thông tin đăng nhập. Lưu trữ mật khẩu chưa mã hóa là vô cùng nguy hiểm. Cách lưu trữ tốt hơn là
tạo một chuỗi số ngẫu nhiên (gọi là muối (salt)) như
salt = random()
cho mỗi người dùng riêng biệt. Sau đó ta sẽ lưu giữ kết quả củaKDF(password + salt)
vào cơ sở dữ liệu. Khi người dùng đăng nhập, ta sẽ tra thông tin salt trong cơ sở dữ liệu và kết hợp cùng mật khẩu mà người dùng nhập để tạo kết quả bằng hàm KDF. Nếu kết quả này giống dữ liệu được lưu trữ cho người dùng thì ta cho phép họ đăng nhập. <!–Applications
- Producing keys from passphrases for use in other cryptographic algorithms (e.g. symmetric cryptography, see below).
- Storing login credentials. Storing plaintext passwords is bad; the right
approach is to generate and store a random
salt
salt = random()
for each user, storeKDF(password + salt)
, and verify login attempts by re-computing the KDF given the entered password and the stored salt. –>
Mật mã học đối xứng
Bảo mật nội dung của một tin nhắn chắc chắn là khái niệm đầu tiên mà bạn biết về mật mã học. Mật mã học bất đối xứng có thể làm điều này bằng các chức năng sau đây:
keygen() -> key (đây là một hàm tạo số ngẫu nhiên)
encrypt(plaintext: array<byte>, key) -> array<byte> (the ciphertext)
decrypt(ciphertext: array<byte>, key) -> array<byte> (the plaintext)
*encrypt, decrypt là hàm mã hóa và hàm giải mã
**plaintext là nội dung chưa mã hóa
***ciphertext là nội dung mã hóa
Hàm mã hóa có tính chất là nếu biết kết quả mã hóa, sẽ rất khó để đoán nội dung chưa mã hóa nếu không
có khóa dùng trong mã hóa. Hàm giải mã thì chắc chắn phải có tính chất decrypt(encrypt(m, k), k) = m
.
Một ví dụ về mật mã đối xứng là AES.
Ứng Dụng
- Mã hóa các file để lưu trữ trên dịch vụ đám mây không đáng tin cậy. Việc này có thể được kết hợp với
hàm tạo khóa KDF và như vậy bạn có thể bảo mật file bằng một mật khẩu của mình. Điều này được thực hiện
bằng cách tạo khóa
key = KDF(mật khẩu)
rồi lưu giữencrypt(file, key)
.
Mật mã học bất đối xứng
Thuật ngữ “bất đối xứng” nhắc đến việc phương pháp này cần hai chìa khóa với hai chứng năng khác nhau. Loại thứ nhất là chìa khóa riêng (private key), cần được giữ bí mật. Loại còn lại là chìa khóa chung và có thể được chia sẻ một cách thoải mái và không hề ảnh hưởng đến bảo mật thông tin (khác với việc không được chia sẻ chìa khóa trong bảo mật đối xứng). Mật mã bất đối xứng gồm các hàm sau để mã hóa/ giải mã hay để kí/ xác nhận chữ kí:
keygen() -> (public key, private key) (đây là một hàm tạo số ngẫu nhiên)
encrypt(plaintext: array<byte>, public key) -> array<byte> (the ciphertext)
decrypt(ciphertext: array<byte>, private key) -> array<byte> (the plaintext)
sign(message: array<byte>, private key) -> array<byte> (the signature)
verify(message: array<byte>, signature: array<byte>, public key) -> bool (true nếu chữ kí là là xác thực và ngược lại là false)
*signature là chữ kí số
Hàm encrypt/decrypt có chức năng như trong mật mã học đối xứng. Tin nhắn có thể được mã hóa
bằng chìa khóa chung. Kết quả mã hóa sau đó sẽ khó được sử sụng để đoán nội dung chưa được mã hóa nếu ta không
có chìa khóa riêng. Hàm giải mã có thuộc tính decrypt(encrypt(m, public key), private key) = m
.
Mật mã học đối xứng và bất đối xứng có thể được hiểu như các loại khóa ngoài đời thực. Mật mã học đối xứng thì giống như khóa cửa: ai có khóa thì khóa/ mở khóa được. Còn bất đối xứng thì như loại khóa số: bạn có thể đưa ổ khóa số đã mở cho ai đó (chìa khóa chung), họ sẽ cho tin nhắn vào trong hộp và khóa lại bằng ổ này, sau đó chỉ có bạn - người biết mật mã (chìa khóa riêng) có thể mở được ổ khóa.
Hàm kí và xác nhận chữ kí thì có tác dụng như chữ kí tay của chúng ta. Sẽ rất khó để nhái chữ kí.
Không cần biết nội dung của tin nhắn, nếu không có chìa khóa riêng, sẽ rất khó để tạo ra một chữ kí
số để kết quả của hàm verify(message, signature, public key)
là true. Và tất nhiên, hàm xác thực chữ kí
có tính chất đúng đắn sau: verify(message,
sign(message, private key), public key) = true
.
Ứng dụng
- Bảo mật thư điện tử PGP. Người dùng thư có thể thông báo chìa khóa chung trên mạng online (như trong một máy chủ PGP, hoặc trên trang web như Keybase). Ai cũng có thể gửi thư mã hóa đến người dùng.
- Bảo mật tin nhắn. Những ứng dụng như Signal and Keybase dùng mật mã bất đối xứng để tạo các kênh liên lạc bí mật.
- Kí phần mềm. Git có thể dùng chữ kí số GPG để kí các commits và tags. Với một chìa khóa chung được thông báo rộng rãi, ai cũng có thể kiểm chứng về độ xác thực về những phần mềm mà họ sẽ tải xuống.
Truyền dẫn chìa khóa
Bảo mật bất đối xứng thật sự tuyệt vời, nhưng đi cùng với nó là những thách thức trong việc chia sẻ khóa chung hay việc định danh khóa chung với một đối tượng đời thực. Có rất nhiều lời giải cho bài toán này. Ứng dụng nhắn tin Signal có một lời giải đơn giản: tin tưởng trong lần dùng đầu và cho phép trao đổi chìa khóa chung ngoài luồng (bạn phải tự xác thực số điện thoại của đối tượng bạn nhắn tin ngoài đời). PGP thì có một phương pháp khác, gọi là “mạng lưới của sự tin cậy” (web of trust). Keybase thì lại có một lời giải khác cho việc chứng thực xã hội (social proof). Mỗi phương pháp có cái hay riêng; chúng tôi - những người tạo khóa học này thì thích cách của Keybase nhất. <!–
Key distribution
Asymmetric-key cryptography is wonderful, but it has a big challenge of distributing public keys / mapping public keys to real-world identities. There are many solutions to this problem. Signal has one simple solution: trust on first use, and support out-of-band public key exchange (you verify your friends’ “safety numbers” in person). PGP has a different solution, which is web of trust. Keybase has yet another solution of social proof (along with other neat ideas). Each model has its merits; we (the instructors) like Keybase’s model. –>
Case studies
Phần mềm quản lý mật khẩu
Đây là một công cụ hữu dụng mà mỗi người nên thử (vài ví dụ như KeePassXC, pass,hay 1Password). Những phần mềm này cho bạn sự tiện lợi để tạo các mật khẩu an toàn với entropy cao cho mỗi tài khoản đăng nhập. Chúng còn có thể lưu giữ các mật khẩu của bạn cùng một chỗ với bảo mật bằng mật mã đối xứng cùng chìa khóa tạo ra từ các hàm KDF và mật khẩu mà bạn cung cấp.
Dùng các chương trình này cũng hạn chế việc lập lại mật khẩu (giúp bạn an toàn hơn khi một trong những trang web có cùng mật khẩu bị tấn công). Điều tốt hơn nữa là bạn chỉ cần phải nhớ một mật khẩu an toàn duy nhất.
Bảo mật hai lớp (2FA)
Phương pháp bảo mật 2 lớp yêu cầu bạn dùng một mật khẩu (“cái bạn biết”) cùng với một trình xác thực 2FA (như YubiKey - “cái bạn sở hữu”) để bảo vệ bạn khỏi việc bị ăn cắp mật khẩu và các cuộc tấn công giả mạo (phishing). <!–
Two-factor authentication
Two-factor authentication (2FA) requires you to use a passphrase (“something you know”) along with a 2FA authenticator (like a YubiKey, “something you have”) in order to protect against stolen passwords and phishing attacks. –>
Mã hóa ổ cứng
Mã hóa toàn bộ ổ đĩa của máy tính của bạn là một cách bảo vệ thông tin của bạn dễ dàng trong trường hợp bị mất cắp. Bạn có thể dùng cryptsetup + LUKS trên Linux, BitLocker trên Windows, hoặc FileVault trên macOS. Những trình này sẽ mã hóa nguyên ổ đĩa bằng mật mã đối xứng với chìa khóa được bảo vệ bằng mật khẩu của bạn. <!–
Full disk encryption
Keeping your laptop’s entire disk encrypted is an easy way to protect your data in the case that your laptop is stolen. You can use cryptsetup + LUKS on Linux, BitLocker on Windows, or FileVault on macOS. This encrypts the entire disk with a symmetric cipher, with a key protected by a passphrase. –>
Tin nhắn bảo mật
Dùng Signal hay Keybase. Đây là những chương trình được bảo mật theo qui trình đầu cuối (end-to-end) bằng phương pháp mã hóa bất đối xứng. Tuy nhiên việc lấy chìa khóa chung từ đối tác của bạn là cái đáng nói ở đây. Nếu bạn muốn bảo mật tốt, bạn cần xác thực chìa khóa chung của đối tác ngoài luồng trao đổi ngoài đời thực (với Signal hay Keybase), hoặc phải tin tưởng bằng chứng minh xã hội (social proofs - với Keybase). <!–
Private messaging
Use Signal or Keybase. End-to-end security is bootstrapped from asymmetric-key encryption. Obtaining your contacts’ public keys is the critical step here. If you want good security, you need to authenticate public keys out-of-band (with Signal or Keybase), or trust social proofs (with Keybase). –>
SSH
Chúng tôi đã có bài học về SSH và chìa khóa trong SSH ở một bài học trước. Bây giờ hãy phân tích về mặt mật mã học của vấn đề này.
Khi bạn chạy trình ssh-keygen
, nó sẽ tạo một cặp khóa bất đối xứng, public_key,
private_key
. Chúng được tạo lập một cách hoàn toàn ngẫu nhiên, bằng entropy được
cung cấp từ hệ điều hành (từ nhũng hoạt động phần cứng, v.v.). Chìa khóa chung
thì được lưu giữ nguyên vẹn vì nó không cần phải bí mật. Còn chìa khóa riêng thì cần được bảo mật
trên ổ cứng của bạn. Vì vậy ssh-keygen
sẽ đòi hỏi người dùng cung cấp một mật khẩu và
dùng nó để tạo một chìa khóa mới dùng để mã hóa chìa khóa riêng bằng bảo mật đối xứng.
Trong thực tế, một khi máy chủ biết chìa khóa chung của máy người dùng (được lưu giữ trong .ssh/authorized_keys
),
máy người dùng kết nối có thể chứng minh danh tính bằng chữ kí bất đối xứng. Việc này được thực hiện qua quy trình
thách đố-chứng minh (challenge-respone) .
Quy trình này được hiểu khái quát là khi máy chủ gửi một số ngẫu nhiên đến máy đầu cuối của người dùng. Máy này sẽ
kí tin nhắn và gửi lại máy chủ, nơi kiểm chứng chữ kí với các chìa khóa chung mà nó lưu giữ sẽ được diễn ra. Nếu thành công,
việc này sẽ chứng minh rằng máy đẩu cuối đang nắm giữ chìa khóa riêng thuộc cùng cặp với chìa khóa chung mà máy chủ đang
lưu giữ trong file .ssh/authorized_keys
của máy chủ. Kết quả là máy chủ SSH chấp thuận cho máy người dùng đăng nhập vào.
Một vài thông tin hữu dụng
- Bài học năm ngoái: khi chúng tôi tập trung về vấn đề an toàn và bảo mật theo cách nhìn của người dùng máy tính nhiều hơn.
- Những câu trả lời đúng về mật mã học: những câu trả lời cho việc dùng thuật toán nào cho X, với vô vàn vấn đề X thông dụng.
Bài tập
- Entropy
- Cho mật khẩu được cấu thành từ 4 từ viết thường trong từ điển Anh Ngữ. Biết rằng mỗi từ được lựa một cách ngẫu, đều nhau từ từ điển 100,000 từ. Ví dụ là “correcthorsebatterystaple`. Entropy của mật khẩu này là bao nhiêu bits?
- Cho một cách chọn mật khẩu khác trên: tạo mật khẩu dài 8 kí tự (cả hoa cả thường). Ví dụ như
rg8Ql34g
. Mật khẩu này có entropy là bao nhiêu? - Trong hai mật khẩu trên, cái nào bảo mật hơn?
- Nếu hacker có thể đoán được 10,000 mật khẩu mỗi giây, sẽ mất bao lâu để đoán được các mật khẩu trên?
-
Hàm băm mật mã: Tải file hình của Debian từ một link phụ (ví dụ từ máy chủ Argentina) Kiểm chứng kết quả hàm băm (từ câu lệnh
sha256sum
) với kết quả băm được đăng trên trang chủ chính thức của Debian (file này được lưu giữ trêndebian.org
, nếu bạn đã tải file trên đường link phụ của Argentina). -
Mật mã đối xứng Mã hóa một file bằng AES qua câu lệnh OpenSSL:
openssl aes-256-cbc -salt -in {input filename} -out {output filename}
. Hãy xem nội dung file mã hóa bằngcat
hayhexdump
. Sau đó giải mã file bằngopenssl aes-256-cbc -d -in {input filename} -out {output filename}
và kiểm tra xem nội dung trước khi mã hóa và sau giải mã là giống nhau (bằng câu lệnhcmp
). - Mật mã bất đối xứng
- Hãy cài đặt chìa khóa SSH trên một máy tính mà bạn có thể đăng nhập được. Hãy chắc chắn rằng chìa khóa riêng của bạn được mã hóa bằng một mật khẩu.
- Cài đặt GPG
- Gửi Anish một thư điện tử bảo mật qua chìa khóa chung
- Kí một commit trong Git với
git commit -S
hay tạo một Git tag với chữ kí bằnggit tag -s
. Xác thực chữ kí này trên commit bằnggit show --show-signature
hoặc trên tag bằnggit tag -v
.
Licensed under CC BY-NC-SA.