SecureString bir C # uygulamasında pratik mi?


224

Varsayımlarım yanlışsa beni düzeltmekten çekinmeyin, ama neden sorduğumu açıklayayım.

MSDN'den alınan SecureString:

Gizli tutulması gereken metni temsil eder. Metin kullanıldığında gizlilik için şifrelenir ve artık gerekmediğinde bilgisayar belleğinden silinir.

Bunu anlıyorum, bir parola veya diğer özel bilgileri bir SecureStringüzerinde saklamak tam anlamıyla mantıklı System.String, çünkü gerçekte nasıl ve ne zaman bellekte saklanacağını kontrol edebilirsiniz, çünkü System.String:

hem değişmez hem de artık gerekmediğinde, çöp toplama için programlı olarak planlanamaz; yani, örnek oluşturulduktan sonra salt okunurdur ve örneğin bilgisayar belleğinden ne zaman silineceğini tahmin etmek mümkün değildir. Sonuç olarak, bir String nesnesi parola, kredi kartı numarası veya kişisel veriler gibi hassas bilgiler içeriyorsa, uygulamanız verileri bilgisayar belleğinden silemediği için bilgilerin kullanıldıktan sonra açığa çıkma riski vardır.

Ancak, bir GUI uygulaması (örneğin, bir ssh istemcisi) söz SecureString konusu olduğunda, a System.String . Tüm metin denetimleri , temel veri türü olarak bir dize kullanır .

Bu, kullanıcı bir tuşa her bastığında, oradaki eski dizenin atıldığı ve parola maskesi kullanıyor olsa bile metin kutusundaki değerin ne olduğunu göstermek için yeni bir dize oluşturulduğu anlamına gelir. Ve bu değerlerden herhangi birinin bellekten ne zaman atılacağını veya atılacağını kontrol edemeyiz .

Şimdi sunucuya giriş yapma zamanı. Bil bakalım ne oldu? Kimlik doğrulama için bağlantının üzerinden bir dize geçirmeniz gerekir . O halde bizim dönüştürmek izin SecureStringbir içine System.String.... ve şimdi çöp toplama geçmesi zorlamak (veya tampon ile 0'lar yazma) için bir yol ile yığın bir dize var.

Benim noktasıdır : sen ne olursa olsun, hat boyunca bir yerde, SecureStringbir gidiş bir çevrilmek üzere System.Stringbunu anlamı, bir noktada yığın üzerinde en varoldukları için de (çöp toplama bir garantisi olmadan) olacak.

Benim açımdan : ssh bağlantısına bir dize göndermeyi engellemenin veya bir kontrol deposunun bir dizgiye sahip olmasını engellemenin (özel bir kontrol yapmanın) yolları olup olmadığı değil . Bu soru için, "ssh bağlantısı" yerine "giriş formu", "kayıt formu", "ödeme formu", "köpek yavrusu-çocuk-değil-sizin-çocuk-değil-formu-gıda-gıda", vb.

  • Peki, SecureStringgerçekte hangi noktada kullanmak pratik hale geliyor?
  • Bir System.Stringnesnenin kullanımını tamamen ortadan kaldırmak için ekstra geliştirme zamanına değecek mi?
  • Bütün mesele a'nın yığın üzerindeki SecureStringsüresini azaltmak mıdır System.String(fiziksel bir takas dosyasına geçme riskini azaltmak)?
  • Bir saldırgan zaten yığın denetimi için araçlara sahipse, büyük olasılıkla (A) tuş vuruşlarını okuma araçlarına sahiptir veya (B) fiziksel olarak makineye sahiptir ... Bu yüzden onu kullanmasını SecureStringönlemek Yine de veri?
  • Bu sadece "muğlaklık yoluyla güvenlik" midir?

Eğer soruları çok kalın soruyorsam özür dilerim, merakım daha iyi oldu. Sorularımın herhangi birini veya tümünü yanıtlamaktan çekinmeyin (veya varsayımlarımın tamamen yanlış olduğunu söyle). :)


25
SecureStringGerçekten güvenli bir dize olmadığını unutmayın . Bu sadece birisinin belleğinizi inceleyebileceği ve hassas verileri başarıyla alabileceği zaman penceresini azaltmanın bir yoludur. Bu kurşun geçirmez değildir ve olması amaçlanmamıştır. Ancak yükselttiğiniz noktalar çok geçerli. İlgili: stackoverflow.com/questions/14449579/…
Theodoros Chatzigiannakis

1
@TheodorosChatzigiannakis, evet, hemen hemen anladım. Bugün bütün gün, uygulamanın ömrü boyunca bir şifre saklamak için güvenli bir yol bulmaya çalışırken beynimi sarsarak geçirdim ve sadece merak ettim, buna değer mi?
Steven Jeffries

1
Muhtemelen buna değmez. Ama sonra, yine, aşırı bir senaryoya karşı savunuyor olabilirsiniz. Birisi bilgisayarınıza bu tür bir erişim elde etmek olası değildir, ama eğer birisi bu tür bir erişim elde ederse, bilgisayarın (tüm niyet ve amaçlar için) tehlikeye atılmış olduğu ve Buna karşı tamamen savunmak için kullanabileceğiniz herhangi bir dil veya teknik olduğunu düşünmeyin.
Theodoros Chatzigiannakis

8
Herkesin bir sorun olabileceğini düşünmesinden çok sonra, yıllarca görünür olan bir parolaya karşı koruma sağlar . Disk belleği dosyasında saklanan atılan bir sabit sürücüde. Bunun için olasılıklar düşük olacak şekilde belleği fırçalamak önemlidir, değişmez olduğu için bunu System.String ile yapamazsınız. Bu günlerde az sayıda programın erişebildiği, yerel kodla birlikte çalışabilmesi için Marshal.SecureStringXxx () yöntemlerinin kullanışlı olması için altyapı gerekir. Ya da kullanıcıyı bunun için
sormanın

1
SecureString derinlemesine bir güvenlik tekniğidir. Geliştirme maliyeti ile güvenlik kazancı arasındaki denge çoğu durumda elverişli değildir. Bunun için çok az iyi kullanım durumu vardır.
usr

Yanıtlar:


237

Aslında çok pratik kullanımları vardır SecureString.

Bu senaryoları kaç kez gördüğümü biliyor musunuz? (cevap: çok!):

  • Günlük dosyasında yanlışlıkla bir parola belirir.
  • Bir yerde bir parola gösteriliyor - bir GUI çalıştırılmakta olan bir komut satırı uygulaması gösterdiğinde ve komut satırı paroladan oluşuyordu. Hata !
  • İş arkadaşınızla yazılımı profillemek için bellek profiler kullanma İş arkadaşınız şifrenizi hafızada görüyor. Gerçek değil mi? Bir şey değil.
  • Bir keresinde RedGateistisnalar durumunda yerel değişkenlerin "değerini" yakalayabilen bir yazılım kullandım . Yine de, yanlışlıkla "dize parolaları" günlüğe kaydedecek hayal edebiliyorum.
  • Dize parolası içeren bir kilitlenme dökümü.

Tüm bu problemlerden nasıl kaçınacağınızı biliyor musunuz? SecureString. Genellikle aptalca hatalar yapmamanızı sağlar. Nasıl önler? Parolanın yönetilmeyen bellekte şifrelenmiş olduğundan ve gerçek değere yalnızca ne yaptığınızdan% 90 emin olduğunuzda erişilebilir.

Bu anlamda SecureStringoldukça kolay çalışır:

1) Her şey şifreli

2) Kullanıcı çağrıları AppendChar

3) YÖNETİLMEYEN BELLEK içindeki her şeyin şifresini çözün ve karakteri ekleyin

4) Yönetilmeyen BELLEK içinde her şeyi tekrar şifreleyin.

Kullanıcının bilgisayarınıza erişimi varsa ne olur? Bir virüs hepsine erişebilir SecureStringsmi? Evet. Yapmanız gereken tek şey, RtlEncryptMemorybelleğin şifresi çözülürken kendinizi takmaktır, şifrelenmemiş bellek adresinin yerini alacak ve okuyacaksınız. İşte bu kadar! Aslında, SecureStringtüm aktiviteleri kullanmak için sürekli olarak tarayacak ve onunla tüm aktiviteleri kaydedecek bir virüs oluşturabilirsiniz . Kolay bir iş olacağını söylemiyorum, ama yapılabilir. Gördüğünüz gibi SecureString, sisteminizde bir kullanıcı / virüs olduğunda "gücü" tamamen ortadan kalkmıştır.

Yayınınızda birkaç nokta var. Tabii ki, dahili bir "dize parolası" tutan UI denetimlerinden bazılarını kullanırsanız, gerçek kullanmak SecureStringo kadar faydalı değildir. Yine de, yukarıda listelediğim bazı aptallıklara karşı koruma sağlayabilir.

Ayrıca, diğerlerinin de belirttiği gibi, WPF SecureString, SecurePassword özelliği aracılığıyla dahili olarak kullanılan PasswordBox'u destekler .

Sonuç olarak; hassas verileriniz varsa (şifreler, kredi kartları, ..), kullanın SecureString. Bu C # Framework takip ediyor. Örneğin, NetworkCredentialsınıf parolayı olarak depolar SecureString. Eğer bakarsanız bu , size .NET çerçevesinde ~ 80 farklı kullanımlarını üzerinde görebilirsiniz SecureString.

SecureStringBazı API'lar beklediği için dizeye dönüştürmeniz gereken birçok durum vardır .

Her zamanki sorun ya:

  1. API GENERIC'tir. Hassas bir veri olduğunu bilmiyor.
  2. API, hassas verilerle uğraştığını bilir ve "string" kullanır - bu sadece kötü bir tasarımdır.

İyi bir noktaya değindiniz: SecureStringdönüştürüldüğünde ne olur string? Bu sadece ilk noktadan dolayı olabilir. Örneğin, API hassas verilerin olduğunu bilmiyor. Ben şahsen bunun olduğunu görmedim. SecureString'den dize almak o kadar kolay değil.

Basit bir nedenden dolayı basit değil ; kullanıcının belirttiğiniz gibi SecureString'i dizeye dönüştürmesine izin vermek asla amaçlanmamıştı: GC devreye girecek. Bunu yaparken kendinize geri dönüp kendinize sormanız gerekiyor: Bunu neden yapıyorum, ya da gerçekten ihtiyacım var Bu neden?

Gördüğüm ilginç bir durum var. Yani, WinApi fonksiyonu LogonUser LPTSTR'yi bir şifre olarak alır, yani aramanız gerekir SecureStringToGlobalAllocUnicode. Bu temel olarak yönetilmeyen bellekte yaşayan şifrelenmemiş bir şifre verir. İşiniz bittiğinde bundan kurtulmanız gerekir:

// 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);
}

SecureStringSınıfı, sunucunun ortak anahtarı kullanılarak şifrelenmiş ToEncryptedString(__SERVER__PUBLIC_KEY)bir stringörneğini veren gibi bir uzantı yöntemiyle her zaman genişletebilirsiniz SecureString. Sadece sunucu şifresini çözebilir. Sorun çözüldü: Çöp Toplama asla "orijinal" dizesini görmeyecektir, çünkü yönetilen belleğe asla maruz bırakmazsınız. PSRemotingCryptoHelper( EncryptSecureStringCore(SecureString secureString)) ' Da tam olarak yapılan budur .

Ve çok ilgili bir şey olarak: Mono SecureString hiç şifrelemez . Uygulama yorumlandı çünkü .. bekle .. "Bir şekilde rahibe testi kırılmasına neden oluyor" , bu benim son noktaya getiriyor:

SecureStringher yerde desteklenmez. Platform / mimari desteklemiyorsa SecureString, bir istisna alırsınız. Belgelerde desteklenen platformların bir listesi var.


Tek tek karakterlerine erişmek için bir mekanizma olsaydı SecureStringçok daha pratik olacağını düşünürdüm . Böyle bir mekanizmanın etkinliği, SecureStringTempBufferherhangi bir genel üyesi olmayan bir yapı türüne sahip olarak geliştirilebilir ve bu ref, SecureString"bir karakteri oku" yöntemine [şifreleme / şifre çözme 8 karakterlik parçalarda işlenirse, böyle bir yapı veri tutabilir 8 karakter ve bu karakterlerden ilkinin SecureString] içindeki yeri .
supercat

2
Bunu yaptığım her kaynak kodu denetiminde işaretliyorum. Ayrıca kullanırsanız SecureString, yığının sonuna kadar kullanılması gerektiği de tekrarlanmalıdır .
Casey

1
.ToEncryptedString () uzantısını ancak sertifika kullanarak uyguladım. Bir göz atmak ister misiniz ve tüm bunları yanlış yapıyorsam bana bildirin. Onun güvenli engouhg umuduyla Özür gist.github.com/sturlath/99cfbfff26e0ebd12ea73316d0843330
Sturla

@Sturla - EngineSettingsUzantı Yöntemi nedir?
InteXX


15

Varsayımlarınızdaki az sayıdaki sorun.

Her şeyden önce SecureString sınıfının bir String yapıcısı yoktur. Bir tane oluşturmak için bir nesne tahsis edip karakterleri eklersiniz.

Bir GUI veya konsol durumunda, basılan her anahtarı güvenli bir dizeye kolayca geçirebilirsiniz.

Sınıf, yanlışlıkla depolanan değere erişemeyeceğiniz şekilde tasarlanmıştır. Bu, stringparolayı doğrudan ondan alamayacağınız anlamına gelir .

Bu nedenle, örneğin web üzerinden kimlik doğrulaması yapmak için kullanmak için güvenli olan uygun sınıfları kullanmanız gerekecektir.

.NET çerçevesinde SecureString'i kullanabileceğiniz birkaç sınıfınız var

  • WPF'nin PasswordBox denetimi, şifreyi dahili olarak SecureString olarak tutar.
  • System.Diagnostics.ProcessInfo's Password özelliği bir SecureString'dir.
  • X509Certificate2 yapıcısı, parola için bir SecureString alır.

(Daha)

Sonuç olarak, SecureString sınıfı yararlı olabilir, ancak geliştiriciden daha fazla dikkat gerektirir.

Bütün bunlar, örneklerle, MSDN'nin SecureString belgelerinde iyi açıklanmıştır.


10
Cevabınızın üçüncü-son paragrafını tam olarak anlamıyorum. Bir ağı, a serileştirmeden nasıl aktarırsınız ? Sorunun OP'nin amacı , a'da tutulan değeri gerçekten kullanmak istediğiniz bir zamanın geldiğini düşünüyorum , yani onu oradan çıkarmak zorundasınız ve artık güvenli değil. Tüm Çerçeve Sınıf Kitaplığı'nda, doğrudan bir girişi (görebildiğim kadarıyla) kabul eden neredeyse hiç yöntem yoktur , bu yüzden bir değeri bir yerde tutmanın anlamı nedir? SecureStringstringSecureStringSecureStringSecureString
stakx - artık

@ DamianLeszczyński-Vash, SecureString'in bir dize yapıcısı olmadığını biliyorum, ama benim açımdan (A) bir SecureString oluşturup her karakteri bir dizeden ona eklemeniz veya bir noktada kullanmanız gerekiyor SecureString içinde bir API olarak aktarmak için dize olarak saklanan değer. Bununla birlikte, bazı iyi noktalar ortaya çıkarıyorsunuz ve bazı çok özel durumlarda bunun nasıl yararlı olabileceğini görebiliyorum.
Steven Jeffries

1
@stakx Bu işlemi ağ üzerinden char[]gönderir ve her birini charbir soket üzerinden göndererek , işlemde çöp toplanabilir nesneler oluşturmazsınız.
user253751

Char [] toplanabilir ve değiştirilebilir, bu yüzden üzerine yazılabilir.
Peter Ritchie

Tabii ki, bu dizinin üzerine yazmayı da unutmak kolaydır. Her iki durumda da, grafikleri ilettiğiniz API'ler de bir kopya oluşturabilir.
cHao

10

Bir SecureString aşağıdaki durumlarda kullanışlıdır:

  • Karakteri karaktere göre (örneğin konsol girişinden) oluşturursunuz veya yönetilmeyen bir API'dan alırsınız

  • Yönetilmeyen bir API'ye (SecureStringToBSTR) ileterek kullanabilirsiniz.

Yönetilen bir dizgiye dönüştürürseniz, amacını yendiniz.

Yoruma yanıt olarak GÜNCELLEME

... veya bahsettiğiniz gibi BSTR, artık daha güvenli görünmüyor

Bir BSTR'a dönüştürüldükten sonra, BSTR'yi kullanan yönetilmeyen bileşen belleği sıfırlayabilir. Yönetilmeyen bellek, bu şekilde sıfırlanabilmesi açısından daha güvenlidir.

Bununla birlikte, .NET Framework'te SecureString'i destekleyen çok az sayıda API vardır, bu yüzden bugün çok sınırlı bir değere sahip olduğunu söylemekte haklısınız.

Gördüğüm ana kullanım durumu, kullanıcının son derece hassas bir kod veya şifre girmesini gerektiren bir istemci uygulamasındadır. Kullanıcı girişi, bir SecureString oluşturmak için karakter karakter kullanılabilir, daha sonra bu, yönetildikten sonra aldığı BSTR'yi sıfırlayan yönetilmeyen bir API'ye geçirilebilir. Sonraki bellek dökümü hassas dizeyi içermez.

Bir sunucu uygulamasında, nerede yararlı olacağını görmek zor.

GÜNCELLEME 2

SecureString'i kabul eden bir .NET API örneği , X509Certificate sınıfı için bu kurucudur . ILSpy veya benzeri ile spelunk ederseniz, SecureString'in dahili olarak yönetilmeyen bir arabelleğe ( Marshal.SecureStringToGlobalAllocUnicode) dönüştürüldüğünü görürsünüz , bu daha sonra ( Marshal.ZeroFreeGlobalAllocUnicode) ile bittiğinde sıfırlanır .


1
+1, ancak her zaman "amacını yenmek" zorunda kalmayacak mısınız? Çerçeve Sınıf Kitaplığı'ndaki neredeyse hiçbir yöntemin bir SecureStringgirdi olarak kabul edilmediği düşünüldüğünde, bunların kullanımı ne olur? Her zaman stringer ya da geç dönmelisiniz (ya da daha önce BSTRbahsettiğiniz gibi, bu daha güvenli görünmüyor). Öyleyse neden hiç uğraşmıyorsunuz SecureString?
stakx - artık

5

Microsoft, SecureStringdaha yeni kodlar için kullanılmasını önermez .

SecureString Sınıfının belgelerinden :

Önemli

SecureStringSınıfı yeni gelişim için kullanmanızı önermiyoruz . Daha fazla bilgi için, bkz SecureStringkullanılmamalıdır

Hangi tavsiye eder:

SecureStringYeni kod için kullanmayın . Kodu .NET Core'a taşırken, dizinin içeriğinin bellekte şifrelenmediğini düşünün.

Kimlik bilgileriyle başa çıkmanın genel yaklaşımı bunlardan kaçınmak ve bunun yerine sertifikalar veya Windows kimlik doğrulaması gibi diğer kimlik doğrulama yöntemlerine güvenmektir. GitHub.


4

Doğru bir şekilde tanımladığınız gibi, SecureStringbelirli bir avantaj sunar string: deterministik silme. Bu gerçekle ilgili iki sorun var:

  1. Diğerlerinin de belirttiği gibi ve kendiniz fark ettiğiniz gibi, bu tek başına yeterli değildir. Sürecin her adımının (girişin geri alınması, ipin yapımı, kullanım, silme, nakliye, vb. Dahil), kullanım amacını bozmadan gerçekleştiğinden emin olmalısınız SecureString. Çöp toplamayla yönetilen değişmez oluşturmak asla dikkatli olması gerektiğini bu araç stringveya hassas bilgileri depolayacak başka tampon (veya takip etmek gerekecek o sıra). Pratikte, bunu başarmak her zaman kolay değildir, çünkü birçok API, çalışmak için sadece bir yol sunar string, değil SecureString. Ve her şeyi doğru yapsanız bile ...
  2. SecureStringçok özel saldırı türlerine karşı koruma sağlar (ve bazıları için o kadar da güvenilir değildir). Örneğin, SecureStringbir saldırganın işleminizin belleğini dökebileceği ve hassas bilgileri (doğru şekilde işaret ettiğiniz gibi) başarıyla ayıklayabileceği zaman penceresini küçültmenize izin verir, ancak pencerenin saldırgan için çok küçük olmasını umarak belleğinizin anlık görüntüsünü almak hiç güvenlik olarak kabul edilmez.

Peki, ne zaman kullanmalısın? Sadece SecureStringtüm ihtiyaçlarınız için çalışmanıza izin verebilecek bir şeyle çalışırken ve o zaman bile bunun sadece belirli durumlarda güvenli olduğuna dikkat etmelisiniz.


2
Saldırganın herhangi bir zamanda bir işlemin belleğini anlık olarak çekebileceğini varsayıyorsunuz. Bu her zaman böyle değildir. Bir çarpışma dökümü düşünün. Uygulama hassas verilerle yapıldıktan sonra çökme olursa, çökme dökümü hassas verileri içermemelidir.

4

Aşağıdaki metin HP Fortify statik kod çözümleyicisinden kopyalandı

Özet: PassGenerator.cs dosyasındaki PassString () yöntemi, hassas verileri güvensiz bir şekilde (örn. Dizede) saklayarak, yığını inceleyerek verileri ayıklamayı mümkün kılar.

Açıklama: Bellekte saklanan hassas veriler (şifreler, sosyal güvenlik numaraları, kredi kartı numaraları vb.) Yönetilen bir String nesnesinde saklanırsa sızdırabilir. Dize nesneleri sabitlenmediği için, çöp toplayıcı bu nesneleri istediği gibi değiştirebilir ve birkaç kopyasını bellekte bırakabilir. Bu nesneler varsayılan olarak şifrelenmez, bu nedenle işlemin belleğini okuyabilen herkes içeriği görebilir. Ayrıca, işlemin belleği diske değiştirilirse, dizenin şifrelenmemiş içeriği bir takas dosyasına yazılır. Son olarak, String nesneleri değiştirilemediğinden, bir String değerinin bellekten kaldırılması yalnızca CLR çöp toplayıcı tarafından yapılabilir. Çöp toplayıcının CLR'nin belleği az olmadığı sürece çalışması gerekmez, bu nedenle çöp toplamanın ne zaman yapılacağına dair bir garanti yoktur.

Öneriler: Hassas verileri Dizeler gibi nesnelerde saklamak yerine, bunları bir SecureString nesnesinde saklayın. Her nesne içeriğini her zaman şifrelenmiş bir biçimde bellekte saklar.


3

Bu noktaya değinmek istiyorum:

Bir saldırgan zaten yığın denetimi için araçlara sahipse, büyük olasılıkla (A) tuş vuruşlarını okuma araçlarına sahiptir veya (B) fiziksel olarak makineye sahiptir ... Bu nedenle SecureString, Yine de veri?

Saldırganın bilgisayara ve uygulamaya tam erişimi olmayabilir, ancak işlem belleğinin bazı bölümlerine erişmek için araçları olabilir. Genellikle, özel olarak oluşturulmuş girdi uygulamanın belleğin bir kısmını açığa çıkarmasına veya üzerine yazmasına neden olabileceği zaman arabellek taşması gibi hatalardan kaynaklanır.

HeartBleed sızıntı hafızası

Örneğin Heartbleed'i ele alalım. Özel olarak yapılandırılmış istekler, kodun işlem belleğinin rasgele bölümlerini saldırgana göstermesine neden olabilir. Saldırgan, SSL sertifikalarını bellekten çıkarabilir, ancak ihtiyacı olan tek şey sadece hatalı biçimlendirilmiş bir istek kullanmaktır.

Yönetilen kod dünyasında, arabellek taşmaları çok daha az sorun haline gelir. Ve WinForms durumunda, veriler zaten güvenli olmayan bir şekilde saklanır ve bu konuda hiçbir şey yapamazsınız. Bu, korumayı SecureStringneredeyse işe yaramaz hale getirir .

Ancak, GUI olabilir kullanım için programlanmış SecureStringve bu durumda değer bunu olabilir bellekte şifre kullanılabilirlik penceresini azaltılması. Örneğin, WPF'den PasswordBox.SecurePassword türündedir SecureString.


Hmm, bilmek kesinlikle ilginç. Dürüst olmak gerekirse, aslında bir Sistem elde etmek için gerekli saldırıların türü hakkında endişelenmiyorum. Ancak, bilgi için teşekkürler! :)
Steven Jeffries

2

Bir süre önce bir java kredi kartı ödeme ağ geçidine karşı ac # arayüzü oluşturmak zorunda kaldım ve uyumlu bir güvenli iletişim anahtarı şifrelemesi gerekiyordu. Java uygulaması oldukça spesifik olduğundan ve korunan verilerle belirli bir şekilde çalışmak zorunda kaldım.

Bu tasarımın SecureString ile çalışmaktan çok daha kolay ve daha kolay olduğunu gördüm… kullanmak isteyenler için… çekinmeyin, yasal kısıtlama yok :-). Bu sınıfların dahili olduğunu, onları herkese açık hale getirmeniz gerekebileceğini unutmayın.

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();
        }
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.