Điểm:0

Mã hóa AES-GCM trong .NET Core

lá cờ de

Tôi đã tạo một dịch vụ tiền điện tử bằng AES-GCM để mã hóa dữ liệu nhạy cảm trong cơ sở dữ liệu. Đầu tiên, tôi đang tạo khóa mật mã từ mật khẩu (có thể sẽ được lưu trữ trong Kubernetes Secrets) bằng cách sử dụng Rfc2898DeriveBytes. Sau đó, chuyển khóa này sang phiên bản AesGcm.Bạn có thể tìm thấy việc thực hiện xuống dưới đây.

lớp công khai CryptoService : ICryptoService, IDisposable
{
    AesGcm _aesGcm chỉ đọc riêng tư;

    dịch vụ tiền điện tử công khai (mật khẩu chuỗi, chuỗi muối)
    {
        byte[] key = new Rfc2898DeriveBytes(mật khẩu, Encoding.UTF8.GetBytes(salt), 200000, HashAlgorithmName.SHA512).GetBytes(32);
        
        //Nhận khóa mã hóa dữ liệu đã mã hóa được tạo ngẫu nhiên một cách an toàn từ Azure Vault.
        chuỗi mã hóaEncryptionKey = AzureVault.GetDataEncryptionKey();
        byte[] EncryptionKey = AzureVault.Decrypt(encryptedEncryptionKey, key);

        _aesGcm = new AesGcm(encryptionKey);
    }

    Mã hóa chuỗi công khai (chuỗi văn bản thuần túy)
    {
        byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);

        int nonceSize = AesGcm.NonceByteSizes.MaxSize;
        int tagSize = AesGcm.TagByteSizes.MaxSize;
        int cipherSize = plainBytes.Length;

        // Kết hợp để mã hóa dễ dàng hơn
        int mã hóaDataLength = 4 + nonceSize + 4 + tagSize + cipherSize;
        Khoảng cách<byte> dữ liệu mã hóa = mã hóaDataLength <1024? stackalloc byte[encryptedDataLength] : byte mới[encryptedDataLength].AsSpan();


        BinaryPrimitives.WriteInt32LittleEndian(encryptedData.Slice(0, 4), nonceSize);
        BinaryPrimitives.WriteInt32LittleEndian(encryptedData.Slice(4 + nonceSize, 4), tagSize);
        var nonce =cryptedData.Slice(4, nonceSize);
        thẻ var = mã hóaData.Slice(4 + nonceSize + 4, tagSize);
        var cipherBytes =cryptedData.Slice(4 + nonceSize + 4 + tagSize, cipherSize);

        RandomNumberGenerator.Fill(nonce);

        _aesGcm.Encrypt(nonce, plainBytes.AsSpan(), cipherBytes, thẻ);

        trả về Convert.ToBase64String(encryptedData);
    }   

    giải mã chuỗi công khai (chuỗi cipherText)
    {
        Span<byte>cryptedData = Convert.FromBase64String(cipherText).AsSpan();

        int nonceSize = BinaryPrimitives.ReadInt32LittleEndian(encryptedData.Slice(0, 4));
        int tagSize = BinaryPrimitives.ReadInt32LittleEndian(encryptedData.Slice(4 + nonceSize, 4));
        int cipherSize = mã hóaData.Length - 4 - nonceSize - 4 - tagSize;

        var nonce =cryptedData.Slice(4, nonceSize);
        thẻ var = mã hóaData.Slice(4 + nonceSize + 4, tagSize);
        var cipherBytes =cryptedData.Slice(4 + nonceSize + 4 + tagSize, cipherSize);

        Span<byte> plainBytes = cipherSize <1024? stackalloc byte[cipherSize] : byte mới[cipherSize];
        _aesGcm.Decrypt(nonce, cipherBytes, tag, plainBytes);

        trả về Encoding.UTF8.GetString(plainBytes);
    }    
}

Đây là câu hỏi của tôi. Tôi tự hỏi liệu việc triển khai này có đủ an toàn hay không vì tôi không phải là chuyên gia về bảo mật. Tôi có thiếu một điểm hoặc lỗ hổng bảo mật ngoại trừ bảo mật mật khẩu không? Mọi lời khuyên và đề xuất sẽ được đánh giá rất cao.

Cảm ơn.

Điểm:0
lá cờ cn

Đây không phải là đánh giá mã, nhưng có một số điều dành riêng cho tiền điện tử:

tùy thuộc vào mô hình mối đe dọa của bạn, việc chuyển đổi dữ liệu nguồn thành một mảng byte thay vì đọc nội dung của nó từ bộ nhớ có thể gặp sự cố, đặc biệt nếu nó đủ lớn.

Điều chính tôi thấy là bạn đang mã hóa dữ liệu trực tiếp bằng mật khẩu, thay vào đó tôi khuyên bạn nên tạo một khóa ngẫu nhiên an toàn (DEK - khóa mã hóa dữ liệu), sau đó sử dụng mật khẩu để tạo khóa để mã hóa khóa đó (KEK - mã hóa khóa Chìa khóa). Điều đó cho phép bạn thay đổi mật khẩu mà không cần mã hóa lại tất cả dữ liệu và cung cấp kích thước tổ hợp khóa + nonce là 352 bit.

Một điều nữa là nếu bạn muốn bảo mật 256-bit cho AES, thì dẫn xuất khóa mật khẩu của bạn phải sử dụng SHA512.

Bạn cũng sẽ muốn sử dụng bất kỳ phương pháp lập trình nào có sẵn để ngăn không cho tài liệu chính được phân trang vào đĩa. Và xem xét điều gì sẽ xảy ra khi bạn cung cấp sai mật khẩu để giải mã.

lagrance avatar
lá cờ de
Cảm ơn @Richie Frame. Đây là những gợi ý tuyệt vời. Để làm rõ các bước sau: Tôi sẽ tạo dữ liệu ngẫu nhiên được bảo mật bằng mật mã (32 byte?) cho DEK. Sau đó, mã hóa DEK bằng khóa (KEK) do Rfc2898DeriveBytes tạo ra và lưu trữ DEK đã mã hóa. Khi tôi muốn mã hóa/giải mã dữ liệu, trước tiên tôi giải mã DEK đã mã hóa bằng KEK. Vào cuối ngày, tôi nên lưu trữ cả mật khẩu (cho KEK) và DEK được mã hóa.
Richie Frame avatar
lá cờ cn
Khá gần, bạn nên lưu trữ muối cho hàm dẫn xuất khóa dựa trên mật khẩu (có mã nào trong mã không?) và ghi nhớ mật khẩu hoặc lưu trữ an toàn bên ngoài ngữ cảnh của dữ liệu. Khối dữ liệu được mã hóa sẽ là muối pbkdf, DEK được mã hóa, nonce, thẻ, bản mã và bất kỳ siêu dữ liệu không được mã hóa nào.
lagrance avatar
lá cờ de
Cảm ơn tất cả các đề xuất @Richie Frame. Tôi đã cập nhật đoạn mã để cung cấp trực giác cho những người khác. Tôi đã quyết định sử dụng Key Vault cho DEK của mình.
Richie Frame avatar
lá cờ cn
@lagrance bạn cũng có thể muốn chỉ định rõ ràng kích thước nonce và thẻ, thay vì chỉ truy xuất giá trị tối đa từ lớp, điều này không tạo ra sự khác biệt cho thẻ, tuy nhiên một ngày nào đó họ có thể quyết định hỗ trợ nonce 128 bit, sau đó tất cả mã phá vỡ
lagrance avatar
lá cờ de
Điều đó không chắc sẽ xảy ra, nhưng bạn nói đúng rằng tôi nên tự đặt chúng để có mã mạnh mẽ.

Đăng câu trả lời

Hầu hết mọi người không hiểu rằng việc đặt nhiều câu hỏi sẽ mở ra cơ hội học hỏi và cải thiện mối quan hệ giữa các cá nhân. Ví dụ, trong các nghiên cứu của Alison, mặc dù mọi người có thể nhớ chính xác có bao nhiêu câu hỏi đã được đặt ra trong các cuộc trò chuyện của họ, nhưng họ không trực giác nhận ra mối liên hệ giữa câu hỏi và sự yêu thích. Qua bốn nghiên cứu, trong đó những người tham gia tự tham gia vào các cuộc trò chuyện hoặc đọc bản ghi lại các cuộc trò chuyện của người khác, mọi người có xu hướng không nhận ra rằng việc đặt câu hỏi sẽ ảnh hưởng—hoặc đã ảnh hưởng—mức độ thân thiện giữa những người đối thoại.