Puncte:0

Criptare AES-GCM în .NET Core

drapel de

Am creat un serviciu de criptare folosind AES-GCM pentru a cripta datele sensibile din baza de date. În primul rând, generez o cheie criptografică dintr-o parolă (probabil va fi stocată în Kubernetes Secrets) utilizând Rfc2898DeriveBytes. Apoi treceți această cheie instanței AesGcm.Puteți găsi implementarea mai jos.

CryptoService de clasă publică: ICryptoService, IDisposable
{
    private readonly AesGcm _aesGcm;

    CryptoService public (parolă șir, sare de șir)
    {
        cheie byte[] = Rfc2898DeriveBytes nou(parolă, Encoding.UTF8.GetBytes(sare), 200000, HashAlgorithmName.SHA512).GetBytes(32);
        
        //Obține cheia de criptare a datelor criptate generată aleatoriu în siguranță din Azure Vault.
        string encryptedEncryptionKey = AzureVault.GetDataEncryptionKey();
        byte[] encryptionKey = AzureVault.Decrypt(encryptedEncryptionKey, cheie);

        _aesGcm = AesGcm nou(encryptionKey);
    }

    șir public Encrypt(string plainText)
    {
        byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);

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

        // Combinați pentru o codificare mai ușoară
        int encryptedDataLength = 4 + nonceSize + 4 + tagSize + cipherSize;
        Span<byte> encryptedData = encryptedDataLength < 1024 ? stackalloc byte[encryptedDataLength] : octet nou[encryptedDataLength].AsSpan();


        BinaryPrimitives.WriteInt32LittleEndian(encryptedData.Slice(0, 4), nonceSize);
        BinaryPrimitives.WriteInt32LittleEndian(encryptedData.Slice(4 + nonceSize, 4), tagSize);
        var nonce = encryptedData.Slice(4, nonceSize);
        var tag = encryptedData.Slice(4 + nonceSize + 4, tagSize);
        var cipherBytes = encryptedData.Slice(4 + nonceSize + 4 + tagSize, cipherSize);

        RandomNumberGenerator.Fill(nonce);

        _aesGcm.Encrypt(nonce, plainBytes.AsSpan(), cipherBytes, tag);

        return Convert.ToBase64String(encryptedData);
    }   

    șir public Decriptare (șir cipherText)
    {
        Span<byte> encryptedData = Convert.FromBase64String(cipherText).AsSpan();

        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 tag = encryptedData.Slice(4 + nonceSize + 4, tagSize);
        var cipherBytes = encryptedData.Slice(4 + nonceSize + 4 + tagSize, cipherSize);

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

        return Encoding.UTF8.GetString(plainBytes);
    }    
}

Iată întrebarea mea. Mă întreb dacă această implementare este suficient de sigură, deoarece nu sunt un expert în securitate. Îmi lipsește un punct sau o gaură de securitate, cu excepția siguranței parolei? Orice sfat și sugestie ar fi foarte apreciat.

Mulțumiri.

Puncte:0
drapel cn

Nu este revizuire a Codului, dar există câteva lucruri care sunt specifice cripto-ului:

în funcție de modelul dvs. de amenințare, conversia datelor sursă într-o matrice de octeți în loc să citiți conținutul acestuia din memorie ar putea fi problematică, mai ales dacă este suficient de mare.

Principalul lucru pe care îl văd este că criptați datele direct cu parola, aș sugera să generați o cheie aleatoare securizată (DEK - cheie de criptare a datelor), apoi să utilizați parola pentru a genera o cheie pentru a cripta acea cheie (KEK - criptare cheie cheie). Acest lucru vă permite să schimbați parola fără a recripta toate datele și oferă o dimensiune combinată cheie+nonce de 352 de biți.

Un alt lucru este că, dacă doriți securitate pe 256 de biți pentru AES, derivarea cheii parolei ar trebui să utilizeze SHA512.

De asemenea, veți dori să utilizați orice metodă de programare disponibilă pentru a preveni paginarea materialului cheie pe disc. Și luați în considerare ce se întâmplă atunci când furnizați parola greșită pentru decriptare.

lagrance avatar
drapel de
Mulțumesc @Richie Frame. Acestea sunt sugestii grozave. Pentru a clarifica acești pași: Voi genera date aleatoare criptografic sigure (32 de octeți?) pentru DEK. Apoi criptați DEK cu cheia (KEK) generată de Rfc2898DeriveBytes și stocați DEK-ul criptat. Când vreau să criptez/decriptez datele, mai întâi decriptez DEK-ul criptat cu KEK. La sfârșitul zilei, ar trebui să stochez atât parola (pentru KEK) cât și DEK criptat.
Richie Frame avatar
drapel cn
Destul de aproape, ar trebui să stocați sarea pentru funcția de derivare a cheilor bazată pe parolă (există una în cod?) și să vă amintiți parola sau să o stocați în siguranță în afara contextului datelor. Blobul de date criptate ar fi pbkdf salt, DEK criptat, nonce, tag, text cifrat și orice metadate necriptate.
lagrance avatar
drapel de
Mulțumesc pentru toate sugestiile @Richie Frame. Am actualizat fragmentul de cod pentru a oferi intuiție celorlalți. Am decis să folosesc Key Vault pentru DEK-ul meu.
Richie Frame avatar
drapel cn
@lagrance este posibil să doriți, de asemenea, să specificați în mod explicit dimensiunile nonce și etichetei, în loc să preluați doar valoarea maximă din clasă, acest lucru nu face o diferență pentru etichetă, totuși ei ar putea decide într-o zi să accepte nonces pe 128 de biți, apoi toate codul se rupe
lagrance avatar
drapel de
Este puțin probabil să se întâmple așa ceva, dar aveți dreptate că ar trebui să le setez eu însumi pentru cod robust.

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.