2014-09-17 15 views
6

Tôi hoàn toàn mới về mật mã, nhưng học tập. Tôi đã ghép nối nhiều đề xuất khác nhau từ nghiên cứu trực tuyến của mình và đã tạo lớp riêng để xử lý băm, muối, kéo dài khóa và so sánh/chuyển đổi dữ liệu được liên kết.Làm cách nào để sử dụng SHA-512 với Rfc2898DeriveBytes trong mã muối và mã băm của tôi?

Sau khi nghiên cứu thư viện .NET tích hợp để mã hóa, tôi phát hiện ra rằng những gì tôi có vẫn chỉ là SHA-1. Nhưng tôi đi đến kết luận rằng nó không phải là xấu vì tôi đang sử dụng nhiều lần lặp của quá trình băm. Đúng không?

Nhưng nếu tôi muốn bắt đầu với SHA-512 mạnh hơn, làm cách nào tôi có thể triển khai mã trong mã dưới đây? Cảm ơn trước.

using System; 
using System.Runtime.InteropServices; 
using System.Security; 
using System.Security.Cryptography; 

public class CryptoSaltAndHash 
{ 
    private string strHash; 
    private string strSalt; 
    public const int SaltSizeInBytes = 128; 
    public const int HashSizeInBytes = 1024; 
    public const int Iterations = 3000; 

    public string Hash { get { return strHash; } } 
    public string Salt { get { return strSalt; } } 

    public CryptoSaltAndHash(SecureString ThisPassword) 
    { 
     byte[] bytesSalt = new byte[SaltSizeInBytes]; 
     using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider()) 
     { 
      crypto.GetBytes(bytesSalt); 
     } 
     strSalt = Convert.ToBase64String(bytesSalt); 
     strHash = ComputeHash(strSalt, ThisPassword); 
    } 

    public static string ComputeHash(string ThisSalt, SecureString ThisPassword) 
    { 
     byte[] bytesSalt = Convert.FromBase64String(ThisSalt); 
     Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(
      convertSecureStringToString(ThisPassword), bytesSalt, Iterations); 
     using (pbkdf2) 
     { 
      return Convert.ToBase64String(pbkdf2.GetBytes(HashSizeInBytes)); 
     } 
    } 

    public static bool Verify(string ThisSalt, string ThisHash, SecureString ThisPassword) 
    { 
     if (slowEquals(getBytes(ThisHash), getBytes(ComputeHash(ThisSalt, ThisPassword)))) 
     { 
      return true; 
     } 
     return false; 
    } 

    private static string convertSecureStringToString(SecureString MySecureString) 
    { 
     IntPtr ptr = IntPtr.Zero; 
     try 
     { 
      ptr = Marshal.SecureStringToGlobalAllocUnicode(MySecureString); 
      return Marshal.PtrToStringUni(ptr); 
     } 
     finally 
     { 
      Marshal.ZeroFreeGlobalAllocUnicode(ptr); 
     } 
    } 

    private static bool slowEquals(byte[] A, byte[] B) 
    { 
     int intDiff = A.Length^B.Length; 
     for (int i = 0; i < A.Length && i < B.Length; i++) 
     { 
      intDiff |= A[i]^B[i]; 
     } 
     return intDiff == 0; 
    } 

    private static byte[] getBytes(string MyString) 
    { 
     byte[] b = new byte[MyString.Length * sizeof(char)]; 
     System.Buffer.BlockCopy(MyString.ToCharArray(), 0, b, 0, b.Length); 
     return b; 
    } 
} 

Lưu ý: Tôi đã tham chiếu nhiều thực tiễn từ https://crackstation.net/hashing-security.htm. Phương thức so sánh slowEquals là bình thường hóa thời gian thực thi bằng cách ngăn chặn phân nhánh. Việc sử dụng SecureString là phải có một dạng mã hóa mật khẩu được chuyển giữa lớp này và các lớp và trang khác trong ứng dụng web của tôi. Mặc dù trang web này sẽ qua HTTPS, nhưng bạn nên sử dụng thêm dặm để đảm bảo mọi thứ an toàn nhất có thể trong khi vẫn đang trong vòng lý do.

Trong mã của mình, tôi đã đặt chuỗi khóa thành 128 byte (mặc dù nó phát triển lớn hơn đôi khi, đó là tốt), kích thước băm thành 1KB và số lần lặp lại là 3.000. Nó lớn hơn một chút so với muối 64 byte điển hình, băm 512 byte và 1.000 hoặc 2.000 lần lặp lại, nhưng sau đó lại có tốc độ đăng nhập và hiệu suất ứng dụng là ưu tiên cực kỳ thấp.

Suy nghĩ?

+0

Câu hỏi tương tự về đánh giá mã: [Mật khẩu băm an toàn] (http://codereview.stackexchange.com/questions/32856/secure-password-hashing) – CodesInChaos

Trả lời

5

Trả lời câu hỏi: Tải xuống mẫu mã miễn phí từ "SecurityDriven.NET" sách. Tìm lớp học PBKDF2 có nhà máy HMAC. HMACSHA512 nhà máy có sẵn, trong số những người khác.

Vì bạn mới sử dụng mật mã, tôi cũng khuyên bạn nên đọc sách (ví dụ: để hiểu đầy đủ về các điểm mà CodeInChaos thực hiện).

+0

Cảm ơn. Trong khi các ví dụ đó sử dụng .NET 4.5, tôi đang sử dụng .NET 4.0. Tuy nhiên, chúng sẽ làm việc cho cả hai với những thay đổi tối thiểu. Các ví dụ đó tham chiếu lớp mã hóa tôi cần: http://msdn.microsoft.com/en-us/library/system.security.cryptography.sha512%28v=vs.100%29.aspx –

8
  1. 3000 lần lặp lại khá thấp. Ngay cả 10000 cũng thấp. Nhưng bạn cần phải tăng cường độ an toàn của các lần lặp lại bổ sung chống lại rủi ro mà kẻ tấn công DoSes máy chủ của bạn bằng cách cố đăng nhập thường xuyên, điều này kích hoạt hàm băm tốn kém cho mỗi lần thử.
  2. Không có điểm nào trong muối lớn hơn 128 bit/16 byte. Một muối nên là duy nhất, không có gì hơn.
  3. Kích thước băm lớn hơn kích thước gốc (20 byte cho SHA-1) giảm hiệu suất cho hậu vệ nhưng không làm giảm hiệu suất của kẻ tấn công. Vì điều này có nghĩa là bạn có thể đủ khả năng lặp lại ít hơn, nó thực sự làm suy yếu an ninh.

    Ví dụ với cùng chi phí như băm 1024 byte của bạn với 3000 lần lặp, bạn có thể đủ khả năng một băm 20 byte với 156.000 lần lặp lại, đắt hơn 52 lần để bẻ khóa.

  4. Để sử dụng SHA-2, bạn sẽ cần triển khai PBKDF2 hoàn toàn khác, phần được bao gồm .net được mã hóa cứng để sử dụng SHA-1.

    Nếu bạn muốn sử dụng thư viện của bên thứ ba, tôi muốn sử dụng thư viện bcrypt vì thư viện này mạnh hơn nhiều so với kẻ tấn công dựa trên GPU.

  5. API của bạn rất khó sử dụng, vì bạn đẩy quản lý muối vào người gọi thay vì xử lý nó trong các hàm Create/Verify.

  6. Thật ngớ ngẩn khi sử dụng SecureString và sau đó chuyển đổi thành String. Điều này chống lại toàn bộ các điểm sử dụng một SecureString ở nơi đầu tiên.

    Cá nhân tôi sẽ không bận tâm với SecureString trong một ứng dụng điển hình.Nó chỉ đáng giá nếu bạn kết hợp nó với một đánh giá bảo mật toàn diện ngăn xếp để kiểm tra xem mật khẩu không bao giờ được lưu trữ trong một String và luôn bị xóa khỏi bộ nhớ có thể thay đổi khi nó không còn cần thiết nữa.

  7. Tôi sẽ không lưu trữ mật khẩu/muối trong các biến mẫu. Chỉ cần giữ chúng cục bộ với các chức năng liên quan. Tôi chỉ lưu trữ cấu hình trong các biến cá thể (chẳng hạn như số lần lặp).

  8. Trong khi SHA-1 bị suy yếu mã hóa, các cuộc tấn công tạo ra xung đột. Đối với các xung đột băm mật khẩu không liên quan, những gì bạn quan tâm là các cuộc tấn công trước hình ảnh đầu tiên. SHA-1 vẫn khá mạnh về vấn đề đó. Ưu điểm chính của SHA-512 không phải là nó mạnh hơn về mặt mã hóa (mặc dù vậy), đó là số học 64 bit chi phí cho kẻ tấn công nhiều hơn hậu vệ, vì người bảo vệ có thể sẽ sử dụng CPU Intel 64 bit cung cấp nhanh Số học 64 bit.

+0

Lời khuyên tuyệt vời, cảm ơn bạn rất nhiều! Tôi sẽ nhớ chỉ sử dụng SecureString nếu tôi không bao giờ chuyển đổi nó thành một chuỗi trong mã. Đối với API của tôi là khó xử để sử dụng, nó có vẻ làm việc tốt. Khởi tạo lớp để tạo ra một muối và có, hoặc gọi nó là tĩnh để xác minh một băm đã tạo trước đó. Không có quản lý nào được đẩy vào người gọi ở đó. Tuy nhiên câu hỏi của tôi xoay quanh điểm số 4 của bạn. Bạn có thể xây dựng thêm về đề xuất đó và cách nó được triển khai trong môi trường .NET (ví dụ: chọn thư viện SHA-2 mà bạn muốn giới thiệu). Cảm ơn một lần nữa! –

+0

Tôi chưa bao giờ bận tâm đến việc triển khai C# của PBKDF2-HMAC-SHA-2, vì vậy tôi không thực sự biết. Tôi đoán rằng bouncycastle hỗ trợ nó. Cá nhân tôi muốn đánh giá bcrypt.net và các triển khai bcrypt khác. – CodesInChaos

1

Nếu có ai gặp câu hỏi này bằng cách tìm kiếm, giờ đây Microsoft cung cấp gói 01GNuGet, cho phép sử dụng PBKDF2 với hàm băm SHA-256 và SHA-512. Tài liệu có sẵn tại docs.microsoft.com.

Các vấn đề liên quan