Score:0

การเข้ารหัส AES-GCM ใน .NET Core

ธง de

ฉันสร้างบริการ crypto โดยใช้ AES-GCM เพื่อเข้ารหัสข้อมูลที่ละเอียดอ่อนในฐานข้อมูล ประการแรก ฉันกำลังสร้างคีย์เข้ารหัสจากรหัสผ่าน (อาจจะเก็บไว้ใน Kubernetes Secrets) โดยใช้ Rfc2898DeriveBytes จากนั้นส่งคีย์นี้ไปยังอินสแตนซ์ AesGcmคุณสามารถค้นหาการใช้งานด้านล่าง

CryptoService ระดับสาธารณะ: ICryptoService, IDisposable
{
    ส่วนตัวอ่านอย่างเดียว AesGcm _aesGcm;

    CryptoService สาธารณะ (รหัสผ่านสตริง, เกลือสตริง)
    {
        คีย์ไบต์ [] = ใหม่ Rfc2898DeriveBytes (รหัสผ่าน, Encoding.UTF8.GetBytes (เกลือ), 200000, HashAlgorithmName.SHA512).GetBytes (32);
        
        // รับคีย์การเข้ารหัสข้อมูลที่เข้ารหัสแบบสุ่มที่สร้างขึ้นอย่างปลอดภัยจาก Azure Vault
        สตริงเข้ารหัสEncryptionKey = AzureVault.GetDataEncryptionKey();
        ไบต์ [] encryptionKey = AzureVault.Decrypt (เข้ารหัส EncryptionKey, คีย์);

        _aesGcm = ใหม่ AesGcm (เข้ารหัสคีย์);
    }

    การเข้ารหัสสตริงสาธารณะ (สตริงข้อความธรรมดา)
    {
        ไบต์ [] plainBytes = Encoding.UTF8.GetBytes (ข้อความธรรมดา);

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

        // รวมเพื่อการเข้ารหัสที่ง่ายขึ้น
        int encryptedDataLength = 4 + nonceSize + 4 + tagSize + cipherSize;
        ช่วง <ไบต์> encryptedData = encryptedDataLength < 1024 ? ไบต์ stackalloc [encryptedDataLength] : ไบต์ใหม่ [encryptedDataLength].AsSpan ();


        BinaryPrimitives.WriteInt32LittleEndian (เข้ารหัส Data.Slice (0, 4), nonceSize);
        BinaryPrimitives.WriteInt32LittleEndian(encryptedData.Slice(4 + nonceSize, 4), tagSize);
        var nonce = encryptedData.Slice (4, nonceSize);
        แท็ก var = encryptedData.Slice (4 + nonceSize + 4, tagSize);
        var cipherBytes = encryptedData.Slice (4 + nonceSize + 4 + tagSize, cipherSize);

        RandomNumberGenerator.Fill(ไม่มี);

        _aesGcm.Encrypt(ไม่มี, plainBytes.AsSpan(), cipherBytes, แท็ก);

        กลับ Convert.ToBase64String (encryptedData);
    }   

    ถอดรหัสสตริงสาธารณะ (string cipherText)
    {
        Span<byte> encryptedData = Convert.FromBase64String(cipherText).Aspan();

        int nonceSize = BinaryPrimitives.ReadInt32LittleEndian (encryptedData.Slice(0, 4));
        int tagSize = BinaryPrimitives.ReadInt32LittleEndian (encryptedData.Slice (4 + nonceSize, 4));
        int cipherSize = encryptedData.Length - 4 - nonceSize - 4 - tagSize;

        var nonce = encryptedData.Slice (4, nonceSize);
        แท็ก var = encryptedData.Slice (4 + nonceSize + 4, tagSize);
        var cipherBytes = encryptedData.Slice (4 + nonceSize + 4 + tagSize, cipherSize);

        ช่วง<byte> plainBytes = cipherSize < 1024 ? ไบต์ stackalloc [cipherSize] : ไบต์ใหม่ [cipherSize];
        _aesGcm.Decrypt (ไม่มี, cipherBytes, แท็ก, ไบต์ธรรมดา);

        กลับ Encoding.UTF8.GetString(ธรรมดาไบต์);
    }    
}

นี่คือคำถามของฉัน ฉันสงสัยว่าการใช้งานนี้มีความปลอดภัยเพียงพอหรือไม่ เนื่องจากฉันไม่ใช่ผู้เชี่ยวชาญด้านความปลอดภัย ฉันพลาดจุดหรือช่องโหว่ด้านความปลอดภัยยกเว้นการรักษาความปลอดภัยด้วยรหัสผ่านหรือไม่ คำแนะนำและข้อเสนอแนะใด ๆ ที่จะได้รับการชื่นชมอย่างมาก

ขอบคุณ.

Score:0
ธง cn

มันไม่ใช่ ตรวจสอบรหัสแต่มีบางสิ่งที่เฉพาะเจาะจงสำหรับ crypto:

ขึ้นอยู่กับรูปแบบภัยคุกคามของคุณ การแปลงข้อมูลต้นทางเป็นอาร์เรย์แบบไบต์แทนที่จะอ่านเนื้อหาจากหน่วยความจำอาจเป็นปัญหาได้ โดยเฉพาะอย่างยิ่งหากข้อมูลนั้นมีขนาดใหญ่พอ

สิ่งสำคัญที่ฉันเห็นคือคุณกำลังเข้ารหัสข้อมูลโดยตรงด้วยรหัสผ่าน ฉันขอแนะนำให้สร้างคีย์สุ่มที่ปลอดภัยแทน (DEK - คีย์เข้ารหัสข้อมูล) จากนั้นใช้รหัสผ่านเพื่อสร้างคีย์เพื่อเข้ารหัสคีย์นั้น (KEK - การเข้ารหัสคีย์ กุญแจ). ซึ่งช่วยให้คุณเปลี่ยนรหัสผ่านได้โดยไม่ต้องเข้ารหัสข้อมูลทั้งหมดใหม่ และกำหนดขนาดคอมโบของคีย์+นอนซ์เป็น 352 บิต

อีกสิ่งหนึ่งคือถ้าคุณต้องการความปลอดภัย 256 บิตสำหรับ AES การได้มาของคีย์รหัสผ่านของคุณควรใช้ SHA512

คุณจะต้องใช้วิธีการเขียนโปรแกรมใดๆ ที่มีให้คุณเพื่อป้องกันไม่ให้เนื้อหาหลักถูกเพจไปยังดิสก์ และพิจารณาว่าจะเกิดอะไรขึ้นเมื่อคุณระบุรหัสผ่านที่ไม่ถูกต้องสำหรับการถอดรหัส

lagrance avatar
de flag
ขอบคุณ @ริชชี่ เฟรม นี่เป็นข้อเสนอแนะที่ดี เพื่อชี้แจงขั้นตอนเหล่านี้: ฉันจะสร้างข้อมูลสุ่มที่ปลอดภัยด้วยการเข้ารหัส (32 ไบต์?) สำหรับ DEK จากนั้นเข้ารหัส DEK ด้วยคีย์ (KEK) ที่สร้างโดย Rfc2898DeriveBytes และจัดเก็บ DEK ที่เข้ารหัส เมื่อฉันต้องการเข้ารหัส/ถอดรหัสข้อมูล ก่อนอื่นฉันจะถอดรหัส DEK ที่เข้ารหัสด้วย KEK ในตอนท้ายของวันฉันควรเก็บทั้งรหัสผ่าน (สำหรับ KEK) และ DEK ที่เข้ารหัส
Richie Frame avatar
cn flag
ค่อนข้างใกล้เคียง คุณควรจัดเก็บเกลือสำหรับฟังก์ชันการสืบทอดคีย์ที่ใช้รหัสผ่าน (มีอยู่ในรหัสหรือไม่) และจดจำรหัสผ่านหรือจัดเก็บไว้อย่างปลอดภัยนอกบริบทของข้อมูล blob ข้อมูลที่เข้ารหัสจะเป็นเกลือ pbkdf, DEK ที่เข้ารหัส, nonce, แท็ก, ciphertext และข้อมูลเมตาที่ไม่ได้เข้ารหัส
lagrance avatar
de flag
ขอบคุณทุกคำแนะนำ @ริชชี่ เฟรม ฉันอัปเดตข้อมูลโค้ดเพื่อให้คนอื่นเข้าใจโดยสัญชาตญาณ ฉันตัดสินใจใช้ Key Vault สำหรับ DEK ของฉัน
Richie Frame avatar
cn flag
@lagrance คุณอาจต้องการระบุ nonce และขนาดแท็กอย่างชัดเจน แทนที่จะเรียกค่าสูงสุดจากคลาส สิ่งนี้ไม่ได้สร้างความแตกต่างให้กับแท็ก อย่างไรก็ตาม สักวันหนึ่งพวกเขาอาจตัดสินใจสนับสนุน nonces 128 บิต จากนั้นทั้งหมด รหัสแตก
lagrance avatar
de flag
มันไม่น่าจะเกิดขึ้น แต่คุณคิดถูกแล้วที่ฉันควรตั้งมันเองสำหรับโค้ดที่มีประสิทธิภาพ

โพสต์คำตอบ

คนส่วนใหญ่ไม่เข้าใจว่าการถามคำถามมากมายจะปลดล็อกการเรียนรู้และปรับปรุงความสัมพันธ์ระหว่างบุคคล ตัวอย่างเช่น ในการศึกษาของ Alison แม้ว่าผู้คนจะจำได้อย่างแม่นยำว่ามีคำถามกี่ข้อที่ถูกถามในการสนทนา แต่พวกเขาไม่เข้าใจความเชื่อมโยงระหว่างคำถามและความชอบ จากการศึกษาทั้ง 4 เรื่องที่ผู้เข้าร่วมมีส่วนร่วมในการสนทนาด้วยตนเองหรืออ่านบันทึกการสนทนาของผู้อื่น ผู้คนมักไม่ตระหนักว่าการถามคำถามจะมีอิทธิพลหรือมีอิทธิพลต่อระดับมิตรภาพระหว่างผู้สนทนา