Mật mã ( Cryptography) phần 2

Chia sẻ: Nghia Bui Tuan | Ngày: | Loại File: PDF | Số trang:10

0
66
lượt xem
24
download

Mật mã ( Cryptography) phần 2

Mô tả tài liệu
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Bạn cần chuyển một file cho ai đó và cấp cho người này một phương cách để xác minh tính toàn vẹn của file. Cấp cho người nhận một khóa bí mật (key).

Chủ đề:
Lưu

Nội dung Text: Mật mã ( Cryptography) phần 2

  1. 1.1 Bảo đảm tính toàn vẹn dữ liệu bằng mã băm có khóa Bạn cần chuyển một file cho ai đó và cấp cho người này một phương cách để xác minh tính toàn vẹn của file. Cấp cho người nhận một khóa bí mật (key). Khóa này có thể là một số được sinh ngẫu nhiên, nhưng nó cũng có thể là một nhóm từ mà bạn và người nhận đã thỏa thuận. Sử dụng khóa cùng với một trong những lớp giải thuật băm có khóa dẫn xuất từ lớp System.Security.Cryptography.KeyedHashAlgorithm để tạo mã băm có khóa. Gửi mã băm này cùng với file. Khi nhận được file, người nhận sẽ tạo mã băm có khóa cho file này bằng khóa. Nếu hai mã băm giống nhau, người nhận sẽ biết rằng file này do bạn gửi đến và nó không bị thay đổi trong quá trình chuyển giao. Mã băm rất hữu ích khi so sánh hai mẩu dữ liệu để xác định chúng có giống nhau hay không (cả khi bạn không thể truy xuất được dữ liệu gốc). Tuy nhiên, bạn không thể sử dụng mã băm để cam đoan với người nhận về tính toàn vẹn của dữ liệu. Nếu có ai đó chặn được dữ liệu, người này có thể thay thế dữ liệu và tạo mã băm mới. Khi người nhận kiểm tra mã băm, nó có vẻ đúng nhưng thực tế dữ liệu không giống với những gì bạn gửi lúc ban đầu. Một giải pháp đơn giản và hiệu quả cho vấn đề toàn vẹn dữ liệu là mã băm có khóa (keyed hash code). Mã băm có khóa cũng tương tự như mã băm bình thường (đã được thảo luận trong mục 14.2 và 14.3); tuy nhiên, mã băm có khóa kết hợp thêm một phần tử dữ liệu bí mật (khóa), phần tử này chỉ có người gửi và người nhận biết. Nếu không có khóa, không ai có thể tạo được mã băm đúng từ tập dữ liệu cho trước. Khóa phải được giữ bí mật. Nếu ai đó biết khóa thì có thể tạo ra mã băm có khóa hợp lệ, nghĩa là bạn sẽ không thể xác định họ có thay đổi nội dung của tài liệu hay không. Vì lý do này, bạn không nên chuyển giao hay lưu trữ khóa cùng với tài liệu cần được bảo vệ tính toàn vẹn. Mục 14.10 sẽ cung cấp một cơ chế mà bạn có thể sử dụng để trao đổi khóa một cách an toàn. Tạo mã băm có khóa cũng tương tự như tạo mã băm bình thường vì lớp trừu tượng System.Security.Cryptography.KeyedHashAlgorithm mở rộng lớp System.Security.Cryptography.HashAlgorithm. Lớp KeyedHashAlgorithm cung cấp một lớp cơ sở để tất cả các giải thuật băm có khóa dẫn xuất từ đó. Thư viện lớp .NET Framework có hai hiện thực giải thuật băm có khóa được liệt kê trong bảng 14.2; mỗi hiện thực là một thành viên của không gian tên System.Security.Cryptography. Bảng 14.2 Các hiện thực giải thuật băm có khóa
  2. Kích thước mã băm Giải thuật/Tên lớp Kích thước khóa (bit) (bit) HMACSHA1 bất kỳ 160 MACTripleDES 64, 128, 192 64 Cũng như các giải thuật băm chuẩn, bạn có thể trực tiếp tạo ra các đối tượng giải thuật băm có khóa, hoặc bạn có thể sử dụng phương thức tĩnh KeyedHashAlgorithm.Create với đối số là tên giải thuật. Sử dụng factory cho phép bạn viết mã lệnh tổng quát và mã lệnh này có thể làm việc với bất kỳ hiện thực giải thuật băm có khóa nào, nhưng theo bảng 14.2, mỗi lớp hỗ trợ các chiều dài khóa khác nhau nên bạn phải cung cấp giá trị này trong mã lệnh tổng quát. Nếu sử dụng phương thức khởi dựng để tạo đối tượng băm có khóa, bạn có thể truyền khóa cho phương thức này. Khi sử dụng factory, bạn phải thiết lập khóa bằng thuộc tính Key (được thừa kế từ lớp KeyedHashAlgorithm). Một khi đã cấu hình khóa, gọi phương thức ComputeHash với đối số là một mảng byte hay một đối tượng System.IO.Stream. Giải thuật băm có khóa sẽ xử lý dữ liệu nhập và trả về một mảng byte chứa mã băm có khóa. Bảng 14.2 cho thấy kích thước của mã băm do mỗi giải thuật băm có khóa sinh ra. Lớp KeyedHashStreamExample dưới đây trình bày cách tạo mã băm có khóa từ một file. Bạn phải chỉ định tên file và một khóa làm đối số dòng lệnh. Ứng dụng này sử dụng lớp HMACSHA1 để tạo mã băm có khóa và rồi hiển thị nó ra cửa sổ Console. using System; using System.IO; using System.Text; using System.Security.Cryptography; public class KeyedHashStreamExample { public static void Main(string[] args) { // Tạo mảng byte từ chuỗi key (là đối số dòng lệnh thứ hai). byte[] key = Encoding.Unicode.GetBytes(args[1]); // Tạo một đối tượng HMACSHA1 // (truyền key cho phương thức khởi dựng). using (HMACSHA1 hashAlg = new HMACSHA1(key)) { // Mở một FileStream để đọc file (tên file
  3. // được chỉ định trong đối số dòng lệnh thứ nhất). using (Stream file = new FileStream(args[0], FileMode.Open)) { // Tạo mã băm có khóa cho nội dung file. byte[] hash = hashAlg.ComputeHash(file); // Hiển thị mã băm có khóa ra cửa sổ Console. Console.WriteLine(BitConverter.ToString(hash)); } } } } Lệnh KeyedHashStreamExample KeyedHashStreamExample.cs secretKey sẽ sinh ra mã băm như sau: 95-95-2A-8E-44-D4-3C-55-6F-DA-06-44-27-79-29-81-15-C7-2A-48 Ứng dụng KeyedHashMessageExample.cs (có trong đĩa CD đính kèm) trình bày cách tạo một mã băm có khóa từ một chuỗi. Ứng dụng này yêu cần hai đối số dòng lệnh: một thông điệp và một khóa, và sẽ tạo ra mã băm có khóa cho chuỗi thông điệp bằng khóa này. Ví dụ, lệnh KeyedHashMessageExample "Two hundred dollars is my final offer" secretKey sẽ sinh ra mã băm như sau: 83-43-0D-9D-07-6F-AA-B7-BC-79-CD-6F-AD-7B-FA-EA-19-D1-24-44 1.2 Bảo vệ file bằng phép mật hóa đối xứng Bạn cần mật hóa một file bằng giải thuật mật hóa đối xứng (symmetric encryption). Trước hết, bạn phải thể hiện hóa một trong các lớp giải thuật đối xứng cụ thể dẫn xuất từ lớp System.Security.Cryptography.SymmetricAlgorithm. Sau đó, gọi phương thức CreateEncryptor hay CreateDecryptor của đối tượng SymmetricAlgorithm để thu lấy một đối tượng có hiện thực giao diện System.Security.Cryptography.ICryptoTransform. Sử dụng đối tượng ICryptoTransform này kết hợp với một đối tượng System.Security.Cryptography.CryptoStream để mật hóa hay giải mật hóa dữ liệu đọc từ một file (được truy xuất bằng một đối tượng System.IO.FileStream). Lớp trừu tượng SymmetricAlgorithm cung cấp một lớp cơ sở để tất cả các hiện thực giải thuật đối xứng cụ thể dẫn xuất từ đó. Thư viện lớp .NET Framework có bốn hiện thực giải thuật đối xứng cụ thể được liệt kê trong bảng 14.3, mỗi lớp là một thành viên của không gian tên System.Security.Cryptography. Các lớp có đuôi là CryptoServiceProvider
  4. bọc lấy các chức năng do Win32 CryptoAPI cung cấp, trong khi các lớp có đuôi là Managed (hiện tại chỉ có RijndaelManaged) được hiện thực hoàn toàn bằng mã lệnh được-quản-lý. Bảng này cũng cho thấy chiều dài khóa mà mỗi giải thuật hỗ trợ (chiều dài mặc định được in đậm). Nói chung, khóa càng dài, càng khó giải mật hóa ciphertext nếu không có khóa, nhưng cũng có nhiều yếu tố khác cần xem xét. Bảng 14.3 Các hiện thực giải thuật đối xứng Chiều dài khóa Tên giải thuật Tên lớp (bit) DES DESCryptoServiceProvider 64 TripleDES hay TripleDESCryptoServiceProvider 128, 192 3DES 40, 48 56, 64, 72, RC2 RC2CryptoServiceProvider 80, 88, 96, 104, 112, 120, 128 Rijndael RijndaelManaged 128, 192, 256 Mặc dù bạn có thể tạo ra các thể hiện của các lớp giải thuật đối xứng một cách trực tiếp, lớp cơ sở SymmetricAlgorithm là một factory cho các lớp hiện thực cụ thể dẫn xuất từ đó. Gọi phương thức tĩnh SymmetricAlgorithm.Create với đối số là tên giải thuật sẽ trả về một đối tượng thuộc kiểu đã được chỉ định. Sử dụng factory cho phép bạn viết mã lệnh tổng quát, và mã lệnh này có thể làm việc với bất kỳ hiện thực giải thuật đối xứng nào: string algName = "3DES"; SymmetricAlgorithm alg = SymmetricAlgorithm.Create(algName); Nếu bạn gọi SymmetricAlgorithm.Create và không chỉ định tên giải thuật, SymmetricAlgorithm sẽ trả về một đối tượng RijndaelManaged. Nếu bạn chỉ định một giá trị không hợp lệ, SymmetricAlgorithm sẽ trả về null. Bạn có thể cấu hình các ánh xạ tên/lớp mới bằng file cấu hình (xem tài liệu .NET Framework SDK để biết thêm chi tiết). Trước khi mật hóa dữ liệu với một trong các lớp giải thuật đối xứng, bạn cần một khóa (key) và một vectơ khởi động (initialization vector). Khóa là thông tin bí mật dùng để mật hóa và giải mật hóa dữ liệu. Vectơ khởi động là dữ liệu ngẫu nhiên được truyền cho giải thuật mật hóa. Bạn phải sử dụng cùng khóa và vectơ khởi động cho cả mật hóa và giải mật hóa dữ liệu. Tuy nhiên, chỉ có khóa là cần phải được giữ bí mật, bạn có thể lưu trữ hay gửi vectơ khởi động cùng với dữ liệu đã-được-mật-hóa.
  5. Khóa cho mỗi lớp dẫn xuất từ SymmetricAlgorithm có thể được truy xuất thông qua thuộc tính Key, và vectơ khởi động có thể được truy xuất thông qua thuộc tính IV. Cách đơn giản nhất và ít lỗi nhất để tạo khóa và vectơ khởi động mới là để lớp tự tạo chúng giùm bạn. Sau khi đã tạo một đối tượng giải thuật đối xứng, nếu bạn không thiết lập các thuộc tính Key và IV cho nó, đối tượng này sẽ tự động tạo ra các giá trị mới ngay khi bạn cho gọi một thành viên có sử dụng các giá trị Key và IV. Một khi đã được thiết lập, đối tượng giải thuật đối xứng sẽ tiếp tục sử dụng các giá trị Key và IV này. Để thay đổi giá trị của Key và IV, bạn có thể gán trực tiếp các giá trị mới hoặc gọi phương thức GenerateKey và GenerateIV (buộc đối tượng giải thuật đối xứng tạo ra các giá trị ngẫu nhiên mới). Bạn không thể trực tiếp thực hiện mật hóa và giải mật hóa với một đối tượng giải thuật đối xứng. Một khi đã tạo và cấu hình đối tượng giải thuật đối xứng, bạn phải gọi phương thức CreateEncryptor hay CreateDecryptor của nó để thu lấy một đối tượng có hiện thực giao diện System.Security.Cryptography.ICryptoTransform. Kế đó, bạn có thể sử dụng các phương thức của đối tượng ICryptoTransform này để mật hóa và giải mật hóa dữ liệu. Tuy nhiên, đối tượng ICryptoTransform yêu cầu bạn truyền dữ liệu theo từng khối (có kích thước cố định) và lấp (bằng tay) khối dữ liệu cuối cùng vì khối này ít khi có kích thước đúng. Giao diện ICryptoTransform không quá khó sử dụng, nhưng không mấy thân thiện; do vậy .NET Framework kèm thêm lớp System.Security.Cryptography.CryptoStream. Đây là lớp dẫn xuất từ System.IO.Stream, dùng để đơn giản hóa việc mật hóa và giải mật hóa dữ liệu được đọc từ các đối tượng Stream khác. Lớp này cho phép bạn mật hóa và giải mật hóa dữ liệu từ các file và các kết nối mạng một cách dễ dàng bằng một mô hình xử lý quen thuộc, và nó cung cấp cho bạn tất cả các tiện ích quen thuộc khi truy xuất dữ liệu dựa-vào-Stream. Phương thức khởi dựng của CryptoStream yêu cầu ba đối số: một Stream nằm dưới, một thể hiện của ICryptoTransform, và một giá trị thuộc kiểu liệt kê System.Security.Cryptography.CryptoStreamMode. Giá trị CryptoStreamMode cho biết chế độ của đối tượng CryptoStream mới; các giá trị hợp lệ là Read và Write. Khi bạn gọi phương thức Read hay Write của CryptoStream, CryptoStream sẽ sử dụng thể hiện ICryptoTransform để mật hóa và giải mật hóa dữ liệu đang truyền qua CryptoStream. Đối tượng CryptoStream bảo đảm kích thước khối dùng cho thể hiện ICryptoTransform luôn đúng. Cấu hình của một đối tượng CryptoStream có tính linh hoạt cao, nhưng có thể hơi khó hiểu. Bảng 14.4 mô tả hoạt động của một đối tượng CryptoStream dựa trên chế độ của CryptoStream và kiểu thể hiện ICryptoTransform được sử dụng trong phương thức khởi dựng của CryptoStream.
  6. Bảng 14.4 Hoạt động của đối tượng CryptoStream Chế độ của Chỉ thị của Mô tả CryptoStream ICryptoTransform Stream nằm dưới chứa plaintext nguồn. Read Mật hóa CryptoStream.Read ghi ciphertext ra bộ đệm xuất. Stream nằm dưới chứa ciphertext nguồn. Read Giải mật hóa CryptoStream.Read ghi plaintext ra bộ đệm xuất. CryptoStream.Write chỉ định plaintext cần Write Mật hóa mật hóa. Stream nằm dưới nhận ciphertext đã-được-mật-hóa. CryptoStream.Write chỉ định ciphertext cần Write Giải mật hóa giải mật hóa. Stream nằm dưới nhận plaintext đã-được-giải-mật-hóa. Lớp SymmetricEncryptionExample dưới đây trình bày cách sử dụng giải thuật Triple DES để mật hóa một file và rồi giải mật hóa file đó. Phương thức Main nhận tên của file cần mật hóa làm đối số dòng lệnh. Trước tiên, nó sẽ tạo khóa và vectơ khởi động; sau đó, gọi phương thức EncryptFile, kế tiếp là phương thức DecryptFile, và sinh ra hai file: file thứ nhất chứa phiên bản đã-được-mật-hóa của file nguồn, file thứ hai chứa phiên bản đã- được-giải-mật-hóa của file đã-được-mật-hóa (giống file nguồn). using System; using System.IO; using System.Security.Cryptography; public class SymmetricEncryptionExample { public static void Main(string[] args) { // Tạo một giải thuật Triple DES mới để thu lấy khóa dùng cho // ví dụ này. Khóa này sẽ được dùng chung trong các phương thức // EncryptFile và DecryptFile. Bình thường, khóa được // thỏa thuận giữa người gửi và người nhận, hoặc được gửi // (bởi người gửi) cùng với file đã-được-mật-hóa. byte[] key; byte[] iv;
  7. using(SymmetricAlgorithm alg = SymmetricAlgorithm.Create("3DES")){ key = alg.Key; iv = alg.IV; } // Mật hóa file. Tiền tố "encrypted" sẽ được thêm vào tên file // nguồn và được sử dụng làm tên của file đã-được-mật-hóa. EncryptFile(args[0], "encrypted"+args[0], (byte[])key.Clone(), (byte[])iv.Clone()); // Giải mật hóa file đã-được-mật-hóa. Tiền tố "decrypted" sẽ được // thêm vào tên file gốc và được sử dụng làm tên của file // đã-được-giải-mật-hóa. DecryptFile("encrypted"+args[0], "decrypted"+args[0], key, iv); } // Phương thức dùng để mật hóa một file (bằng giải thuật Triple DES) // với key và iv cho trước. private static void EncryptFile(string srcFileName, string destFileName, byte[] key, byte[] iv) { // Tạo các stream để truy xuất file nguồn và file đích. Stream srcFile = new FileStream(srcFileName, FileMode.Open, FileAccess.Read); Stream destFile = new FileStream(destFileName, FileMode.Create, FileAccess.Write); // Tạo một giải thuật Triple DES mới để mật hóa file. using(SymmetricAlgorithm alg = SymmetricAlgorithm.Create("3DES")){ // Cấu hình thuộc tính Key và IV của giải thuật. alg.Key = key; alg.IV = iv; // Tạo một CryptoStream để mật hóa nội dung của
  8. // Stream nguồn khi nó được đọc. Gọi phương thức // CreateEncryptor của SymmetricAlgorithm // để nhận thể hiện ICryptoTransform và // truyền nó cho CryptoStream. CryptoStream cryptoStream = new CryptoStream(srcFile, alg.CreateEncryptor(), CryptoStreamMode.Read); // Khai báo bộ đệm dùng để đọc dữ liệu từ file nguồn // thông qua CryptoStream và ghi nó ra file đích. int bufferLength; byte[] buffer = new byte[1024]; // Đọc file nguồn (từng khối 1024 byte) và ghi phiên bản // đã-được-mật-hóa ra file đích. do { bufferLength = cryptoStream.Read(buffer, 0, 1024); destFile.Write(buffer, 0, bufferLength); } while (bufferLength > 0); // Đóng stream và xóa các dữ liệu bí mật. destFile.Flush(); Array.Clear(key,0,key.Length); Array.Clear(iv,0,iv.Length); cryptoStream.Clear(); cryptoStream.Close(); srcFile.Close(); destFile.Close(); } } // Phương thức dùng để giải mật hóa một file đã-được-mật-hóa bằng // giải thuật Triple DES với key và iv cho trước. private static void DecryptFile(string srcFileName, string destFileName, byte[] key, byte[] iv) { // Tạo các stream để truy xuất file nguồn và file đích. Stream srcFile = new FileStream(srcFileName, FileMode.Open, FileAccess.Read);
  9. Stream destFile = new FileStream(destFileName, FileMode.Create, FileAccess.Write); // Tạo một giải thuật Triple DES mới để giải mật hóa file. using(SymmetricAlgorithm alg = SymmetricAlgorithm.Create("3DES")){ // Cấu hình thuộc tính Key và IV của giải thuật. alg.Key = key; alg.IV = iv; // Tạo một CryptoStream để giải mật hóa nội dung của dữ liệu // đã-được-mật-hóa khi nó được ghi. Gọi phương thức // CreateDecryptor của SymmetricAlgorithm để nhận thể hiện // ICryptoTransform và truyền nó cho CryptoStream. CryptoStream cryptoStream = new CryptoStream(destFile, alg.CreateDecryptor(), CryptoStreamMode.Write); // Khai báo bộ đệm dùng để đọc dữ liệu từ file đã-được- // mật-hóa và ghi ra file đích thông qua CryptoStream. int bufferLength; byte[] buffer = new byte[1024]; // Đọc file đã-được-mật-hóa (từng khối 1024 byte) và ghi // phiên bản đã-được-giải-mật-hóa ra file đích. do { bufferLength = srcFile.Read(buffer, 0, 1024); cryptoStream.Write(buffer, 0, bufferLength); } while (bufferLength > 0); // Đóng stream và xóa các dữ liệu bí mật. cryptoStream.FlushFinalBlock(); Array.Clear(key,0,key.Length); Array.Clear(iv,0,iv.Length); cryptoStream.Clear(); cryptoStream.Close(); srcFile.Close();
  10. destFile.Close(); } } }
Đồng bộ tài khoản