571 Chương 14: Mật mã using System.Text; using System.Security.Cryptography; public class AsymmetricEncryptionExample { public static void Main(string[] args) { // Khai báo một biến RSAParameters, biến này sẽ chứa // thông tin PUBLIC KEY của người nhận. RSAParameters recipientsPublicKey; // Khai báo một biến CspParameters, biến này sẽ cho biết // PRIVATE KEY được lưu trữ trong kho chứa khóa nào. // Thông thường, chỉ có người nhận mới có thể truy xuất // thông tin này. Với mục đích minh họa, chúng ta sẽ tạo // một cặp khóa ngay đầu ví dụ và sử dụng các khóa này // cho cả bên gửi và bên nhận. CspParameters cspParams = new CspParameters(); cspParams.KeyContainerName = "MyKeys"; // Tạo cặp khóa bất đối xứng bằng lớp RSACryptoServiceProvider. // Lưu các khóa này vào một kho chứa khóa có tên là "MyKeys" // và trích thông tin PUBLIC KEY vào biến recipientsPublicKey. using (RSACryptoServiceProvider rsaAlg = new RSACryptoServiceProvider(cspParams)) { // Cấu hình cho giải thuật lưu khóa vào kho chứa khóa. rsaAlg.PersistKeyInCsp = true; // Trích PUBLIC KEY. recipientsPublicKey = rsaAlg.ExportParameters(false); } // Hiển thị thông điệp plaintext gốc. Console.WriteLine("Original message = {0}", args[0]); // Chuyển thông điệp gốc thành mảng byte. Tốt nhất là không // truyền các thông tin bí mật ở dạng chuỗi giữa các phương thức. 572 Chương 14: Mật mã byte[] plaintext = Encoding.Unicode.GetBytes(args[0]); // Mật hóa thông điệp bằng phương thức EncryptMessage. // Phương thức này cần PUBLIC KEY của người nhận. byte[] ciphertext = EncryptMessage(plaintext, recipientsPublicKey); // Hiển thị ciphertext do phương thức EncryptMessage trả về. // Sử dụng phương thức BitConverter.ToString method cho đơn giản // mặc dù nó chèn dấu gạch nối (-) vào giữa các giá trị byte // (không đúng với biểu diễn dữ liệu trong bộ nhớ). Console.WriteLine("Formatted Ciphertext = {0}", BitConverter.ToString(ciphertext)); // Giải mật hóa thông điệp (đã-được-mật-hóa) bằng phương thức // DecryptMessage. Phương thức này cần truy xuất PRIVATE KEY // của người nhận (chỉ có người nhận mới có thể truy xuất được). // Chúng ta sẽ truyền cho nó một đối tượng CspParameters // (cho biết PRIVATE KEY được lưu trữ trong kho chứa khóa nào). // Giải pháp này an toàn hơn là truyền PRIVATE KEY thô // giữa các phương thức. byte[] decData = DecryptMessage(ciphertext, cspParams); // Chuyển thông điệp đã-được-giải-mật-hóa từ mảng byte // thành chuỗi và hiển thị nó ra cửa sổ Console. Console.WriteLine("Decrypted message = {0}", Encoding.Unicode.GetString(decData)); // Nhấn Enter để kết thúc. Console.ReadLine(); } // Phương thức dùng để mật hóa (theo RSA) một thông điệp bằng // PUBLIC KEY (nằm trong một cấu trúc RSAParameters). private static byte[] EncryptMessage(byte[] plaintext, RSAParameters rsaParams) { 573 Chương 14: Mật mã // Khai báo mảng byte chứa ciphertext. byte[] ciphertext = null; // Tạo một thể hiện của giải thuật RSA. using (RSACryptoServiceProvider rsaAlg = new RSACryptoServiceProvider()) { rsaAlg.ImportParameters(rsaParams); // Mật hóa plaintext bằng OAEP padding // (chỉ được hỗ trợ trên Windows XP trở về sau). ciphertext = rsaAlg.Encrypt(plaintext, true); } // Xóa các giá trị được giữ trong mảng byte chứa plaintext. // Điều này bảo đảm dữ liệu bí mật không còn trong bộ nhớ // sau khi bạn giải phóng tham chiếu đến nó. Array.Clear(plaintext, 0, plaintext.Length); return ciphertext; } // Phương thức dùng để giải mật hóa một thông điệp (đã-được-mật-hóa- // theo-RSA) bằng PRIVATE KEY (do đối tượng CspParameters chỉ định). private static byte[] DecryptMessage(byte[] ciphertext, CspParameters cspParams ) { // Khai báo mảng byte chứa plaintext (đã-được-giải-mật-hóa). byte[] plaintext = null; // Tạo một thể hiện của giải thuật RSA. using (RSACryptoServiceProvider rsaAlg = new RSACryptoServiceProvider(cspParams)) { // Giải mật hóa plaintext bằng OAEP padding. plaintext = rsaAlg.Decrypt(ciphertext, true); } 574 Chương 14: Mật mã return plaintext; } } Lệnh AsymmetricEncryptionExample "I love you!" sẽ sinh ra kết xuất tương tự như sau: Original message = I love you! Formatted Ciphertext = 1F-53-05-2B-9D-CC-20-6B-5D-D3-D4-0B-C9-5F-CA-FA-C1-61-6C- 3B-5B-9E-EA-B9-D0-AF-E5-2B-05-BC-D4-94-DD-71-D6-21-2A-B0-82-6B-16-C0-89-3E-24-B3- B3-A3-15-FE-16-7A-B0-58-14-43-CD-69-1A-FD-08-39-2D-09-A6-41-86-96-78-B4-3D-D6-C7- 39-8A-90-84-D6-68-E6-5D-86-32-14-67-51-A7-B7-5A-EF-CF-F4-6D-E4-B0-18-6A-16-2A-AF- 54-B7-3C-B8-19-6E-A5-86-BF-3E-B2-6D-17-E3-1D-E8-AD-D1-A8-D9-54-93-8E-F1-E8-5D-AC- 4A Decrypted message = I love you! Nếu bạn chạy ví dụ này nhiều lần với cùng thông điệp và khóa, ciphertext sẽ khác nhau. Đó là vì cơ chế padding sinh ra dữ liệu ngẫu nhiên để tránh các dạng tấn công bằng mật mã. Mặc dù hơi rắc rối nhưng đây chính là cách hành xử mà ta mong đợi. 9. 9. L u tr khóa b t đ i x ng m t cách an toàn ư ữ ấ ố ứ ộ L u tr khóa b t đ i x ng m t cách an toàn ư ữ ấ ố ứ ộ Bạn cần lưu trữ cặp khóa bất đối xứng vào một nơi an toàn để ứng dụng của bạn có thể truy xuất được dễ dàng. Dựa vào chức năng lưu trữ khóa do hai lớp giải thuật bất đối xứng cung cấp ( RSACryptoServiceProvider và DSACryptoServiceProvider —thuộc không gian tên System.Security.Cryptography ). Cả hai lớp giải thuật bất đối xứng— RSACryptoServiceProvider và DSACryptoServiceProvider —đều bọc lấy các chức năng do CSP (Cryptographic Service Provider—một thành phần của Win32 CryptoAPI) hiện thực. Ngoài các dịch vụ như mật hóa, giải mật hóa, và chữ ký số, mỗi CSP còn cung cấp một kho chứa khóa (key container). Kho chứa khóa là vùng lưu trữ dành cho các khóa mà CSP quản lý; CSP sử dụng cơ chế bảo mật của hệ điều hành và phép mật hóa mạnh để bảo vệ nội dung của kho chứa khóa. Kho chứa khóa cho phép ứng dụng dễ dàng truy xuất khóa mà không ảnh hưởng đến tính bảo mật của khóa. Khi gọi các hàm của một CSP, ứng dụng cần chỉ định tên của kho chứa khóa và CSP sẽ truy xuất các khóa cần thiết. Vì khóa không truyền từ CSP đến ứng dụng nên ứng dụng không thể làm hại tính bảo mật của khóa. Lớp RSACryptoServiceProvider và DSACryptoServiceProvider cho phép bạn cấu hình hiện thực CSP nằm dưới bằng một thể hiện của lớp System.Security.Cryptography. CspParameters . Để cấu hình cho một đối tượng RSACryptoServiceProvider hay DSACryptoServiceProvider sử dụng một kho chứa khóa cụ thể, bạn phải hoàn tất các bước dưới đây: 1. Tạo một đối tượng CspParameters . 575 Chương 14: Mật mã 2. Thiết lập trường KeyContainerName của đối tượng CspParameters là một giá trị chuỗi mô tả tên của kho chứa khóa cần sử dụng; chuỗi có thể chứa khoảng trắng. 3. Tạo một đối tượng RSACryptoServiceProvider hay DSACryptoServiceProvider , và truyền đối tượng CspParameters làm đối số cho phương thức khởi dựng. Nếu kho chứa khóa tồn tại bên trong tầm vực của CSP và chứa các khóa thích hợp, CSP sẽ sử dụng các khóa này khi thực hiện các thao tác mật mã. Nếu kho chứa khóa hay khóa không tồn tại, CSP sẽ tự động tạo khóa mới. Để buộc CSP lưu trữ các khóa mới được tạo vào kho chứa khóa, bạn phải thiết lập thuộc tính PersistKeyInCsp (của đối tượng RSACryptoServiceProvider hay DSACryptoServiceProvider ) là true . Phương thức LoadKeys dưới đây là một đoạn trích trong file StoreAsymmetricKeyExample.cs (xem đĩa CD đính kèm). LoadKeys tạo một đối tượng RSACryptoServiceProvider và cấu hình cho nó sử dụng một kho chứa khóa có tên là MyKeys . Bằng cách chỉ định PersistKeyInCsp là true , giải thuật sẽ tự động lưu trữ các khóa mới được tạo vào kho chứa khóa này. // Phương thức này tạo một đối tượng RSACryptoServiceProvider // và nạp các khóa từ một kho chứa khóa nếu chúng tồn tại; nếu không, // RSACryptoServiceProvider sẽ tự động tạo các khóa mới và lưu // chúng vào kho chứa khóa để sử dụng sau này. public static void LoadKeys(string container) { // Tạo một đối tượng CspParameters và thiết lập trường // KeyContainerName là tên của kho chứa khóa. System.Security.Cryptography.CspParameters cspParams = new System.Security.Cryptography.CspParameters(); cspParams.KeyContainerName = container; // Tạo một đối tượng giải thuật RSA và truyền đối tượng // CspParameters làm đối số trong phương thức khởi dựng. using (System.Security.Cryptography.RSACryptoServiceProvider rsaAlg = new System.Security.Cryptography.RSACryptoServiceProvider(cspParams)){ // Cấu hình cho đối tượng RSACryptoServiceProvider // lưu trữ khóa vào kho chứa khóa. rsaAlg.PersistKeyInCsp = true; // Hiển thị PUBLIC KEY. System.Console.WriteLine(rsaAlg.ToXmlString(false)); } } 576 Chương 14: Mật mã Lớp RSACryptoServiceProvider và DSACryptoServiceProvider không cung cấp phương thức nào trực tiếp gỡ bỏ kho chứa khóa. Để xóa các khóa đã được lưu trữ, bạn hãy thiết lập giá trị của PersistKeyInCsp là false và gọi phương thức Clear hay Dispose của đối tượng RSACryptoServiceProvider hay DSACryptoServiceProvider . Phương thức DeleteKeys dưới đây sẽ trình bày kỹ thuật này: // Phương thức này tạo một đối tượng RSACryptoServiceProvider // và xóa các khóa hiện có khỏi kho chứa khóa. public static void DeleteKeys(string container) { // Tạo một đối tượng CspParameters và thiết lập trường // KeyContainerName là tên của kho chứa khóa cần xóa. System.Security.Cryptography.CspParameters cspParams = new System.Security.Cryptography.CspParameters(); cspParams.KeyContainerName = container; // Tạo một đối tượng giải thuật RSA và truyền đối tượng // CspParameters làm đối số trong phương thức khởi dựng. using (System.Security.Cryptography.RSACryptoServiceProvider rsaAlg = new System.Security.Cryptography.RSACryptoServiceProvider(cspParams)){ // Cấu hình cho đối tượng RSACryptoServiceProvider // không lưu trữ khóa vào kho chứa khóa. rsaAlg.PersistKeyInCsp = false; // Hiển thị PUBLIC KEY. Vì chúng ta gọi Dispose() // sau lời gọi này nên các khóa hiện có sẽ không thay đổi // cho đến khi phương thức được gọi lần thứ hai. System.Console.WriteLine(rsaAlg.ToXmlString(false)); // Vì mã lệnh nằm trong khối "using" nên Dispose được gọi // trên đối tượng RSACryptoServiceProvider. Vì đối tượng // này được cấu hình là không lưu trữ khóa nên kho chứa khóa // sẽ bị xóa. Thay vì gọi Dispose(), gọi rsaAlg.Clear() // sẽ có cùng tác dụng, vì nó gián tiếp gọi Dispose(). } 577 Chương 14: Mật mã } Win32 CryptoAPI hỗ trợ cả user-key-store và machine-key-store. Hệ điều hành Windows bảo đảm một user-key-store chỉ có thể được truy xuất bởi người đã tạo ra nó, nhưng một machine- key-store có thể được truy xuất bởi bất kỳ người dùng nào của máy. Theo mặc định, lớp RSACryptoServiceProvider và DSACryptoServiceProvider sẽ sử dụng user-key-store. Bạn có thể chỉ định sử dụng machine-key-store bằng cách thiết lập thuộc tính tĩnh UseMachineKeyStore của lớp RSACryptoServiceProvider hay DSACryptoServiceProvider là true . Điều này sẽ có tác dụng với tất cả mã lệnh đang chạy trong miền ứng dụng hiện hành. Nếu muốn kiểm soát chặt chẽ hơn, bạn có thể thiết lập thuộc tính CspParameters.Flags là giá trị System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore trước khi tạo đối tượng mật hóa bất đối xứng. Bạn nên xét các yêu cầu bảo mật một cách cẩn thận trước khi chọn sử dụng machine-key-store . Thực tế là người dùng nào có quyền truy xuất máy đều có thể giành được quyền truy xuất các khóa trong kho lưu trữ, điều này phủ định hầu hết các lợi ích do phép mật hóa bất đối xứng mang lại. 10. 10. Trao đ i khóa phiên đ i x ng m t cách an toànổ ố ứ ộ Trao đ i khóa phiên đ i x ng m t cách an toànổ ố ứ ộ Bạn cần trao đổi dữ liệu đã-được-mật-hóa-đối-xứng với ai đó, và bạn cần một biện pháp an toàn để phân bổ khóa phiên ( session key ) đối xứng cùng với dữ liệu. Sử dụng cơ chế trao đổi khóa do lớp System.Security.Cryptography. RSACryptoServiceProvider hiện thực. Theo cơ chế này, khóa đối xứng sẽ được mật hóa bất đối xứng bằng khóa công khai ( public key ) của người nhận. Theo đó, bạn có thể gửi khóa đối xứng đã-được-mật-hóa cùng với dữ liệu đã-được-mật- hóa. Người nhận phải giải mật hóa khóa đối xứng bằng khóa riêng ( private key ), rồi mới tiến hành giải mật hóa dữ liệu. Mỗi khi mật hóa dữ liệu (bằng giải thuật đối xứng) để chuyển giao, bạn nên tạo một khóa mới, được gọi là khóa phiên (session key). Sử dụng khóa phiên có hai lợi ích chính: • Nếu ai đó (không được phép) lấy được nhiều khối ciphertext đã được mật hóa bằng cùng một khóa đối xứng, khả năng người đó giải được dữ liệu sẽ tăng cao. • Nếu ai đó tìm được khóa phiên của bạn, người này chỉ có thể truy xuất được một tập dữ liệu nào đó đã-được-mật-hóa, chứ không phải tất cả các bí mật của bạn ở quá khứ và tương lai. Vấn đề đối với khóa phiên là phân bổ và bảo mật khóa. Một giải pháp là thỏa thuận một lượng lớn khóa phiên với những người mà bạn cần trao đổi dữ liệu với họ. Thật không may, việc này nhanh chóng trở nên khó quản lý; và thực tế là tất cả các khóa của bạn trong tương lai đều được lưu trữ tại một nơi nào đó, điều này tăng khả năng chúng sẽ bị xâm hại. Cách tốt hơn là gửi khóa phiên theo một dạng được mật hóa mạnh cùng với dữ liệu mà bạn đã mật hóa với khóa đó—quá trình này được gọi là trao đổi khóa (key exchange). Quá trình trao đổi khóa sử dụng phép mật hóa bất đối xứng để mật hóa khóa phiên đối xứng. Nếu muốn gửi dữ liệu cho ai đó, bạn tạo một khóa phiên đối xứng, mật hóa dữ liệu, và rồi mật hóa khóa phiên bằng khóa công khai của người nhận. Khi nhận được dữ liệu, người nhận giải mật hóa khóa phiên bằng khóa riêng của họ, và rồi giải mật hóa dữ liệu. Quan trọng là việc 578 Chương 14: Mật mã trao đổi khóa cho phép bạn trao đổi các lượng dữ liệu lớn (đã-được-mật-hóa) với bất cứ ai, thậm chí những người bạn chưa từng tiếp xúc trước đây, miễn là bạn có thể truy xuất khóa công khai đối xứng của họ. Một cách lý tưởng, bạn sử dụng một giải thuật bất đối xứng để mật hóa tất cả dữ liệu, như thế tránh được nhu cầu trao đổi các khóa đối xứng. Tuy nhiên, tốc độ của các giải thuật bất đối xứng khi mật hóa và giải mật hóa dữ liệu khiến chúng không thực tế cho việc sử dụng với các lượng lớn dữ liệu. Sử dụng các giải thuật bất đối xứng để mật hóa các khóa phiên đối xứng là một giải pháp tuy phức tạp hơn, nhưng là tốt nhất ở cả hai mặt: tính linh hoạt và tính nhanh chóng. Thư viện lớp .NET Framework hỗ trợ việc trao đổi khóa chỉ với giải thuật RSA, nhưng bạn phải lựa chọn giữa hai formatting scheme: Optimal Asymmetric Encryption Padding (OAEP) và PKCS #1 v 1.5. Bàn về các formatting scheme này vượt quá phạm vi của quyển sách này. Nói chung, bạn nên sử dụng OAEP formatting trừ khi bạn có nhu cầu giao tiếp với một hệ thống cũ có sử dụng PKCS formatting. Hai lớp dưới đây hiện thực cơ chế trao đổi khóa, mỗi cơ chế ứng với một formatting scheme: • System.Security.Cryptography.RSAOAEPKeyExchangeFormatter • System.Security.Cryptography.RSAPKCS1KeyExchangeFormatter Để chuẩn bị một khóa đối xứng dùng cho trao đổi, bạn phải tạo một đối tượng formatter với kiểu như mong muốn và rồi ấn định một đối tượng giải thuật bất đối xứng ( RSACryptoServiceProvider ) cho formatter bằng phương thức SetKey của formatter. Bạn phải cấu hình cho giải thuật bất đối xứng sử dụng khóa công khai của người nhận. Khi đã cấu hình xong, gọi phương thức CreateKeyExchange của formatter và truyền một mảng byte chứa khóa phiên đối xứng mà bạn cần định dạng. Phương thức CreateKeyExchange trả về một mảng byte chứa dữ liệu bạn sẽ gửi đi. Giải định dạng cho khóa ngược với quá trình định dạng. Có hai lớp deformatter, mỗi lớp ứng với một formatting scheme. • System.Security.Cryptography.RSAOAEPKeyExchangeDeformatter • System.Security.Cryptography.RSAPKCS1KeyExchangeDeformatter Để giải định dạng một khóa phiên đã được định dạng, hãy tạo một đối tượng deformatter với kiểu phù hợp rồi gọi phương thức SetKey của nó để ấn định một đối tượng giải thuật bất đối xứng. Bạn phải nạp khóa riêng của bạn vào giải thuật bất đối xứng. Cuối cùng, gọi phương thức DecryptKeyExchange với đối số là dữ liệu trao đổi. Phương thức này trả về một mảng byte chứa khóa phiên đối xứng gốc. File KeyExchangeExample.cs chứa ví dụ minh họa cho việc trao đổi khóa. Phương thức Main mô phỏng việc tạo, định dạng, trao đổi, và giải định dạng một khóa phiên đối xứng. Nó sẽ tạo một cặp khóa bất đối xứng để sử dụng cho cả ví dụ này. Thực tế, người gửi (người tạo khóa đối xứng) chỉ có khóa công khai của người nhận; người nhận có khóa riêng (được giữ bí mật). 579 Chương 14: Mật mã Cũng như nên sử dụng một khóa đối xứng có chiều dài phù hợp với tính bí mật của dữ liệu đang được bảo vệ, bạn nên mật hóa khóa phiên bằng một giải thuật bất đối xứng và chiều dài khóa ít nhất cũng phải tương đương với khóa đối xứng. Nếu khóa bất đối xứng yếu hơn khóa đối xứng, có khả năng kẻ tấn công sẽ phá vỡ giải thuật bất đối xứng và thu lấy khóa đối xứng thay vì cố giải mật hóa dữ liệu đã-được-mật-hóa-đối-xứng. Xem [ http://www.ietf.org/rfc/rfc3766.txt ] (có trong đĩa CD đính kèm) để biết chi tiết về sự tương đương giữa chiều dài khóa đối xứng và bất đối xứng. Kế đó, phương thức Main gọi phương thức FormatKeyExchange với đối số là một mảng byte chứa khóa đối xứng và một đối tượng RSAParameters chứa khóa công khai của người nhận. Phương thức FormatKeyExchange trả về một mảng byte chứa khóa đối xứng đã-được-mật-hóa và đã-được-định-dạng, chuẩn bị gửi đi. Kế tiếp, phương thức Main gọi phương thức DeformatKeyExchange với đối số là dữ liệu trao đổi đã được định dạng và đối tượng CspParameters chứa một tham chiếu đến kho chứa khóa MyKeys (chứa khóa riêng của người nhận). Trong suốt quá trình này, phương thức Main sẽ hiển thị khóa phiên gốc, dữ liệu trao đổi đã được định dạng, và cuối cùng là khóa phiên đã được giải định dạng. using System; using System.Text; using System.Security.Cryptography; public class KeyExchangeExample { public static void Main() { // Khai báo một biến RSAParameters, biến này sẽ // chứa thông tin PUBLIC KEY của người nhận. RSAParameters recipientsPublicKey; // Khai báo một biến CspParameters, biến này sẽ cho biết // PRIVATE KEY được lưu trữ trong kho chứa khóa nào. // Thông thường, chỉ có người nhận mới có thể truy xuất // thông tin này. Với mục đích minh họa, chúng ta sẽ tạo // một cặp khóa ngay đầu ví dụ và sử dụng các khóa này // cho cả bên gửi và bên nhận. CspParameters cspParams = new CspParameters(); cspParams.KeyContainerName = "MyKeys"; // Tạo cặp khóa bất đối xứng bằng lớp RSACryptoServiceProvider. // Lưu các khóa này vào một kho chứa khóa có tên là "MyKeys" 580 Chương 14: Mật mã // và trích thông tin PUBLIC KEY vào biến recipientsPublicKey. using (RSACryptoServiceProvider rsaAlg = new RSACryptoServiceProvider(cspParams)) { // Cấu hình cho giải thuật lưu khóa vào kho chứa khóa. rsaAlg.PersistKeyInCsp = true; // Trích PUBLIC KEY. recipientsPublicKey = rsaAlg.ExportParameters(false); } // Tạo giải thuật đối xứng Triple-DES và sử dụng // khóa được sinh tự động làm khóa phiên. using (SymmetricAlgorithm symAlg = SymmetricAlgorithm.Create("3DES")) { // Hiển thị khóa phiên gốc. Console.WriteLine("Session Key at Source = {0}\n\r", BitConverter.ToString(symAlg.Key)); // Chuẩn bị khóa phiên đối xứng dùng cho trao đổi // (sử dụng phương thức FormatKeyExchange, phương thức // này cần khóa dùng để mật hóa và PUBLIC KEY // của người nhận). byte[] exchangeData = FormatKeyExchange(symAlg.Key, recipientsPublicKey); // Hiển thị khóa phiên đã-được-mật-hóa (do phương thức // FormatKeyExchange trả về). Console.WriteLine("Exchange Data = {0}\n\r", BitConverter.ToString(exchangeData)); // ****** GỬI KHÓA ****** // Bây giờ, khóa phiên có thể được gửi đi bằng các // kênh giao tiếp bình thường. . hóa và giải mật hóa dữ liệu khiến chúng không thực tế cho việc sử dụng với các lượng lớn dữ liệu. Sử dụng các giải thuật bất đối xứng để mật hóa các khóa phiên đối xứng là một giải pháp tuy. của họ. Một cách lý tưởng, bạn sử dụng một giải thuật bất đối xứng để mật hóa tất cả dữ liệu, như thế tránh được nhu cầu trao đổi các khóa đối xứng. Tuy nhiên, tốc độ của các giải thuật bất. và chứa các khóa thích hợp, CSP sẽ sử dụng các khóa này khi thực hiện các thao tác mật mã. Nếu kho chứa khóa hay khóa không tồn tại, CSP sẽ tự động tạo khóa mới. Để buộc CSP lưu trữ các khóa