SecureString è mai pratico in un'applicazione C #?


224

Sentiti libero di correggermi se i miei presupposti sono sbagliati qui, ma lasciami spiegare perché lo sto chiedendo.

Tratto da MSDN, a SecureString:

Rappresenta il testo che deve essere mantenuto riservato. Il testo viene crittografato per motivi di privacy quando viene utilizzato ed eliminato dalla memoria del computer quando non è più necessario.

Capisco, ha perfettamente senso archiviare una password o altre informazioni private in un SecureStringover a System.String, perché è possibile controllare come e quando è effettivamente archiviato in memoria, perché a System.String:

è sia immutabile che, quando non è più necessario, non può essere programmato programmaticamente per la garbage collection; vale a dire, l'istanza è di sola lettura dopo che è stata creata e non è possibile prevedere quando l'istanza verrà eliminata dalla memoria del computer. Di conseguenza, se un oggetto String contiene informazioni riservate come una password, un numero di carta di credito o dati personali, esiste il rischio che le informazioni possano essere rivelate dopo essere state utilizzate poiché l'applicazione non può eliminare i dati dalla memoria del computer.

Tuttavia, nel caso di un'applicazione GUI (ad esempio un client ssh), SecureString deve essere creato da a System.String . Tutti i controlli di testo utilizzano una stringa come tipo di dati sottostante .

Quindi, questo significa che ogni volta che l'utente preme un tasto, la vecchia stringa presente viene scartata e viene creata una nuova stringa per rappresentare il valore all'interno della casella di testo, anche se si utilizza una maschera password. E non possiamo controllare quando o se qualcuno di questi valori viene scartato dalla memoria .

Ora è il momento di accedere al server. Indovina un po? È necessario passare una stringa sulla connessione per l'autenticazione . Quindi convertiamo il nostro SecureStringin un System.String.... e ora abbiamo una stringa nell'heap senza alcun modo per forzarla a passare attraverso la garbage collection (o scrivere 0 nel suo buffer).

Il mio punto è : non importa quello che fai, da qualche parte lungo la linea, che SecureStringsta andando a essere convertito in una System.String, il che significa che sarà almeno esistere sul mucchio ad un certo punto (senza alcuna garanzia di raccolta dei rifiuti).

Il mio punto non è : se ci sono modi per aggirare l'invio di una stringa a una connessione ssh o per evitare che un controllo memorizzi una stringa (crea un controllo personalizzato). Per questa domanda, puoi sostituire "connessione ssh" con "modulo di accesso", "modulo di registrazione", "modulo di pagamento", "alimenti-che-alimenteresti-il-tuo-cucciolo-ma-non-i-tuoi-figli", eccetera.

  • Quindi, a che punto l'utilizzo di un SecureStringdiventa effettivamente pratico?
  • Vale sempre la pena il tempo di sviluppo aggiuntivo per sradicare completamente l'uso di un System.Stringoggetto?
  • Il punto è SecureStringsemplicemente quello di ridurre la quantità di tempo a disposizione System.Stringdell'heap (riducendo il rischio di passare a un file di scambio fisico)?
  • Se un attaccante ha già i mezzi per un'ispezione dell'heap, molto probabilmente (A) ha già i mezzi per leggere le sequenze di tasti, oppure (B) ha già fisicamente la macchina ... Quindi usare un SecureStringimpedirgli di raggiungere il dati comunque?
  • È solo "sicurezza attraverso l'oscurità"?

Scusate se sto ponendo le domande troppo fitte, la curiosità ha appena avuto la meglio su di me. Sentiti libero di rispondere a una o tutte le mie domande (o dimmi che i miei presupposti sono completamente sbagliati). :)


25
Tieni presente che SecureStringnon è davvero una stringa sicura. È semplicemente un modo per ridurre la finestra temporale in cui qualcuno può ispezionare la tua memoria e ottenere con successo i dati sensibili. Questo non è a prova di proiettile e non doveva essere. Ma i punti che stai sollevando sono molto validi. Correlati: stackoverflow.com/questions/14449579/…
Theodoros Chatzigiannakis

1
@TheodorosChatzigiannakis, sì, è praticamente quello che ho pensato. Ho passato tutto il giorno oggi a scervellarmi per cercare di trovare un modo sicuro per archiviare una password per la durata della vita dell'applicazione, e mi ha fatto meravigliare, ne vale la pena?
Steven Jeffries,

1
Probabilmente non ne vale la pena. Ma poi, di nuovo, potresti difenderti da uno scenario estremo. Estremo non nel senso che è improbabile che qualcuno ottenga questo tipo di accesso al tuo computer, ma nel senso che se qualcuno ottiene questo tipo di accesso, il computer viene considerato (a tutti gli effetti) compromesso e io non Penso che ci sia una lingua o una tecnica che puoi usare per difenderti completamente.
Theodoros Chatzigiannakis,

8
Protegge da una password che è visibile per anni , molto tempo dopo che tutti hanno smesso di pensare che potrebbe esserci un problema. Su un disco rigido scartato, memorizzato nel file di paging. Strofinare la memoria in modo che le probabilità per questo siano basse è importante, non è possibile farlo con System.String poiché è immutabile. Richiede un'infrastruttura a cui pochi programmi oggi hanno accesso, interoperabilità con codice nativo, quindi i metodi Marshal.SecureStringXxx () sono utili sta diventando raro. O un modo decente per sollecitare l'utente :)
Hans Passant

1
SecureString è una tecnica di sicurezza approfondita. Il compromesso tra costo di sviluppo e guadagno di sicurezza non è favorevole nella maggior parte delle situazioni. Ci sono pochissimi casi d'uso per questo.
usr

Risposte:


237

In realtà ci sono usi molto pratici di SecureString.

Sai quante volte ho visto questi scenari? (la risposta è: molti!):

  • Una password appare accidentalmente in un file di registro.
  • Una password viene mostrata da qualche parte: una volta una GUI mostrava una riga di comando dell'applicazione che era in esecuzione e la riga di comando consisteva in password. Oops .
  • Utilizzo del profiler di memoria per profilare il software con il collega. Il collega vede la tua password in memoria. Sembra irreale? Affatto.
  • Una volta ho usato un RedGatesoftware in grado di catturare il "valore" delle variabili locali in caso di eccezioni, incredibilmente utile. Tuttavia, posso immaginare che registrerà accidentalmente "password di stringa".
  • Un dump di arresto anomalo che include la password della stringa.

Sai come evitare tutti questi problemi? SecureString. In genere si assicura che non si commettano errori stupidi in quanto tali. Come lo evita? Assicurandoti che la password sia crittografata nella memoria non gestita e che il valore reale sia accessibile solo quando sei sicuro al 90% di ciò che stai facendo.

Nel senso, SecureStringfunziona abbastanza facilmente:

1) Tutto è crittografato

2) Chiamate dell'utente AppendChar

3) Decifrare tutto in MEMORIA UNMANAGATA e aggiungere il personaggio

4) Cifrare di nuovo tutto nella MEMORIA NON GESTITA.

Cosa succede se l'utente ha accesso al tuo computer? Un virus sarebbe in grado di accedere a tutti SecureStrings? Sì. Tutto quello che devi fare è agganciarti RtlEncryptMemoryquando la memoria viene decifrata, otterrai la posizione dell'indirizzo di memoria non crittografato e la leggerai. Ecco! In effetti, potresti creare un virus che eseguirà costantemente la scansione per individuare SecureStringe registrare tutte le attività con esso. Non sto dicendo che sarà un compito facile, ma può essere fatto. Come puoi vedere, la "potenza" di SecureStringè completamente sparita quando c'è un utente / virus nel tuo sistema.

Hai alcuni punti nel tuo post. Certo, se si utilizzano alcuni dei controlli dell'interfaccia utente che contengono internamente una "password stringa", l'utilizzo di effettivo SecureStringnon è così utile. Tuttavia, può proteggere da una certa stupidità che ho elencato sopra.

Inoltre, come altri hanno notato, WPF supporta PasswordBox che utilizza SecureStringinternamente tramite la sua proprietà SecurePassword .

La linea di fondo è; se si dispone di dati sensibili (password, carte di credito, ..), utilizzare SecureString. Questo è ciò che segue C # Framework. Ad esempio, la NetworkCredentialclasse memorizza la password come SecureString. Se si guarda a questo , è possibile vedere oltre ~ 80 diversi usi in .NET framework di SecureString.

Ci sono molti casi in cui devi convertire SecureStringin stringa, perché alcune API lo prevedono .

Il solito problema è:

  1. L'API è GENERICA. Non sa che ci sono dati sensibili.
  2. L'API sa che ha a che fare con dati sensibili e usa "string" - questo è solo un cattivo design.

Hai sollevato un buon punto: cosa succede quando SecureStringviene convertito string? Questo può succedere solo a causa del primo punto. Ad esempio, l'API non sa che si tratta di dati sensibili. Personalmente non l'ho visto accadere. Ottenere la stringa da SecureString non è così semplice.

Non è semplice per un semplice motivo ; non è mai stato progettato per consentire all'utente di convertire SecureString in stringa, come hai affermato: GC si avvierà. Se ti vedi fare questo, devi fare un passo indietro e chiederti: perché lo sto facendo anche, o ho davvero bisogno questo, perché?

C'è un caso interessante che ho visto. Vale a dire, la funzione WinApi LogonUser utilizza LPTSTR come password, il che significa che è necessario chiamare SecureStringToGlobalAllocUnicode. Questo in pratica ti dà una password non crittografata che vive nella memoria non gestita. Devi liberartene non appena hai finito:

// Marshal the SecureString to unmanaged memory.
IntPtr rawPassword = Marshal.SecureStringToGlobalAllocUnicode(password);
try
{
   //...snip...
}
finally 
{
   // Zero-out and free the unmanaged string reference.
   Marshal.ZeroFreeGlobalAllocUnicode(rawPassword);
}

Puoi sempre estendere la SecureStringclasse con un metodo di estensione, come ad esempio ToEncryptedString(__SERVER__PUBLIC_KEY), che ti dà stringun'istanza SecureStringche è crittografata usando la chiave pubblica del server. Solo il server può quindi decrittografarlo. Problema risolto: Garbage Collection non vedrà mai la stringa "originale", poiché non la esponi mai nella memoria gestita. Questo è esattamente ciò che viene fatto in PSRemotingCryptoHelper( EncryptSecureStringCore(SecureString secureString)).

E come qualcosa di molto simile: Mono SecureString non crittografa affatto . L'implementazione è stata commentata perché .. aspettatela .. "In qualche modo provoca la rottura del test nunit" , il che porta al mio ultimo punto:

SecureStringnon è supportato ovunque. Se la piattaforma / architettura non supporta SecureString, otterrai un'eccezione. C'è un elenco di piattaforme supportate nella documentazione.


Penserei che SecureStringsarebbe molto più pratico se esistesse un meccanismo per accedere ai singoli personaggi. L'efficienza di un tale meccanismo potrebbe essere migliorata avendo un tipo di struttura SecureStringTempBuffersenza membri pubblici, che potrebbe essere passato refal SecureStringmetodo "leggi un carattere" [se la crittografia / decodifica viene elaborata in blocchi di 8 caratteri, tale struttura potrebbe contenere dati per 8 caratteri e la posizione del primo di quei caratteri all'interno di SecureString].
supercat

2
Lo contrassegno in ogni controllo del codice sorgente che eseguo. Va anche ripetuto che se lo si utilizza SecureStringdeve essere utilizzato fino in fondo nello stack.
Casey,

1
Ho implementato l'estensione .ToEncryptedString () ma utilizzando il certificato. Ti dispiacerebbe dare un'occhiata e fammi sapere se sto facendo tutto sbagliato. Spero che sia sicuro engouhg gist.github.com/sturlath/99cfbfff26e0ebd12ea73316d0843330
Sturla

@Sturla - Cosa c'è EngineSettingsnel tuo metodo di estensione?
InteXX,


15

Ci sono alcuni problemi nei tuoi presupposti.

Innanzitutto la classe SecureString non ha un costruttore String. Per crearne uno, allocare un oggetto e quindi aggiungere i caratteri.

Nel caso di una GUI o di una console, è possibile passare molto facilmente ogni tasto premuto a una stringa protetta.

La classe è progettata in modo tale da non poter accedere, per errore, al valore memorizzato. Ciò significa che non è possibile ottenere la stringpassword direttamente da essa.

Quindi, per usarlo, ad esempio, per autenticarti attraverso il web, dovrai usare classi appropriate che siano anche sicure.

Nel framework .NET esistono alcune classi che possono utilizzare SecureString

  • Il controllo PasswordBox di WPF mantiene la password come SecureString internamente.
  • La proprietà Password di System.Diagnostics.ProcessInfo è SecureString.
  • Il costruttore per X509Certificate2 accetta un SecureString per la password.

(Di Più)

Per concludere, la classe SecureString può essere utile, ma richiede maggiore attenzione da parte dello sviluppatore.

Tutto questo, con esempi, è ben descritto nella documentazione di SecureString di MSDN


10
Non capisco bene il terzo all'ultimo paragrafo della tua risposta. Come trasferiresti un SecureStringsulla rete senza serializzarlo in un string? Penso che l'OP della domanda sia che arriva un momento in cui si desidera effettivamente utilizzare il valore mantenuto in modo sicuro in a SecureString, il che significa che è necessario estrarlo da lì e non è più sicuro. In tutta la libreria di classi Framework, non ci sono praticamente metodi che accettano SecureStringdirettamente un input (per quanto posso vedere), quindi qual è il punto di mantenere un valore all'interno di a SecureStringin primo luogo?
stakx - non contribuisce più il

@ DamianLeszczyński-Vash, so che SecureString non ha un costruttore di stringhe, ma il punto è che tu (A) crei un SecureString e aggiungi ogni carattere da una stringa ad esso, o (B) ad un certo punto devi usare il valore memorizzato in SecureString come stringa per passarlo ad alcune API. Detto questo, fai emergere alcuni punti positivi e posso vedere come in alcuni casi molto specifici possa essere utile.
Steven Jeffries,

1
@stakx Lo invieresti attraverso la rete ottenendo char[]e inviando ciascuno charsu un socket, senza creare oggetti da raccogliere nel cestino.
user253751

Char [] è raccoglibile ed è modificabile, quindi può essere sovrascritto.
Peter Ritchie,

Naturalmente, è anche facile dimenticare di sovrascrivere quell'array. In ogni caso, qualsiasi API a cui passi i caratteri può anche fare una copia.
cHao,

10

Un SecureString è utile se:

  • Lo costruisci carattere per carattere (ad es. Dall'input della console) o lo ottieni da un'API non gestita

  • Lo si utilizza passandolo a un'API non gestita (SecureStringToBSTR).

Se mai lo converti in una stringa gestita, hai annullato il suo scopo.

AGGIORNAMENTO in risposta al commento

... o BSTR come dici tu, che non sembra più sicuro

Dopo essere stato convertito in un BSTR, il componente non gestito che consuma il BSTR può azzerare la memoria. La memoria non gestita è più sicura nel senso che può essere ripristinata in questo modo.

Tuttavia, ci sono pochissime API in .NET Framework che supportano SecureString, quindi hai ragione a dire che oggi ha un valore molto limitato.

Il caso d'uso principale che vedrei è in un'applicazione client che richiede all'utente di inserire un codice o una password altamente sensibili. L'input dell'utente può essere utilizzato carattere per carattere per creare un SecureString, quindi può essere passato a un'API non gestita, che azzera il BSTR che riceve dopo averlo utilizzato. Qualsiasi successivo dump della memoria non conterrà la stringa sensibile.

In un'applicazione server è difficile vedere dove sarebbe utile.

AGGIORNAMENTO 2

Un esempio di API .NET che accetta SecureString è questo costruttore per la classe X509Certificate . Se esegui il spelunking con ILSpy o simili, vedrai che SecureString viene convertito internamente in un buffer non gestito ( Marshal.SecureStringToGlobalAllocUnicode), che viene quindi azzerato al termine di ( Marshal.ZeroFreeGlobalAllocUnicode).


1
+1, ma non finirai sempre per "sconfiggere il suo scopo"? Dato che quasi nessun metodo nella libreria di classi Framework accetta un SecureStringinput, quale sarebbe il loro utilizzo? Dovresti sempre riconvertirti stringprima o poi (o BSTRcome dici, che non sembra più sicuro). Quindi perché preoccuparsene SecureString?
stakx - non contribuisce più il

5

Microsoft non consiglia di utilizzare SecureStringper i codici più recenti.

Dalla documentazione della classe SecureString :

Importante

Non è consigliabile utilizzare la SecureStringclasse per nuovi sviluppi. Per ulteriori informazioni, vedere SecureStringnon dovrebbe essere utilizzato

Che raccomanda:

Non utilizzare SecureStringper il nuovo codice. Quando si esegue il porting del codice su .NET Core, tenere presente che i contenuti dell'array non sono crittografati in memoria.

L'approccio generale di gestione delle credenziali è quello di evitarle e invece fare affidamento su altri mezzi per l'autenticazione, come certificati o autenticazione di Windows. su GitHub.


4

Come hai correttamente identificato, SecureStringoffre uno specifico vantaggio rispetto alla stringcancellazione deterministica. Ci sono due problemi con questo fatto:

  1. Come altri hanno già detto e come hai notato da solo, questo non è abbastanza da solo. Devi assicurarti che ogni fase del processo (incluso il recupero dell'input, la costruzione della stringa, l'uso, la cancellazione, il trasporto, ecc.) Avvenga senza vanificare lo scopo dell'uso SecureString. Ciò significa che è necessario fare attenzione a non creare un GC gestiti immutabile stringo qualsiasi altro tampone che memorizzerà le informazioni sensibili (o si dovrà tenere traccia di che pure). In pratica, questo non è sempre facile da raggiungere, perché molte API offrono solo un modo di lavorare string, non SecureString. E anche se riesci a fare tutto bene ...
  2. SecureStringprotegge da attacchi molto specifici (e per alcuni di essi non è nemmeno così affidabile). Ad esempio, SecureStringti consente di ridurre la finestra temporale in cui un utente malintenzionato può scaricare la memoria del tuo processo ed estrarre correttamente le informazioni sensibili (di nuovo, come hai correttamente sottolineato), ma sperando che la finestra sia troppo piccola per l'attaccante fare un'istantanea della tua memoria non è affatto considerata sicurezza.

Quindi, quando dovresti usarlo? Solo quando lavori con qualcosa che può permetterti di lavorare SecureStringper tutte le tue esigenze e anche in questo caso dovresti comunque tenere presente che questo è sicuro solo in circostanze specifiche.


2
Supponi che un utente malintenzionato sia in grado di eseguire l'istantanea della memoria di un processo in un determinato momento. Questo non è necessariamente il caso. Considera una discarica. Se l'arresto anomalo si è verificato dopo che l'applicazione è stata eseguita con i dati riservati, il dump dell'arresto anomalo non deve contenere i dati riservati.

4

Il testo seguente viene copiato dall'analizzatore di codice statico HP Fortify

Riassunto: il metodo PassString () in PassGenerator.cs memorizza i dati sensibili in modo non sicuro (ad esempio nella stringa), consentendo di estrarre i dati tramite l'ispezione dell'heap.

Spiegazione: I dati sensibili (come password, numeri di previdenza sociale, numeri di carte di credito, ecc.) Archiviati in memoria possono essere divulgati se archiviati in un oggetto String gestito. Gli oggetti stringa non sono bloccati, quindi il Garbage Collector può riposizionare questi oggetti a piacimento e lasciare più copie in memoria. Questi oggetti non sono crittografati per impostazione predefinita, quindi chiunque sia in grado di leggere la memoria del processo sarà in grado di vedere i contenuti. Inoltre, se la memoria del processo viene scambiata su disco, i contenuti non crittografati della stringa verranno scritti in un file di scambio. Infine, poiché gli oggetti String sono immutabili, la rimozione del valore di una stringa dalla memoria può essere eseguita solo dal garbage collector CLR. Non è necessario eseguire Garbage Collector a meno che il CLR non abbia memoria insufficiente, quindi non esiste alcuna garanzia su quando verrà eseguita la Garbage Collection.

Raccomandazioni: invece di archiviare dati sensibili in oggetti come String, archiviarli in un oggetto SecureString. Ogni oggetto memorizza i suoi contenuti in un formato crittografato in ogni momento.


3

Vorrei affrontare questo punto:

Se un attaccante ha già i mezzi per un'ispezione dell'heap, molto probabilmente (A) hanno già i mezzi per leggere i tasti premuti, oppure (B) hanno già fisicamente la macchina ... Quindi usare un sistema SecureStringimpedisce loro di raggiungere dati comunque?

Un utente malintenzionato potrebbe non avere pieno accesso al computer e all'applicazione, ma può disporre di mezzi per accedere ad alcune parti della memoria del processo. Di solito è causato da bug come sovraccarichi del buffer quando l'input appositamente costruito può far sì che l'applicazione esponga o sovrascriva parte della memoria.

Memoria che perde HeartBleed

Prendi Heartbleed per esempio. Le richieste appositamente costruite possono far sì che il codice esponga parti attaccate della memoria del processo all'attaccante. Un utente malintenzionato può estrarre certificati SSL dalla memoria, ma l'unica cosa di cui ha bisogno è solo usare una richiesta non valida.

Nel mondo del codice gestito, i sovraccarichi del buffer diventano un problema molto meno spesso. E nel caso di WinForms, i dati sono già archiviati in modo non sicuro e non puoi farci nulla. Questo rende la protezione SecureStringpraticamente inutile.

Tuttavia, la GUI può essere programmata per l'uso SecureStringe in tal caso può valere la pena ridurre la finestra di disponibilità della password in memoria. Ad esempio, PasswordBox.SecurePassword di WPF è di tipo SecureString.


Hmm, sicuramente interessante da sapere. In tutta onestà, in realtà non sono così preoccupato per il tipo di attacchi necessari anche per ottenere un sistema. Valore della memoria fuori dalla mia memoria, sto solo chiedendo per pura curiosità. Tuttavia, grazie per l'informazione! :)
Steven Jeffries,

2

Qualche tempo fa ho dovuto creare un'interfaccia ac # contro un gateway di pagamento con carta di credito java e uno aveva bisogno di una crittografia della chiave di comunicazione sicura compatibile. Dato che l'implementazione Java era piuttosto specifica e ho dovuto lavorare con i dati protetti in un determinato modo.

Ho trovato questo design molto semplice da usare e più semplice che lavorare con SecureString ... per coloro a cui piace usare ... sentiti libero, senza restrizioni legali :-). Nota che queste classi sono interne, potrebbe essere necessario renderle pubbliche.

namespace Cardinity.Infrastructure
{
    using System.Security.Cryptography;
    using System;
    enum EncryptionMethods
    {
        None=0,
        HMACSHA1,
        HMACSHA256,
        HMACSHA384,
        HMACSHA512,
        HMACMD5
    }


internal class Protected
{
    private  Byte[] salt = Guid.NewGuid().ToByteArray();

    protected byte[] Protect(byte[] data)
    {
        try
        {
            return ProtectedData.Protect(data, salt, DataProtectionScope.CurrentUser);
        }
        catch (CryptographicException)//no reason for hackers to know it failed
        {
#if DEBUG
            throw;
#else
            return null;
#endif
        }
    }

    protected byte[] Unprotect(byte[] data)
    {
        try
        {
            return ProtectedData.Unprotect(data, salt, DataProtectionScope.CurrentUser);
        }
        catch (CryptographicException)//no reason for hackers to know it failed
        {
#if DEBUG
            throw;
#else
            return null;
#endif
        }
    }
}


    internal class SecretKeySpec:Protected,IDisposable
    {
        readonly EncryptionMethods _method;

        private byte[] _secretKey;
        public SecretKeySpec(byte[] secretKey, EncryptionMethods encryptionMethod)
        {
            _secretKey = Protect(secretKey);
            _method = encryptionMethod;
        }

        public EncryptionMethods Method => _method;
        public byte[] SecretKey => Unprotect( _secretKey);

        public void Dispose()
        {
            if (_secretKey == null)
                return;
            //overwrite array memory
            for (int i = 0; i < _secretKey.Length; i++)
            {
                _secretKey[i] = 0;
            }

            //set-null
            _secretKey = null;
        }
        ~SecretKeySpec()
        {
            Dispose();
        }
    }

    internal class Mac : Protected,IDisposable
    {
        byte[] rawHmac;
        HMAC mac;
        public Mac(SecretKeySpec key, string data)
        {

            switch (key.Method)
            {
                case EncryptionMethods.HMACMD5:
                    mac = new HMACMD5(key.SecretKey);
                    break;
                case EncryptionMethods.HMACSHA512:
                    mac = new HMACSHA512(key.SecretKey);
                    break;
                case EncryptionMethods.HMACSHA384:
                    mac = new HMACSHA384(key.SecretKey);
                    break;
                case EncryptionMethods.HMACSHA256:
                    mac = new HMACSHA256(key.SecretKey);

                break;
                case EncryptionMethods.HMACSHA1:
                    mac = new HMACSHA1(key.SecretKey);
                    break;

                default:                    
                    throw new NotSupportedException("not supported HMAC");
            }
            rawHmac = Protect( mac.ComputeHash(Cardinity.ENCODING.GetBytes(data)));            

        }

        public string AsBase64()
        {
            return System.Convert.ToBase64String(Unprotect(rawHmac));
        }

        public void Dispose()
        {
            if (rawHmac != null)
            {
                //overwrite memory address
                for (int i = 0; i < rawHmac.Length; i++)
                {
                    rawHmac[i] = 0;
                }

                //release memory now
                rawHmac = null;

            }
            mac?.Dispose();
            mac = null;

        }
        ~Mac()
        {
            Dispose();
        }
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.