it-swarm-vi.com

Bài học kinh nghiệm và những quan niệm sai lầm về mã hóa và mật mã

Mật mã học là một chủ đề rộng lớn đến nỗi ngay cả các lập trình viên có kinh nghiệm hầu như sẽ luôn mắc lỗi trong vài lần đầu tiên. Tuy nhiên, mã hóa là một chủ đề quan trọng như vậy, thường chúng ta không thể có những sai lầm này.

Mục đích của câu hỏi này là xác định và liệt kê những gì không để làm với một thuật toán hoặc API nhất định. Bằng cách này, chúng ta có thể học hỏi từ kinh nghiệm của người khác và ngăn chặn sự lây lan của các thực tiễn xấu.

Để giữ câu hỏi này mang tính xây dựng, xin vui lòng

  1. Bao gồm một ví dụ "sai"
  2. Giải thích những gì sai với ví dụ đó
  3. Cung cấp một thực hiện chính xác (nếu có).
  4. Để có khả năng tốt nhất, hãy cung cấp các tài liệu tham khảo về # 2 và # 3 ở trên.
68
goodguys_activate

Đừng cuộn tiền điện tử của riêng bạn.

Đừng phát minh ra thuật toán hoặc giao thức mã hóa của riêng bạn; đó là cực kỳ dễ bị lỗi. Như Bruce Schneier muốn nói,

"Bất cứ ai cũng có thể phát minh ra một thuật toán mã hóa mà chính họ không thể phá vỡ; việc phát minh ra một thuật toán mà không ai khác có thể phá vỡ sẽ khó hơn nhiều".

Các thuật toán tiền điện tử rất phức tạp và cần kiểm tra chuyên sâu để đảm bảo chúng an toàn; nếu bạn tự phát minh ra, bạn sẽ không có được điều đó, và rất dễ kết thúc với một thứ gì đó không an toàn mà không nhận ra điều đó.

Thay vào đó, sử dụng một thuật toán và giao thức mật mã tiêu chuẩn. Điều lạ lùng là người khác đã gặp phải vấn đề của bạn trước đây và đã thiết kế một thuật toán phù hợp cho mục đích đó.

Trường hợp tốt nhất của bạn là sử dụng một chương trình được kiểm duyệt tốt ở mức độ cao: để bảo mật thông tin liên lạc, hãy sử dụng TLS (hoặc SSL); đối với dữ liệu khi nghỉ ngơi, hãy sử dụng GPG (hoặc PGP). Nếu bạn không thể làm điều đó, hãy sử dụng thư viện tiền điện tử cấp cao, như cryptlib , GPGME, Keyczar hoặc NaCL , thay vì a cấp độ thấp, như OpenSSL, CryptoAPI, JCE, v.v .. Cảm ơn Nate Lawson về đề xuất này.

76
D.W.

Không sử dụng mã hóa mà không xác thực tin nhắn

Đó là một lỗi rất phổ biến để mã hóa dữ liệu mà không xác thực nó.

Ví dụ: Nhà phát triển muốn giữ bí mật tin nhắn, vì vậy hãy mã hóa tin nhắn bằng chế độ AES-CBC. Lỗi: Điều này không đủ để bảo mật khi có các cuộc tấn công hoạt động, tấn công lại, tấn công phản ứng, v.v. Có những cuộc tấn công được biết đến về mã hóa mà không cần xác thực tin nhắn và các cuộc tấn công có thể khá nghiêm trọng. Cách khắc phục là thêm xác thực tin nhắn.

Lỗi này đã dẫn đến các lỗ hổng nghiêm trọng trong các hệ thống được triển khai sử dụng mã hóa mà không cần xác thực, bao gồm ASP.NET , XML mã hóa , Amazon EC2 , Khuôn mặt JavaServer, Ruby trên Rails, OWASP ESAPI , IPSEC , WEP , lại ASP.NETSSH2 Bạn không muốn là người tiếp theo trong danh sách này.

Để tránh những vấn đề này, bạn cần sử dụng xác thực tin nhắn mỗi khi bạn áp dụng mã hóa. Bạn có hai lựa chọn để làm điều đó:

  • Có lẽ giải pháp đơn giản nhất là sử dụng sơ đồ mã hóa cung cấp mã hóa được xác thực , ví dụ: GCM, CWC, EAX, CCM, OCB. (Xem thêm: 1 .) Lược đồ mã hóa được xác thực xử lý việc này cho bạn, vì vậy bạn không phải suy nghĩ về nó.

  • Ngoài ra, bạn có thể áp dụng xác thực tin nhắn của riêng bạn, như sau. Đầu tiên, mã hóa tin nhắn bằng cách sử dụng sơ đồ mã hóa khóa đối xứng thích hợp (ví dụ: AES-CBC). Sau đó, lấy toàn bộ bản mã (bao gồm mọi IV, nonces hoặc các giá trị khác cần thiết để giải mã), áp dụng mã xác thực tin nhắn (ví dụ: AES-CMAC, SHA1-HMAC, SHA256-HMAC) và nối thêm phần tiêu hóa MAC kết quả vào bản mã trước khi truyền. Về phía nhận, kiểm tra xem thông báo MAC có hợp lệ trước khi giải mã không. Điều này được gọi là xây dựng mã hóa-sau đó xác thực. (Xem thêm: 1 , 2 .) Điều này cũng hoạt động tốt, nhưng đòi hỏi bạn phải chăm sóc nhiều hơn một chút.

47
D.W.

Cẩn thận khi nối nhiều chuỗi, trước khi băm.

Một lỗi tôi đôi khi thấy: Mọi người muốn băm chuỗi S và T. Họ nối chúng để lấy một chuỗi S | | T, sau đó băm nó để lấy H (S || T). Điều này là thiếu sót.

Vấn đề: Sự kết hợp để lại ranh giới giữa hai chuỗi mơ hồ. Ví dụ: builtin || securely = built || insecurely. Nói cách khác, hàm băm H (S | | T) không xác định duy nhất chuỗi S và T. Do đó, kẻ tấn công có thể thay đổi ranh giới giữa hai chuỗi, mà không thay đổi hàm băm. Chẳng hạn, nếu Alice muốn gửi hai chuỗi builtinsecurely, kẻ tấn công có thể thay đổi chúng thành hai chuỗi builtinsecurely mà không làm mất hiệu lực băm.

Các vấn đề tương tự được áp dụng khi áp dụng mã xác thực chữ ký số hoặc mã xác thực cho nối chuỗi.

Cách khắc phục: thay vì nối đơn giản, sử dụng một số mã hóa có thể giải mã rõ ràng. Chẳng hạn, thay vì tính H (S | | T), bạn có thể tính H (length (S) | | S | | T), trong đó độ dài (S) là giá trị 32 bit biểu thị độ dài của S tính bằng byte. Hoặc, một khả năng khác là sử dụng H (H (S) | | H (T)) hoặc thậm chí H (H (S) | | T).

Để biết ví dụ thực tế về lỗ hổng này, hãy xem lỗ hổng này trong Dịch vụ web của Amazon hoặc lỗ hổng này trong Flickr [pdf].

36
D.W.

Không sử dụng lại nonces hoặc IV

Nhiều chế độ hoạt động yêu cầu IV (Vector khởi tạo). Bạn không bao giờ được sử dụng lại cùng một giá trị cho IV hai lần; làm như vậy có thể hủy bỏ tất cả các bảo đảm an ninh và gây ra một sự vi phạm nghiêm trọng về an ninh.

  • Đối với các chế độ hoạt động của mật mã luồng, như chế độ CTR hoặc chế độ OFB, sử dụng lại IV là một thảm họa bảo mật. Nó có thể khiến các tin nhắn được mã hóa có thể phục hồi một cách tầm thường.

  • Đối với các chế độ hoạt động khác, như chế độ CBC, sử dụng lại IV cũng có thể tạo điều kiện cho các cuộc tấn công khôi phục bản rõ trong một số trường hợp.

Cho dù bạn sử dụng chế độ hoạt động nào, bạn không nên sử dụng lại IV. Nếu bạn đang tự hỏi làm thế nào để làm điều đó đúng, đặc tả NIST cung cấp tài liệu chi tiết về cách sử dụng các chế độ mã hóa khối hoạt động đúng cách.

Dự án Tarsnap cung cấp một ví dụ tốt về cạm bẫy này. Tarsnap mã hóa dữ liệu sao lưu bằng cách chia dữ liệu thành các đoạn và sau đó mã hóa từng đoạn bằng AES ở chế độ CTR. Trong các phiên bản 1.0.22 đến 1.0.27 của Tarsnap, IV tương tự đã vô tình được sử dụng lại, cho phép phục hồi văn bản gốc.

Làm sao chuyện này lại xảy ra? Để đơn giản hóa mã Tarsnap - và với hy vọng giảm nguy cơ lỗi - Colin Percival đã nhân cơ hội "tái cấu trúc" mã AES-CTR thành một tệp mới (lib/crypto/crypto_aesctr.c trong mã nguồn Tarsnap ) và sửa đổi các địa điểm hiện có nơi AES-CTR được sử dụng để tận dụng các thói quen này. Mã mới trông như thế này:

[.__.]/* Mã hóa dữ liệu. */[.__.] - aes_ctr (& encr_aes-> key, encr_aes-> nonce ++, buf, len, [.__.] - filebuf + CRYPTO_FILE_HLEN); [.__.] + if ((stream = [. ] + crypto_aesctr_init (& encr_aes-> key, encr_aes-> nonce)) == NULL) [.__.] + goto err0; [.__.] + crypto_aesctr_stream (stream, buf, .] + crypto_aesctr_free (luồng); [.__.]

Trong quá trình tái cấu trúc, encr_aes->nonce++ vô tình bị biến thành encr_aes->nonce và kết quả là cùng một giá trị nonce được sử dụng nhiều lần . Cụ thể, giá trị nonce CTR không được tăng lên sau mỗi đoạn được mã hóa. (Bộ đếm CTR được tăng chính xác sau mỗi 16 byte dữ liệu được xử lý, nhưng bộ đếm này được đặt lại về 0 cho mỗi đoạn mới.) Chi tiết đầy đủ được Colin Percival mô tả trong: http: //www.daemonology. net/blog/2011-01-18-tarsnap -itical-security-bug.html

29
Alex Holst

Đảm bảo bạn tạo hạt giống cho các trình tạo số ngẫu nhiên với đủ entropy.

Hãy chắc chắn rằng bạn sử dụng trình tạo số giả ngẫu nhiên cường độ mã hóa cho những việc như tạo khóa, chọn IV/nonces, v.v. Đừng sử dụng Rand(), random(), drand48() , Vân vân.

Hãy chắc chắn rằng bạn chọn trình tạo số giả ngẫu nhiên với đủ entropy. Đừng gieo hạt giống với thời gian trong ngày; đó là điều có thể đoán được.

Ví dụ: srand(time(NULL)) rất tệ. Một cách hay để chọn hạt giống PRNG của bạn là lấy 128 bit hoặc số ngẫu nhiên thực, ví dụ: từ /dev/urandom, CryptGenRandom hoặc tương tự. Trong Java, sử dụng SecureRandom, không phải ngẫu nhiên. Trong .NET, sử dụng System.Security.Cryptography.RandomNumberGenerator, không phải System.Random. Trong Python, sử dụng Random.SystemRandom, không phải ngẫu nhiên. Cảm ơn Nate Lawson cho một số ví dụ.

Ví dụ trong thế giới thực: xem lỗ hổng này trong các phiên bản đầu của trình duyệt Netscape , cho phép kẻ tấn công phá vỡ SSL.

29
D.W.

Không sử dụng mật mã khối với ECB để mã hóa đối xứng

(Áp dụng cho AES, 3DES, ...)

Đây là một bài đăng và rất giống bài viết Microsoft KB liên quan đến cách chế độ ECB dẫn đến mã không được mã hóa.

Cũng xem bài tương tự này từ Rook

Tin nhắn văn bản đơn giản:

alt text

Thông điệp tương tự được mã hóa với chế độ ECB (không quan trọng bạn sử dụng mật mã nào): alt text

Thông báo CHÍNH XÁC tương tự sử dụng chế độ CBC (một lần nữa, không quan trọng bạn sử dụng mật mã nào): alt text

Sai cách

public static string Encrypt(string toEncrypt, string key, bool useHashing)
{

byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);

if (useHashing)
    keyArray = new MD5CryptoServiceProvider().ComputeHash(keyArray);

var tdes = new TripleDESCryptoServiceProvider() 
    { Key = keyArray, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 };

ICryptoTransform cTransform = tdes.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(
    toEncryptArray, 0, toEncryptArray.Length);

return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}

Lỗi nằm ở dòng sau

{Key = keyArray, Chế độ = CodesMode.ECB , Padding = PaddingMode.PKCS7};


Đúng cách

Những người tốt ở Microsoft đã gửi cho tôi đoạn mã sau để sửa bài viết KB được liên kết ở trên. Điều này được tham chiếu trong trường hợp # 111021973179005

Mã mẫu này đang sử dụng AES để mã hóa dữ liệu và khóa cho mã hóa AES là mã băm được tạo bởi SHA256. AES là thuật toán Tiêu chuẩn mã hóa nâng cao (AES). Thuật toán AES dựa trên hoán vị và thay thế. Hoán vị là sự sắp xếp lại dữ liệu và thay thế một đơn vị dữ liệu bằng một đơn vị khác. AES thực hiện hoán vị và thay thế bằng một số kỹ thuật khác nhau. Để biết thêm chi tiết về AES, vui lòng tham khảo bài viết Giữ dữ liệu của bạn an toàn với tiêu chuẩn mã hóa nâng cao mới trên Tạp chí MSDN tại http://msdn.Microsoft.com/en-us/magazine/cc164055.aspx .

SHA là thuật toán Hash an toàn. SHA-2 (SHA-224, SHA-256, SHA-384, SHA-512) hiện được khuyến nghị. Để biết thêm thông tin chi tiết về Giá trị Hash trong .NET Framework, vui lòng tham khảo http://msdn.Microsoft.com/en-us/l Library/92f9ye3s.aspx#hash_values .

Giá trị mặc định của chế độ hoạt động của thuật toán đối xứng cho AesCryptoServiceProvider là CBC. CBC là chế độ Chuỗi khối mã hóa. Nó giới thiệu thông tin phản hồi. Trước khi mỗi khối văn bản đơn giản được mã hóa, nó được kết hợp với văn bản mã hóa của khối trước đó bằng thao tác OR độc quyền theo bit. Điều này đảm bảo rằng ngay cả khi văn bản đơn giản chứa nhiều khối giống hệt nhau, mỗi khối sẽ mã hóa thành một khối văn bản mã hóa khác nhau. Vectơ khởi tạo được kết hợp với khối văn bản thuần đầu tiên bằng thao tác OR độc quyền theo bit trước khi khối được mã hóa. Nếu một bit của khối văn bản mật mã được đọc sai, khối văn bản thuần tương ứng cũng sẽ được đọc sai. Ngoài ra, một bit trong khối tiếp theo, ở vị trí tương tự như bit mangled ban đầu, sẽ được đọc sai. Để biết thêm thông tin chi tiết về CipherMode, vui lòng tham khảo http://msdn.Microsoft.com/en-us/l Library/system.security.cryptography.codesmode.aspx .

Đây là mã mẫu.

// This function is used for encrypting the data with key and iv.
byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
{
    // Create an AESCryptoProvider.
    using (var aesCryptoProvider = new AesCryptoServiceProvider())
    {
        // Initialize the AESCryptoProvider with key and iv.
        aesCryptoProvider.KeySize = key.Length * 8;
        aesCryptoProvider.IV = iv;
        aesCryptoProvider.Key = key;

        // Create encryptor from the AESCryptoProvider.
        using (ICryptoTransform encryptor = aesCryptoProvider.CreateEncryptor())
        {
            // Create memory stream to store the encrypted data.
            using (MemoryStream stream = new MemoryStream())
            {
                // Create a CryptoStream to encrypt the data.
                using (CryptoStream cryptoStream = new CryptoStream(stream, encryptor, CryptoStreamMode.Write))
                    // Encrypt the data.
                    cryptoStream.Write(data, 0, data.Length);

                // return the encrypted data.
                return stream.ToArray();
            }
        }
    }
}

// This function is used for decrypting the data with key and iv.
byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
{
    // Create an AESCryptoServiceProvider.
    using (var aesCryptoProvider = new AesCryptoServiceProvider())
    {
        // Initialize the AESCryptoServiceProvier with key and iv.
        aesCryptoProvider.KeySize = key.Length * 8;
        aesCryptoProvider.IV = iv;
        aesCryptoProvider.Key = key;

        // Create decryptor from the AESCryptoServiceProvider.
        using (ICryptoTransform decryptor = aesCryptoProvider.CreateDecryptor())
        {
            // Create a memory stream including the encrypted data.
            using (MemoryStream stream = new MemoryStream(data))
            {
                // Create a CryptoStream to decrypt the encrypted data.
                using (CryptoStream cryptoStream = new CryptoStream(stream, decryptor, CryptoStreamMode.Read))
                {
                    // Create a byte buffer array.
                    byte[] readData = new byte[1024];
                    int readDataCount = 0;

                    // Create a memory stream to store the decrypted data.
                    using (MemoryStream resultStream = new MemoryStream())
                    {
                        do
                        {
                            // Decrypt the data and write the data into readData buffer array.
                           readDataCount = cryptoStream.Read(readData, 0, readData.Length);
                            // Write the decrypted data to resultStream.
                            resultStream.Write(readData, 0, readDataCount);
                        }
                        // Check whether there is any more encrypted data in stream.
                        while (readDataCount > 0);
                        // Return the decrypted data.
                        return resultStream.ToArray();
                    }
                }
            }
        }
    }
}



// This function is used for generating a valid key binary with UTF8 encoding and SHA256 hash algorithm.
byte[] GetKey(string key)
{
    // Create SHA256 hash algorithm class.
    using (SHA256Managed sha256 = new SHA256Managed())

    // Decode the string key to binary and compute the hash binary of the key.
    return sha256.ComputeHash(Encoding.UTF8.GetBytes(key));
}

Để biết thêm chi tiết về các lớp trong mã mẫu, vui lòng tham khảo các liên kết sau:

· Lớp AesCryptoServiceProvider

· Lớp quản lý SHA256

· Lớp tiền điện tử

Ngoài ra, có một số bài viết có thể giúp hiểu rõ hơn về mật mã trong .NET Framework, vui lòng tham khảo các liên kết dưới đây:

· Dịch vụ mã hóa

· . Mô hình mã hóa khung NET

· Hướng dẫn đơn giản về Mật mã học

· Mã hóa không bí mật

20
goodguys_activate

Không sử dụng cùng một khóa cho cả mã hóa và xác thực. Đừng sử dụng cùng một khóa cho cả mã hóa và ký.

Một khóa không nên được sử dụng lại cho nhiều mục đích; điều đó có thể mở ra các cuộc tấn công tinh tế khác nhau.

Chẳng hạn, nếu bạn có cặp khóa riêng/chung RSA, bạn không nên sử dụng cả hai để mã hóa (mã hóa bằng khóa chung, giải mã bằng khóa riêng) và để ký (ký bằng khóa riêng, xác minh bằng khóa chung ): chọn một mục đích duy nhất và sử dụng cho mục đích đó. Nếu bạn cần cả hai khả năng, hãy tạo hai bàn phím, một để ký và một để mã hóa/giải mã.

Tương tự, với mật mã đối xứng, bạn nên sử dụng một khóa để mã hóa và một khóa độc lập riêng để xác thực tin nhắn. Không sử dụng lại cùng một khóa cho cả hai mục đích.

20
D.W.

Nguyên tắc của Kerckhoffs: Một hệ thống mật mã phải được bảo mật ngay cả khi mọi thứ về hệ thống, ngoại trừ khóa, là kiến ​​thức công khai

Một ví dụ sai: LANMAN băm

Các băm LANMAN sẽ khó có thể nhận ra nếu không ai biết thuật toán, tuy nhiên một khi thuật toán đã được biết thì bây giờ rất đơn giản để bẻ khóa.

Thuật toán như sau ( từ wikipedia ):

  1. Mật khẩu người dùng ASCII được chuyển đổi thành chữ hoa.
  2. Mật khẩu này được đệm vào 14 byte
  3. Mật khẩu có độ dài cố định của thành phố được chia thành hai nửa bảy byte.
  4. Các giá trị này được sử dụng để tạo hai khóa DES, một khóa từ mỗi nửa byte 7
  5. Mỗi trong số hai khóa được sử dụng để mã hóa hằng số ASCII chuỗi KGS! @ # $%, Kết quả là tạo ra hai giá trị bản mã 8 byte.
  6. Hai giá trị bản mã này được nối với nhau để tạo thành giá trị 16 byte, là giá trị băm LM

Vì bây giờ bạn đã biết bản mã của các sự kiện này, giờ đây bạn có thể dễ dàng chia bản mã thành hai bản mã mà bạn biết là chữ hoa dẫn đến một bộ ký tự giới hạn có thể có mật khẩu.

Một ví dụ đúng: Mã hóa AES

  • Thuật toán đã biết
  • Cân với công nghệ. Tăng kích thước khóa khi cần thêm oomph mật mã
17
Chris Dale

Cố gắng tránh sử dụng mật khẩu làm khóa mã hóa.

Một điểm yếu phổ biến trong nhiều hệ thống là sử dụng mật khẩu hoặc cụm mật khẩu hoặc hàm băm của mật khẩu hoặc cụm mật khẩu, làm khóa mã hóa/giải mã. Vấn đề là điều này có xu hướng rất dễ bị tấn công keyearch ngoại tuyến. Hầu hết người dùng chọn mật khẩu không có đủ entropy để chống lại các cuộc tấn công như vậy.

Cách khắc phục tốt nhất là sử dụng khóa mã hóa/giải mã thực sự ngẫu nhiên, không phải là một khóa được tạo một cách xác định từ mật khẩu/cụm mật khẩu.

Tuy nhiên, nếu bạn phải sử dụng một mật khẩu dựa trên mật khẩu/cụm mật khẩu, hãy sử dụng một lược đồ thích hợp để làm chậm quá trình tìm kiếm khóa. Tôi khuyên bạn nên PBKDF2 , sử dụng băm lặp (dọc theo dòng H(H(H(....H(password)...)))) để làm chậm quá trình tìm kiếm từ điển. Sắp xếp sử dụng đủ nhiều lần lặp để khiến quá trình này mất, giả sử, 100ms trên máy của người dùng để tạo khóa.

13
D.W.

Trong giao thức mã hóa: Làm cho mọi tin nhắn được xác thực có thể nhận ra: không có hai tin nhắn nào giống nha

Một khái quát/biến thể của:

  • Cẩn thận khi nối nhiều chuỗi, trước khi băm.
  • Đừng sử dụng lại khóa.
  • Đừng tái sử dụng nonces.

Trong quá trình chạy giao thức mật mã, nhiều tin nhắn không thể bị làm giả mà không có bí mật (khóa hoặc không mở) có thể được trao đổi. Những tin nhắn này có thể được xác nhận bởi người nhận vì anh ta biết một số khóa công khai (chữ ký) hoặc vì chỉ anh ta và người gửi biết một số khóa đối xứng hoặc không phải là khóa. Điều này đảm bảo rằng những tin nhắn này chưa được sửa đổi.

Nhưng điều này không không đảm bảo rằng các tin nhắn này đã được phát ra trong cùng một lần chạy giao thức: một kẻ thù có thể đã bắt được những tin nhắn này trước đó hoặc trong khi chạy đồng thời của giao thức. Một kẻ thù có thể bắt đầu nhiều lần chạy giao thức mật mã để nắm bắt các thông điệp hợp lệ và sử dụng lại chúng không được sửa đổi.

Bằng cách khéo léo phát lại các tin nhắn, có thể tấn công một giao thức mà không ảnh hưởng đến bất kỳ khóa chính nào, mà không tấn công bất kỳ RNG, bất kỳ cypher nào, v.v.

Bằng cách làm cho mọi thông điệp được xác thực của giao thức rõ ràng là khác biệt đối với người nhận, cơ hội để phát lại các tin nhắn chưa sửa đổi sẽ giảm (không bị loại bỏ).

13
curiousguy

Không sử dụng độ dài khóa không an toàn.

Đảm bảo bạn sử dụng các thuật toán với một khóa đủ dài.

Đối với mật mã khóa đối xứng, tôi khuyên dùng ít nhất một khóa 80 bit và nếu có thể, khóa 128 bit là một ý tưởng hay. Đừng sử dụng tiền điện tử 40 bit; nó không an toàn và dễ dàng bị phá vỡ bởi những người nghiệp dư, chỉ đơn giản bằng cách cố gắng hết sức cố gắng mọi chìa khóa có thể. Không sử dụng DES 56 bit; Nó không phải là tầm thường để phá vỡ, nhưng nó nằm trong tầm tay của những kẻ tấn công chuyên dụng để phá vỡ DES. Thuật toán 128 bit, như AES, không chậm hơn đáng kể so với tiền điện tử 40 bit, vì vậy bạn không có lý do gì để sử dụng tiền điện tử.

Đối với mật mã khóa công khai, các khuyến nghị về độ dài khóa phụ thuộc vào thuật toán và mức độ bảo mật cần thiết. Ngoài ra, việc tăng kích thước khóa sẽ gây hại cho hiệu suất, do đó, quá mức cần thiết là không kinh tế; do đó, điều này đòi hỏi một chút suy nghĩ hơn so với việc lựa chọn kích thước khóa đối xứng. Đối với RSA, El Gamal hoặc Diffie-Hellman, tôi khuyên bạn nên khóa tối thiểu 1024 bit, ở mức tối thiểu tuyệt đối; tuy nhiên, các khóa 1024 bit nằm trên Edge của những gì có thể bị bẻ khóa trong thời gian tới và thường không được khuyến nghị sử dụng hiện đại, vì vậy, nếu có thể, tôi sẽ khuyên dùng các khóa 1536 hoặc thậm chí 2048 bit. Đối với mật mã đường cong elip, các khóa 160 bit xuất hiện đầy đủ và các khóa 224 bit là tốt hơn. Bạn cũng có thể tham khảo các hướng dẫn đã thiết lập tương đương thô giữa các kích thước khóa đối xứng và khóa công khai .

8
D.W.

Không sử dụng cùng một khóa theo cả hai hướng.

Trong giao tiếp mạng, một lỗi phổ biến là sử dụng cùng một khóa để liên lạc theo hướng A-> B như đối với hướng B-> A. Đây là một ý tưởng tồi, bởi vì nó thường cho phép phát lại các cuộc tấn công phát lại thứ A gửi đến B, trở lại A.

Cách tiếp cận an toàn nhất là đàm phán hai khóa độc lập, mỗi khóa cho mỗi hướng. Ngoài ra, bạn có thể thương lượng một khóa K duy nhất, sau đó sử dụng K1 = AES (K, 00..0) cho một hướng và K2 = AES (K, 11..1) cho hướng khác.

8
D.W.

Một miếng đệm một lần không phải là một miếng đệm một lần nếu khóa được kéo dài bằng thuật toán

Mã định danh "bộ đệm một lần" (còn được gọi là mật mã Vernam) thường bị áp dụng sai cho các giải pháp mã hóa khác nhau trong nỗ lực yêu cầu bảo mật không thể phá vỡ. Nhưng theo định nghĩa, mật mã Vernam là an toàn nếu và chỉ khi cả ba điều kiện này được đáp ứng:

  • Các tài liệu quan trọng là thực sự không thể đoán trước; VÀ
  • Tài liệu chính có cùng chiều dài với bản rõ; VÀ
  • Các vật liệu quan trọng không bao giờ được sử dụng lại.

Bất kỳ vi phạm các điều kiện đó có nghĩa là nó không còn là mật mã pad một lần nữa.

Lỗi phổ biến được thực hiện là một khóa ngắn được kéo dài bằng một thuật toán. Hành động này vi phạm quy tắc không thể đoán trước (không bao giờ để ý quy tắc độ dài khóa.) Một khi điều này được thực hiện, phần đệm một lần được chuyển đổi về mặt toán học thành thuật toán kéo dài khóa. Kết hợp khóa ngắn với các byte ngẫu nhiên chỉ làm thay đổi không gian tìm kiếm cần thiết để bắt buộc thuật toán kéo dài khóa. Tương tự, sử dụng byte "được tạo ngẫu nhiên" sẽ biến thuật toán tạo số ngẫu nhiên thành thuật toán bảo mật.

Đây là một ví dụ đơn giản. Tôi có một thông báo rằng tôi sẽ mã hóa bằng cách sử dụng "bộ đệm một lần" sử dụng chức năng bảo mật bằng mật mã làm trình tạo khóa. Tôi đã chọn một khóa bí mật, sau đó thêm một số ngẫu nhiên vào nó để đảm bảo nó sẽ không được sử dụng lại. Vì tôi không sử dụng lại khóa, không có cách nào để tấn công bản mã bằng cách trừ đi một tin nhắn từ một tin nhắn khác.

          plaintext : 1234567890123456789012345678901234567890
       key material : 757578fbf23ffa4d748e0800dd7c424a46feb0cc
OTP function (xor)  : ----------
         ciphertext : 67412E83622DCE1B0C1E1A348B04D25872A8C85C

Tài liệu chính được tạo an toàn bằng SHA-1 để băm mật khẩu bí mật của tôi (cộng với ngẫu nhiên) để kéo dài nó. Nhưng bất kỳ kẻ tấn công nào biết thuật toán kéo dài * được sử dụng là SHA-1 đều có thể tấn công nó bằng cách thử nhiều đầu vào khác nhau vào SHA-1 và XORing đầu ra với bản mã. Đoán khóa "OTP" bây giờ không khó hơn việc đoán các đầu vào kết hợp với thuật toán mã hóa. Thuộc tính này giữ đúng bất kể thuật toán mã hóa cơ sở nào được chọn, biện pháp phức tạp nào được giữ hoặc cách thức triển khai hoặc gieo hạt.

Bạn có thể có một thuật toán kéo dài khóa rất tốt. Bạn cũng có thể có một trình tạo số ngẫu nhiên rất an toàn. Tuy nhiên, thuật toán của bạn theo định nghĩa không phải là bộ đệm một lần và do đó không có thuộc tính không thể phá vỡ của bộ đệm một lần.

* Áp dụng nguyên tắc của Kerckhoff có nghĩa là bạn phải cho rằng kẻ tấn công luôn có thể xác định các thuật toán được sử dụng.

3
John Deters

Sử dụng chế độ đúng

Tương tự, không dựa vào cài đặt mặc định của thư viện để bảo mật. Cụ thể, nhiều thư viện triển khai AES thực hiện thuật toán được mô tả trong FIPS 197, được gọi là chế độ ECB (Sách mã điện tử), về cơ bản là ánh xạ đơn giản của:

AES(plaintext [32]byte, key [32]byte) -> ciphertext [32]byte

là rất không an toàn. Lý do rất đơn giản, trong khi số lượng các phím có thể có trong không gian khóa là khá lớn, liên kết yếu ở đây là lượng entropy trong tin nhắn. Như mọi khi, xkcd.com mô tả tốt hơn tôi http://xkcd.com/257/

Điều rất quan trọng là sử dụng một cái gì đó như CBC (Chuỗi khối mã hóa) về cơ bản làm cho bản mã hóa [i] thành ánh xạ:

ciphertext[i] = SomeFunction(ciphertext[i-1], message[i], key)

Chỉ cần chỉ ra một vài thư viện ngôn ngữ dễ mắc lỗi này: http://golang.org/pkg/crypto/aes/ cung cấp một triển khai AES, nếu được sử dụng một cách ngây thơ, sẽ dẫn đến chế độ ECB.

Thư viện pycrypto mặc định ở chế độ ECB khi tạo đối tượng AES mới.

OpenSSL, làm điều này đúng. Mỗi cuộc gọi AES là rõ ràng về chế độ hoạt động. IMO thực sự an toàn nhất là chỉ cố gắng không làm tiền điện tử cấp thấp như thế này. Nếu bạn bị ép buộc, hãy tiến hành như thể bạn đang đi trên kính vỡ (một cách cẩn thận) và cố gắng đảm bảo người dùng của bạn có lý khi đặt niềm tin của họ vào bạn để bảo vệ dữ liệu của họ.

3
Shane Hansen

Không sử dụng lại cùng một khóa trên nhiều thiết bị.

Bạn chia sẻ càng nhiều khóa mật mã, bạn càng có khả năng giữ bí mật. Một số hệ thống được triển khai đã sử dụng lại khóa đối xứng giống nhau trên mọi thiết bị trên hệ thống. Vấn đề với điều này là sớm hay muộn, ai đó sẽ trích xuất khóa từ một thiết bị duy nhất và sau đó họ sẽ có thể tấn công tất cả các thiết bị khác. Vì vậy, đừng làm điều đó.

Xem thêm "Mã hóa đối xứng Đừng # 6: Không chia sẻ một khóa trên nhiều thiết bị" trong bài viết trên blog này . Tín dụng cho Matthew Green.

3
D.W.

Không sử dụng mã hóa OTP hoặc luồng trong mã hóa ổ đĩa

Ví dụ 1

Giả sử hai tệp được lưu bằng mật mã luồng/OTP. Nếu tệp được lưu lại sau một chỉnh sửa nhỏ, kẻ tấn công có thể thấy rằng chỉ một số bit nhất định đã được thay đổi và suy luận thông tin về tài liệu. (Hãy tưởng tượng thay đổi lời chào "Bob thân mến" thành "Alice thân mến").

Ví dụ 2

Không có tính toàn vẹn trong đầu ra: kẻ tấn công có thể sửa đổi bản mã và sửa đổi nội dung của dữ liệu bằng cách đơn giản là XOR dữ liệu.

Bỏ đi: Sửa đổi cho bản mã không bị phát hiện và có tác động có thể dự đoán được trên bản rõ.

Giải pháp

Sử dụng mật mã khối cho các tình huống này bao gồm kiểm tra tính toàn vẹn của tin nhắn

1
goodguys_activate

Không tin tưởng Tiêu chuẩn.

Nhiều tiêu chuẩn tồn tại trong mật mã, và đôi khi bạn phải sử dụng chúng. Nhưng đừng cho rằng những người viết các tiêu chuẩn hiểu đầy đủ về mật mã họ cần. Ví dụ, EAX đã được làm lại trong một tiêu chuẩn mạng. EAX có bằng chứng về bảo mật. Các phiên bản làm lại đã không.

MD5 là một tiêu chuẩn. Bây giờ nó đã bị hỏng. Chip và PIN đã bị hỏng nhiều lần, nhờ có nhiều tính năng nguy hiểm. GPG vẫn hỗ trợ các khóa DSA quá ngắn để thoải mái. SSL có các tùy chọn không nên sử dụng và yêu cầu quan tâm để tránh chúng.

Có thể làm gì về điều này? Cẩn thận, hiểu những rủi ro đã biết và theo kịp nghiên cứu về những rủi ro mới.

1
Watson Ladd

Chỉ sử dụng MAC không dễ bị tấn công mở rộng thư

MAC là mã băm đảm bảo tính toàn vẹn của thông điệp (không sửa đổi, v.v.) của một văn bản thuần nhất định. Nhiều triển khai và các tiêu chuẩn được công bố không bảo vệ MAC khỏi kẻ tấn công nối thêm dữ liệu vào MAC.

Giải pháp cho việc này là để triển khai MAC sử dụng khóa thứ hai (khác) và mã hóa lại đầu ra cuối cùng.

ECBC và NMAC là những ví dụ về mật mã ngăn chặn chính xác cuộc tấn công mở rộng thư.

Giải pháp:

  • Sử dụng Encrypted CBC (ECBC) thay vì raw CBC
  • Sử dụng NMAC thay vì cascade
0
goodguys_activate

Không bao giờ sử dụng Bảng mã một lần (OTP) hoặc khóa mật mã luồng nhiều lần

Một OTP được áp dụng hai lần có nghĩa là dữ liệu được mã hóa với "bí mật hoàn hảo" sẽ được giải mã và rõ ràng. Điều này xảy ra vì dữ liệu được XOR hai lần.

Ví dụ

Giả sử một OTP/hoặc luồng có cùng khóa đang được sử dụng lại.

Kẻ tấn công thu thập rất nhiều dữ liệu được gửi từ máy khách đến máy chủ và XOR tập hợp hai gói với nhau cho đến khi hai gói giải mã lẫn nhau (hoặc tập hợp con ở đó).

Mã hóa ASCII có đủ dự phòng, điều đó có nghĩa là đã cung cấp đủ bản mã, các thông điệp ban đầu có thể được giải mã (cùng với khóa OTP bí mật).

ví dụ trong thế giới thực

  • Dự án Verona (1941-46) cho một ví dụ về OTP được người Nga sử dụng và sau đó được cơ quan tình báo Hoa Kỳ giải mã

  • PPTPv1 của Microsoft cả máy khách và máy chủ đều mã hóa dữ liệu bằng cùng một khóa.

  • WEP sử dụng lại cùng một khóa sau khi 2 ^ 24 gói được gửi hoặc nếu thẻ a NIC được đặt lại. Vấn đề đầu tiên là do IV dài 24 bit, dẫn đến sau 16 triệu khung hình Đã truyền một bộ đệm hai thời gian. Vấn đề thứ hai xảy ra trong việc triển khai phần cứng trong đó sau một chu kỳ nguồn, IV đặt lại về 0, dẫn đến một bộ đệm hai thời gian. Vấn đề này rất dễ thấy vì IV được gửi rõ ràng.

Khuyến nghị

  • Một khóa mới sẽ được tạo cho mỗi phiên (ví dụ: TLS).

  • Máy khách nên sử dụng một OTP (hoặc mật mã luồng w/PRG) với máy chủ và máy chủ nên sử dụng khóa khác khi mã hóa dữ liệu cho máy khách

  • Thay vì tạo nhiều khóa, có thể mở rộng một khóa thành một luồng dài bằng PRG (giả sử bạn tin tưởng PRG) và sử dụng từng phân đoạn của bản mở rộng đó làm khóa.

  • Biết rằng không phải tất cả các PRG đều được thực hiện để hoạt động ở chế độ tăng và có thể cần nhập liệu ngẫu nhiên. (RC4 có vấn đề này ở chế độ tăng)

0
goodguys_activate

Không sử dụng RC4

RC4 được thiết kế vào năm 1987 để sử dụng làm mật mã dòng. Nó được sử dụng trong HTTPS và WEP.

Có những điểm yếu

  1. Có sự thiên vị trong đầu ra ban đầu: Pr [2 byte = 0] = 2/256
  2. Xác suất của mười sáu bit bằng 0 là 1/256 ^ 2 + 1/256 ^ 3. Điều này xảy ra sau khi một số Gigs dữ liệu đã được mã hóa.
  3. Dễ bị tấn công bằng các phím liên quan, trong đó chỉ IV thay đổi nhưng khóa vẫn giữ nguyên.

Bỏ đi Nếu bạn phải sử dụng RC4, hãy bỏ qua 256 byte đầu tiên vì chúng bị sai lệch. Nếu bạn sử dụng RC4 cho Gigs dữ liệu, thì độ lệch trong RC4 sẽ cho phép tấn công tất cả dữ liệu được mã hóa trước đó.

0
goodguys_activate

Sử dụng bộ xử lý luồng hiện đại hoạt động phù hợp trong Phần cứng hoặc Phần mềm

Không phải tất cả các mật mã luồng được thiết kế để được thực hiện trong phần cứng hoặc phần mềm. Thanh ghi dịch chuyển phản hồi tuyến tính (LFSR) là một ví dụ về mật mã phần cứng được triển khai rộng rãi, dễ bị phá vỡ.

LFSR được sử dụng trong:

  • Mã hóa DVD (còn được gọi là CSS) 2 LFSR
  • Mã hóa GSM (A5/1.2) 3 LSFR
  • Bluetooth (E0): 4 LFSR

Phần cứng cho ở trên được triển khai rộng rãi và do đó khó cập nhật, hoặc mang đến các tiêu chuẩn hiện đại. Tất cả những điều trên đều bị hỏng nặng và không đáng tin cậy để liên lạc an toàn.

Tấn công:

Vì khóa được chia thành hai phần trong quá trình mã hóa (17 bit và 25 bit) và các bit đó được sử dụng để mã hóa cùng một văn bản mã hóa, nên có thể sử dụng kiến ​​thức về định dạng MPEG và sử dụng khóa 17 bit để ngoại suy khóa 25 bit Là.

Điều này hầu như không mới, nhưng FOSS rất dễ tìm thấy chứng minh vấn đề này.

Giải pháp:

dự án eStream (năm 2008) 5 mật mã luồng đủ điều kiện nên được sử dụng. Một sự khác biệt đáng chú ý là thay vì sử dụng Khóa với IV, mật mã sử dụng Khóa, nonce và bộ đếm. Salsa20 vận hành theo cách này và được thiết kế để sử dụng cả phần cứng và phần mềm một cách dễ dàng. Cụ thể, nó được bao gồm trong tập lệnh x86 SSE2.

Ngoài ra

Các mật mã hiện đại không chỉ an toàn hơn mà còn nhanh hơn:

PRG          Speed (MB/sec)
RC4              126         (obsolete)
Salsa20/12       643         (modern)
Sosemaunk        727         (modern)
0
goodguys_activate