Bài HMAC giải quyết xác thực toàn vẹn kèm khóa bí mật chung — nhưng nó có điểm yếu: ai kiểm được cũng tạo được. Vậy làm sao chứng minh một bản cập nhật phần mềm, một JWT, hay một chứng chỉ đúng do đúng một người tạo, ai cũng kiểm được nhưng không ai giả được? Câu trả lời là chữ ký số — ứng dụng đẹp nhất của mật mã bất đối xứng. Nó dùng cặp khóa theo chiều ngược với mã hóa: ký bằng khóa riêng, xác thực bằng khóa công khai. Đo thật bằng openssl 3.0 và khóa EC.

Ký bằng khóa riêng, xác thực bằng khóa công khai

Ở bài RSA, mã hóa là: mã bằng công khai, giải bằng riêng. Chữ ký số dùng cặp khóa ngược lại:

  • Ký: dùng khóa riêng — chỉ chủ khóa làm được.
  • Xác thực: dùng khóa công khai — ai cũng kiểm được.

Nhờ vậy chữ ký số bảo đảm ba điều mà HMAC không đủ:

  • Xác thực (authenticity): đúng người giữ khóa riêng đã ký — không ai giả được.
  • Toàn vẹn (integrity): nội dung không bị sửa (sửa một byte là verify thất bại).
  • Chống chối bỏ (non-repudiation): người ký không chối được đã ký — vì chỉ họ có khóa riêng. HMAC không có tính này (khóa chung, bên kiểm cũng tạo được, nên không chứng minh ai tạo).

Về cơ chế, chữ ký không ký cả file mà ký giá trị băm của file (nhanh, và file dài bao nhiêu cũng được).

openssl dgst -sha256 -sign priv.pem -out f.sig f              # ký
openssl dgst -sha256 -verify pub.pem -signature f.sig f       # xác thực

Ảnh chụp đoạn mã nền tối giải thích chữ ký số ký bằng khóa riêng ai cũng xác thực bằng khóa công khai, dùng cặp khóa ngược với mã hóa mã hóa mã bằng công khai giải bằng riêng chữ ký số thì ngược lại ký bằng khóa riêng chỉ chủ khóa làm được xác thực bằng khóa công khai ai cũng kiểm được, chữ ký số bảo đảm ba điều xác thực đúng người giữ khóa riêng đã ký không ai giả được toàn vẹn nội dung không bị sửa sửa 1 byte verify fail chống chối bỏ non-repudiation người ký không chối được khác HMAC HMAC khóa chung nên bên kiểm cũng tạo được không chống chối bỏ chữ ký chỉ khóa riêng ký ai giữ công khai đều kiểm mà không ký được, dùng ở đâu JWT RS256 ES256 cập nhật phần mềm ký số chứng chỉ TLS commit tag Git ký gói phần mềm apt rpm openssl dgst -sha256 -sign priv.pem ký openssl dgst -sha256 -verify pub.pem kiểm bên trong băm f rồi ký giá trị băm bằng khóa riêng

Hình 1: Chữ ký số dùng cặp khóa ngược với mã hóa — ký bằng riêng, xác thực bằng công khai. Bảo đảm xác thực + toàn vẹn + chống chối bỏ; khác HMAC (khóa chung) ở chỗ chỉ chủ khóa riêng ký được.

Đo thật: ký, xác thực, và các trường hợp thất bại

Ảnh chụp bảng kết quả đo thật nền tối chạy openssl 3.0 EC P-256 file Ban phat hanh v2.0 tai ve an toan, phần một ký bằng khóa riêng openssl dgst -sha256 -sign priv.pem -out file.sig file.txt ra file.sig chữ ký 71 byte, phần hai xác thực bằng khóa công khai OK openssl dgst -sha256 -verify pub.pem -signature file.sig file.txt Verified OK đúng người ký nội dung nguyên vẹn, phần ba sửa nội dung v2.0 thành v9.0 xác thực thất bại file2.txt là v9.0 sửa 1 ký tự Verification failure chữ ký không khớp nội dung mới, phần bốn xác thực bằng khóa công khai khác thất bại openssl dgst -verify other.pub -signature file.sig file.txt Verification failure chữ ký của khóa A khóa B không khớp

Hình 2: Ký file bằng khóa riêng → file.sig (71 byte). Xác thực bằng khóa công khai đúng → Verified OK. Sửa nội dung (v2.0→v9.0) → Verification failure. Xác thực bằng khóa công khai khác → Verification failure.

Kết quả xác nhận đủ tính chất:

  • Ký: openssl dgst -sha256 -sign priv.pem tạo file.sig (71 byte với ECDSA P-256). Chỉ người có priv.pem tạo được chữ ký này.
  • Xác thực đúng: -verify pub.pem với đúng chữ ký và đúng nội dung → Verified OK. Bất kỳ ai có khóa công khai đều kiểm được — không cần bí mật chung như HMAC.
  • Nội dung bị sửa: đổi "v2.0" thành "v9.0" rồi xác thực với chữ ký cũ → Verification failure. Chữ ký gắn chặt với nội dung (qua giá trị băm), sửa một ký tự là hỏng.
  • Sai khóa công khai: xác thực chữ ký hợp lệ bằng một khóa công khai khác → Verification failure. Chữ ký chỉ khớp với đúng khóa công khai cặp đôi của khóa riêng đã ký.

Đây chính xác là cơ chế đằng sau: JWT ký ES256/RS256 (server ký bằng riêng, client kiểm bằng công khai), bản cập nhật phần mềm ký số (bạn kiểm bằng khóa công khai của nhà phát hành → chắc chắn không phải bản giả), chứng chỉ TLS (CA ký), commit/tag Git ký, gói apt/rpm.

Đánh đổi và lưu ý

Xác thực chữ ký chỉ chứng minh "khóa nào ký", không phải "ai đáng tin". Verified OK nghĩa là chữ ký đúng khớp khóa công khai đó — nhưng khóa công khai đó có thật sự thuộc về người bạn nghĩ không? Đây là bài toán phân phối khóa công khai, giải bằng chuỗi tin cậy (chứng chỉ X.509 — bài trước) hoặc mạng tin cậy (PGP). Chữ ký hợp lệ bằng khóa của kẻ tấn công vẫn "Verified OK".

Ký cái gì cho đúng. Ký giá trị băm là chuẩn, nhưng phải ký đúng thứ cần bảo vệ và theo định dạng an toàn (RSA dùng PSS, ECDSA/EdDSA). Lỗi kinh điển: JWT "alg: none" (bỏ chữ ký) hay nhầm lẫn thuật toán (ký HS256 rồi verify như RS256) từng hạ nhiều hệ thống — luôn cố định thuật toán mong đợi khi verify.

Khóa riêng ký là tài sản tối mật. Lộ khóa riêng ký = kẻ tấn công ký được bản cập nhật giả, token giả, mọi thứ mang danh bạn. Bảo vệ như khóa mã hóa: mật khẩu bảo vệ, phân quyền, HSM/KMS cho hệ thống quan trọng. Và có cơ chế thu hồi (revocation) khi nghi lộ.

Ba ý mang về

  1. Chữ ký số dùng cặp khóa ngược với mã hóa: ký bằng khóa riêng (chỉ chủ khóa), xác thực bằng khóa công khai (ai cũng kiểm) — đo thật, Verified OK khi đúng, Verification failure khi sửa nội dung hay sai khóa.
  2. Khác HMAC ở chống chối bỏ: HMAC khóa chung nên bên kiểm cũng tạo được (không chứng minh ai ký); chữ ký chỉ khóa riêng ký được nên ai giữ công khai đều kiểm mà không giả được — nền của JWT, cập nhật phần mềm, chứng chỉ, Git ký.
  3. Xác thực chữ ký ≠ tin người: Verified OK chỉ chứng minh "khóa nào ký", còn khóa đó có đúng chủ không thì cần chuỗi tin cậy (X.509); cố định thuật toán khi verify (tránh alg:none), và bảo vệ khóa riêng tuyệt đối.

Nguồn

Phần sau ta xem cách hai bên tạo ra một khóa bí mật chung mà không hề gửi nó qua mạng: trao đổi khóa Diffie-Hellman — đo thật hai bên tính ra cùng một bí mật bằng openssl.