Pentru a cripta și a decripta informații importante, va trebui să efectuați pașii următori (acestea vor fi explicate în detaliu în secțiunile următoare):
Selectați și creați un algoritm.
Generați și salvați cheia privată.
Criptați sau decriptați informațiile prin intermediul CryptoStream.
Închideți fluxul sursă și țintă corespunzător.
După ce a creat și testat clasele de criptare a serviciului, trebuie creată o bază de date pentru a stoca informații sensibile, iar codul este scris pentru a cripta și decripta această informație sensibilă în baza de date.
Managementul cheie
Înainte de a trece la detalii despre lucrul cu clasele de criptare, trebuie să vă gândiți la un punct suplimentar: unde să stocați cheia? Cheia utilizată pentru criptare și decriptare este un secret, deci ar trebui să fie stocată într-un loc sigur. Adesea, dezvoltatorii consideră că este mai bine să stocați cheia în codul sursă. Cu toate acestea, aceasta este una dintre cele mai grave greseli care pot fi făcute doar în cererea dumneavoastră. Să presupunem că există codul din codul bibliotecii de clasă care va fi compilat într-o bibliotecă binară DLL:
Aceste tipuri de chei pot fi ușor deschise folosind unelte de dezasamblare. Pur și simplu rulați instrumentul ILDASM și analizați clasa. Desigur, puteți găsi cu siguranță această cheie, după cum se arată în figura de mai jos:
Dacă credeți că această problemă este tipică numai pentru codul gestionat, încercați să faceți ceva similar cu o aplicație neangajată în C ++. Creați o clasă și includeți valoarea secretă ca o constantă a aplicației în ea. Deoarece valorile constante sunt stocate într-o anumită secțiune a fișierelor executabile interne, urmați acești pași:
Instalați fișierul SDK Microsoft.
Deschideți un prompt de comandă și tastați următoarea comandă:
Deci, cu siguranță trebuie să ai grijă de o protecție cheie. S-ar putea să doriți să criptați această cheie, dar atunci aveți nevoie de o altă cheie de criptare.
Windows acceptă un mecanism încorporat pentru stocarea și protejarea cheilor secrete. Acest mecanism utilizează cheia mașinii generată în timpul instalării sistemului și este proiectată special pentru criptarea datelor. Accesul la cheia mașinii este doar un sistem de operare local (centrul de securitate locală). Firește, tasta mașinii este unică pentru fiecare instalare.
Pentru a proteja datele cu această cheie, Windows furnizează un API pentru protecția datelor (DPAPI). Când utilizați acest API, nu aveți acces direct la această cheie, ci pur și simplu instruiți sistemul să cripteze sau să decripteze ceva utilizând cheia mașinii. Astfel, permite rezolvarea sarcinii de gestionare a cheilor: aplicația poate cripta cheia utilizată în ea utilizând DPAPI. În acest scop, .NET Framework suportă clasa System.Security.Cryptography.ProtectedData. care se aplică după cum urmează:
Pentru a utiliza clasa ProtectedData pentru a proteja informațiile sensibile, trebuie să adăugați o referință la ansamblul System.Security.dll și să importați spațiul de nume System.Security.Cryptography. Contextele posibile sunt LocalMachine și CurrentUser. Prima opțiune utilizează tasta mașină, iar în al doilea rând, cheia generată pentru utilizatorul curent înregistrat.
Dacă utilizatorul este administratorul mașinii și are anumite cunoștințe, poate decripta datele scriind un program care apelează funcția de mai sus. Cu toate acestea, în mod cert erectează o barieră și face dificil accesul la cheie. Și dacă utilizatorul nu este administrator și nu are dreptul să lucreze cu DPAPI, nu va putea decripta datele criptate cu cheia mașinii.
Nu utilizați DPAPI pentru criptarea informațiilor din baza de date. Deși DPAPI este ușor de folosit cu .NET Framework, există o problemă cu această metodă: dacă utilizați setarea DataProtectionScope.LocalMachine, datele criptate vor fi legate de mașină. Astfel, dacă mașina nu reușește și datele trebuie recuperate pe altă mașină, în acest caz este necesar să aveți o copie de rezervă a cheii într-un alt loc sigur. Pentru a utiliza DPAPI într-un scenariu de fermă web, va trebui să executați aplicația în numele contului de utilizator de domeniu și să aplicați cheia creată pentru profilul utilizatorului (DataProtectionScope.CurrentUser). Pentru a evita utilizarea unui utilizator de domeniu din rețeaua internă a companiei, este recomandat să creați un domeniu separat pentru ferma web.
Folosind algoritmi simetrici
După cum sa menționat deja, algoritmii de criptare simetric utilizează o singură cheie pentru criptarea și decriptarea datelor. În secțiunea următoare, veți afla detaliile creării unei clase de servicii care criptează și decriptează datele importante. Această clasă poate fi reutilizată în mai multe aplicații web. Clasa de servicii creată va avea structura prezentată mai jos și poate fi utilizată pentru a cripta și decripta datele de șir. (Rețineți că, pe baza lui ProtectKey, factorul de decizie va fi scris mai târziu, va cripta cheia utilizând DPAPI sau nu. Valoarea adevărată înseamnă că cheia trebuie protejată cu DPAPI.)
Deoarece această clasă este oficială numai cu membri statici, ea poate fi făcută statică, astfel încât nimeni să nu-și poată crea instanțele. Clasa oferă posibilitatea de a specifica numele algoritmului (DES, TripleDES, RijnDael sau RC2) în proprietatea AlgorithmName.
De asemenea, suportă operațiile de generare a unei noi chei, citirea cheii din fișier direct în proprietatea cheie a instanței algoritmului și criptarea și decriptarea datelor. Pentru a folosi această clasă, trebuie să specificați numele algoritmului în mod corespunzător și apoi să generați cheia dacă nu există deja. Apoi, trebuie doar să apelați metodele EncryptData și DescryptData, care numesc intern metoda ReadKey pentru a inițializa algoritmul. Proprietatea ProtectKey permite utilizatorului clasei să specifice dacă să protejeze cheia utilizând DPAPI.
Cheile de criptare pot fi generate prin clase de algoritmi. Metoda GenerateKey arată astfel:
Metoda GenerateKey () a clasei SymmetricAlgorithm generează o nouă cheie utilizând un algoritm care generează numere criptografice aleatorii strict prin metoda GenerateKey () a algoritmului creat și inițiază proprietatea Key cu această cheie nouă. Dacă codul de apel are flagul ProtectKey al clasei de serviciu setat la true, atunci implementarea criptează cheia utilizând DPAPI.
Metoda ReadKey citește cheia din fișierul generat de metoda GenerateKey, după cum se arată mai jos:
Dacă cheia a fost protejată anterior, metoda ReadKey () utilizează DPAPI pentru a dezabona cheia după ce a citit-o din fișier. Metoda necesită transferul unei instanțe existente a unui algoritm simetric. Inițializează direct proprietatea cheie a algoritmului, astfel încât această cheie să fie aplicată automat în toate operațiile ulterioare. În final, ambele funcții - EncryptData () și DecryptData () - utilizează funcția ReadKey ().
Ambele metode necesită parametrul keyFile cu calea spre fișierul în care este stocată cheia. Ambele le numesc secvențial metoda ReadKey pentru a inițializa instanța algoritmului cu această cheie. În timp ce metoda EncryptData ia un șir și returnează o matrice de octeți cu reprezentarea sa criptată, DecryptData acceptă matricea byte criptată și returnează șirul ca text plaintext:
Să începem cu metoda EncryptData ():
În primul rând, metoda convertește un șir într-o matrice octet, deoarece toate funcțiile de criptare a algoritmului necesită matrice de octeți ca parametri de intrare. Cea mai ușoară modalitate de a face acest lucru este de a folosi clasa Encoding din spațiul de nume System.Text. Apoi, metoda creează un algoritm în funcție de proprietatea clasei AlgorithmName. Această valoare poate fi una dintre următoarele: RC2, Rijndael, DES sau TripleDES.
Metoda din fabrica SymmetricAlgorithm.Create () creează instanța corespunzătoare, în timp ce clasele suplimentare de criptografie pot fi înregistrate în
După aceasta, metoda creează un flux în memorie, care în acest caz va servi ca țintă pentru operația de criptare. Înainte ca clasa să înceapă o operațiune de criptare prin CryptoStream, generează un vector de inițializare (IV) și o scrie în fluxul țintă din prima poziție. Vectorul de inițializare adaugă date aleatorii în fluxul criptat.
Imaginați-vă următoarea situație: dacă o aplicație trimite aceleași informații de mai multe ori între client și server, criptarea simplă va duce întotdeauna la aceeași reprezentare criptată a acestor informații. Acest lucru va simplifica atacul prin "forță brută". Pentru a adăuga un fel de informație aleatorie, un algoritm simetric acceptă vectorii de inițializare. Aceste vectori de inițializare nu sunt adăugate numai la fluxurile de date criptate, ci sunt folosite și ca intrări pentru criptarea primului bloc de date.
Când utilizați CryptoStream pentru criptarea informațiilor, nu uitați să apelați FlushFinalBlock () pentru a vă asigura că ultimul bloc de date criptate este scris corect în destinație.
Vectorii de inițializare trebuie adăugați în setul criptat de octeți, deoarece aceste informații sunt necesare pentru următoarea decriptare:
Structura funcției de decriptare este construită diferit. Creează un algoritm și un flux țintă pentru informațiile decriptate. Înainte de a decripta datele, este necesar să citim vectorul de inițializare din fluxul criptat de intrare, deoarece este folosit de algoritm pentru ultima transformare. Apoi se folosește CryptoStream, așa cum a fost făcut înainte, dar cu diferența că de data aceasta este creată transformarea decriptare. Și, în final, obținem reprezentarea octetului decodat a șirului creat de Encoding.UTF8.GetBytes (). Pentru a efectua o operație inversă, trebuie să apelați metoda GetString () a clasei de codare UTF-8 pentru a obține o reprezentare textuală a șirului.
Utilizând clasa SymmetricEncryptionUtility
Acum puteți crea o pagină pentru testarea clasei. Aceasta va fi o pagină simplă care va genera o cheie și va introduce date în câmpul de text. Datele criptate pot fi afișate cu ușurință folosind Convert.ToBase64String (). Pentru a decripta, trebuie doar să decodați partea codificată de Base64 în matricea octeților. Folosind metoda Convert.FromBase64String (), trebuie să trimiteți octeți criptați înapoi și să le trimiteți la metoda DecryptData:
Pagina de mai sus utilizează algoritmul DES, deoarece este specificat în AlgorithmName. În cadrul evenimentului Click () al butonului GenerateKeyCommand, se apelează metoda GenerateKey (). În funcție de setarea casetei de validare de pe pagină, cheia este criptată prin DPAPI sau nu. După ce datele sunt criptate de clasa de utilități din evenimentul Click () al butonului EncryptCommand, octeții criptați sunt convertiți la șirul Base64 și apoi scriși în câmpul text EcryptedDataText. Astfel, pentru a decripta din nou informațiile, trebuie să creați o matrice de octeți bazată pe reprezentarea șirului Base64 și apoi să apelați metoda de decriptare.
Rezultatul este prezentat în figura de mai jos:
Utilizarea algoritmilor asimetrici
Sunt folosiți algoritmi asimetrici ca algoritmi simetrici. Există foarte puține diferențe. Principala diferență este legată de managementul cheie. Dacă algoritmii simetrici se ocupă de o cheie, atunci în asimetric se folosesc două chei: una pentru criptarea datelor (cheia publică) și una pentru decriptare (cheia privată). În timp ce cheia publică poate fi disponibilă oricui dorește să cripteze datele, cheia secretă trebuie să fie accesibilă numai celor care o decriptează. În această secțiune, vom crea o clasă de servicii similară celei indicate anterior.
Deoarece .NET Framework vine cu un singur algoritm asimetric pentru criptarea datelor reale (RSA, amintiți-vă că DSA este utilizat doar pentru semnăturile digitale), nu este nevoie să includeți o modalitate de a selecta un algoritm:
Metoda GenerateKey () creează o instanță a algoritmului RSA pentru a genera cheia. Se stochează numai cheia secretă din fișier, protejându-l cu DPAPI și returnând cheia publică ca un șir XML folosind metoda ToXmlString () a algoritmului. Acesta este un concept destul de realist - o cheie secretă este, de obicei, păstrată în secret de aplicație, în timp ce cheia publică este împărțită cu alții pentru a putea cripta informații ulterior decriptate de aplicație folosind cheia secretă:
Codul care apelează această funcție trebuie să salveze undeva cheia publică primită - va fi necesară pentru criptarea informațiilor. Puteți extrage cheia în vizualizarea XML folosind metoda ToXmlString (). Parametrul specifică dacă informațiile cheii secrete (adevărate) trebuie să fie incluse sau nu (false). Astfel, funcția GenerateKey mai întâi numește o funcție cu parametrul adevărat pentru a stoca informații complete despre cheile din fișier și apoi o apelează cu argumentul false pentru a include numai cheia publică. Ulterior, metoda ReadKey () citește pur și simplu cheia din fișier și inițializează instanța transferată a algoritmului prin FromXml (). care este opusul metodei ToXmlString ():
De data aceasta, metoda ReadKey () este utilizată numai de funcția de decriptare. Funcția EncryptData () are drept argument argumentul reprezentării XML a cheii publice returnate de metoda GenerateKey (), deoarece cheia privată nu este obligată să efectueze criptarea. Criptarea și decriptarea utilizând RSA se efectuează după cum urmează:
Acum puteți construi o pagină de test, după cum se arată mai jos: