2010-01-27 74 views
10

Tôi tuân theo quy trình mã hóa/giải mã đối xứng trong C#. Tôi biết đã có một vài câu hỏi về chủ đề này trước đây, nhưng hầu hết các câu trả lời dường như là về triết lý mã hóa thay vì đưa ra mã thực tế.Mã hóa/giải mã đối xứng trong .NET

Cập nhật: Tôi thực sự muốn xem một số mã, thay vì chỉ liên kết. Cảm ơn nhiều!

+1

Rijndael không đối xứng? –

+0

Tôi tin rằng đó là –

+1

Tôi khuyên bạn nên sử dụng Rijndael, sau đó :) –

Trả lời

11

Xem mã ví dụ ở cuối this page.

Sao chép-dán nó ở đây:

int Rfc2898KeygenIterations= 100; 
int AesKeySizeInBits = 128; 
String Password = "VerySecret!"; 
byte[] Salt = new byte[16]; 
System.Random rnd = new System.Random(); 
rnd.NextBytes(Salt); 
byte[] rawPlaintext = System.Text.Encoding.Unicode.GetBytes("This is all clear now!"); 
byte[] cipherText= null; 
byte[] plainText= null; 
using (Aes aes = new AesManaged()) 
{ 
    aes.Padding = PaddingMode.PKCS7; 
    aes.KeySize = AesKeySizeInBits; 
    int KeyStrengthInBytes= aes.KeySize/8; 
    System.Security.Cryptography.Rfc2898DeriveBytes rfc2898 = 
     new System.Security.Cryptography.Rfc2898DeriveBytes(Password, Salt, Rfc2898KeygenIterations); 
    aes.Key = rfc2898.GetBytes(KeyStrengthInBytes); 
    aes.IV = rfc2898.GetBytes(KeyStrengthInBytes); 
    using (MemoryStream ms = new MemoryStream()) 
    { 
     using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write)) 
     { 
      cs.Write(rawPlaintext, 0, rawPlaintext.Length); 
     } 
     cipherText= ms.ToArray(); 
    } 

    using (MemoryStream ms = new MemoryStream()) 
    { 
     using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write)) 
     { 
      cs.Write(cipherText, 0, cipherText.Length); 
     } 
     plainText = ms.ToArray(); 
    } 
} 
string s = System.Text.Encoding.Unicode.GetString(plainText); 
Console.WriteLine(s); 
+5

Ewww, sử dụng Random không an toàn để tạo muối? Ý tưởng tồi tệ. – blowdart

+6

@blowdart - Không. Muối và IV cần phải độc đáo nhất có thể, nhưng tạo ra chúng một cách an toàn có nghĩa là không có gì. An toàn ngẫu nhiên có nghĩa là ngẫu nhiên khó dự đoán, và bạn không quan tâm nếu IV hoặc muối của bạn được dự đoán - chúng được truyền/lưu trữ trong văn bản thuần túy. – orip

+0

@blowdart - Tôi thừa nhận quan điểm của bạn về IV ở chế độ CBC. Nó không giữ cho muối trong PBKDF2 mặc dù. – orip

2

Chuyển đổi văn bản của bạn, chìa khóa và khởi tạo vector để byte đầu tiên bằng cách sử dụng mã hóa của sự lựa chọn của bạn. Sau đó sử dụng các nhà cung cấp DES ba, như đã chứng minh ở đây:

http://msdn.microsoft.com/en-us/library/system.security.cryptography.tripledes.aspx

Hoặc một cho AES, nếu bạn nghĩ triple DES là quá cũ-trường, hoặc bất cứ điều gì.

Ngoài sự tò mò, bạn định lập kế hoạch truyền thông khóa bí mật như thế nào?

+1

Vì vậy, bạn đang cố mã hóa dữ liệu để ngăn người dùng đọc nó? –

+0

Đối với DES, khóa và IV có thể là chuỗi ký tự bất kỳ, phải không? –

+5

Mã hóa khóa trong nguồn của ứng dụng .NET là vô vọng. Tất cả người dùng phải làm là tải xuống Reflector và chìa khóa là ngay ở đó trong cảnh đồng bằng. –

5

Tốt cho các phím khởi động không phải là chuỗi, các phím là các đốm màu nhị phân. PlainText là như nhau, nó không thực sự là văn bản, một lần nữa nó là một đốm màu nhị phân. Bây giờ tất nhiên bạn có thể chuyển đổi chuỗi thành mảng byte bằng cách sử dụng Encoding.UTF8.GetBytes(message), tuy nhiên khi chuyển đổi các phím qua lại phức tạp hơn một chút, bạn thường sử dụng Convert.ToBase64StringConvert.FromBase64String.

Đừng quên rằng mật mã khối cũng cần một điều nữa, những khởi Vector, vì vậy thực sự chữ ký phương pháp của bạn nên được

byte[] Encrypt(byte[] plainText, byte[] key, byte[] iv) 

byte[] Decrypt(byte[] cipherText, byte[] key, byte[] iv) 

Chìa khóa và IV phải mã hóa an toàn số ngẫu nhiên, don' t chỉ cần gõ chúng và không sử dụng chức năng ngẫu nhiên của C#. Kích thước của khóa và IV phụ thuộc vào thuật toán mã hóa được sử dụng và có thể được truy cập bởi các thuộc tính trên các lớp.

Để tạo một CSRPNG bạn làm điều gì đó như

RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); 
byte[] key = new byte[algorithm.KeySizeValue/8]; 
rng.GetBytes(key); 
byte[] iv = new byte[algorithm.BlockSizeValue/8]; 
rng.GetBytes(iv); 

Bạn cũng có thể sử dụng lớp Rfc2898DeriveBytes để lấy được chìa khóa và IV từ một mật khẩu và một muối, nhưng một lần nữa muối phải là một số ngẫu nhiên an toàn . Bạn cũng nên lưu ý khi tạo thuật toán đối xứng, khóa bảo mật và IV được tạo cho bạn.

Bằng cách này, bạn có thể chọn mã hóa chính xác cho văn bản của mình, có thể là UTF8, ASCII hoặc bất kỳ thứ gì. Các liên kết có đủ mẫu để cắt và dán ở đây là vô nghĩa.

+1

Các IV không cần phải bảo mật mã hóa, chỉ có các phím. – orip

+1

Không đúng, trong chế độ CBC, IV phải không thể đoán trước tại thời điểm mã hóa – blowdart

+1

Cảm ơn, đã không biết điều đó. – orip

4

Dưới đây là một giải pháp đơn giản mà tôi tìm thấy trên một diễn đàn VB.NET và chuyển đổi sang C#. Nó chắc chắn đã giúp tôi hiểu chủ đề tốt hơn.

// Shamelessly lifted from http://discuss.itacumens.com/index.php?topic=62872.0, 
// then converted to C# (http://www.developerfusion.com/tools/convert/vb-to-csharp/) and 
// changed where necessary. 
public class Encryptor 
{ 
    private static SymmetricAlgorithm _cryptoService = new TripleDESCryptoServiceProvider(); 
    // maybe use AesCryptoServiceProvider instead? 

    // vector and key have to match between encryption and decryption 
    public static string Encrypt(string text, byte[] key, byte[] vector) 
    { 
     return Transform(text, _cryptoService.CreateEncryptor(key, vector)); 
    } 

    // vector and key have to match between encryption and decryption 
    public static string Decrypt(string text, byte[] key, byte[] vector) 
    { 
     return Transform(text, _cryptoService.CreateDecryptor(key, vector)); 
    } 

    private static string Transform(string text, ICryptoTransform cryptoTransform) 
    { 
     MemoryStream stream = new MemoryStream(); 
     CryptoStream cryptoStream = new CryptoStream(stream, cryptoTransform, CryptoStreamMode.Write); 

     byte[] input = Encoding.Default.GetBytes(text); 

     cryptoStream.Write(input, 0, input.Length); 
     cryptoStream.FlushFinalBlock(); 

     return Encoding.Default.GetString(stream.ToArray()); 
    } 
} 
Các vấn đề liên quan