2012-01-15 7 views
19

個人データを暗号化して保存する機能をユーザーに提供したいと考えています。これは簡単ではないかもしれないし、すでに尋ねられているかもしれませんが、私はパスワードを暗号化/復号化する使いやすい方法の例を見つけることができません。アプリケーションのユーザー設定(パスワードなど)を暗号化するにはどうすればよいですか?

私は本当に超魔法のような壊れないパスワードは必要ありません。パスワードを壊すのが難しいようにするだけです。

私はいくつかのmsdnとSOの質問を見てきましたが、使用するものが見つかりませんでした。

+0

関連の質問:(http://stackoverflow.com/questions/ [データベースやテキストファイルに、後でそれを保存するためのパスワードを暗号化するには?] 541219 /それを保存するためのパスワードを暗号化する方法 - データベース - または - テキストファイルの後に)。そして、たくさんの、より多くの:[[c#encrypt password 'を含む質問](http://stackoverflow.com/search?q=c%23+encrypt+password)。 –

+4

あなたが何をしても**パスワード*を解読しない**ことに注意してください。むしろ、2つのハッシュが一致していることを確認してください。 –

+1

@CodyGrayには、sql接続文字列にハッシュされたパスワードを送信する方法がありますか? – Odys

答えて

31

Davidを、私はyour answerは、気の利いたと思ったが、私はそれらを拡張メソッドとしてniftierだろうと思いました。それは、このような構文を可能にする:

using System; 
using System.Collections.Generic; 
using System.Runtime.InteropServices; 
using System.Security; 
using System.Security.Cryptography; 
using System.Text; 

public static class SecureIt 
{ 
    private static readonly byte[] entropy = Encoding.Unicode.GetBytes("Salt Is Not A Password"); 

    public static string EncryptString(this SecureString input) 
    { 
     if (input == null) 
     { 
      return null; 
     } 

     var encryptedData = ProtectedData.Protect(
      Encoding.Unicode.GetBytes(input.ToInsecureString()), 
      entropy, 
      DataProtectionScope.CurrentUser); 

     return Convert.ToBase64String(encryptedData); 
    } 

    public static SecureString DecryptString(this string encryptedData) 
    { 
     if (encryptedData == null) 
     { 
      return null; 
     } 

     try 
     { 
      var decryptedData = ProtectedData.Unprotect(
       Convert.FromBase64String(encryptedData), 
       entropy, 
       DataProtectionScope.CurrentUser); 

      return Encoding.Unicode.GetString(decryptedData).ToSecureString(); 
     } 
     catch 
     { 
      return new SecureString(); 
     } 
    } 

    public static SecureString ToSecureString(this IEnumerable<char> input) 
    { 
     if (input == null) 
     { 
      return null; 
     } 

     var secure = new SecureString(); 

     foreach (var c in input) 
     { 
      secure.AppendChar(c); 
     } 

     secure.MakeReadOnly(); 
     return secure; 
    } 

    public static string ToInsecureString(this SecureString input) 
    { 
     if (input == null) 
     { 
      return null; 
     } 

     var ptr = Marshal.SecureStringToBSTR(input); 

     try 
     { 
      return Marshal.PtrToStringBSTR(ptr); 
     } 
     finally 
     { 
      Marshal.ZeroFreeBSTR(ptr); 
     } 
    } 
} 
+0

すばらしい改善。実際のユーザーアカウントとパスワードを使ってテストを行っていた古い単体テストプロジェクトのコードをコピーしました。パスワードを安全に保存して、クリアテキストでパスワードを表示したり記録したりせずにテストを実行できるようにしたかったのです。 –

+0

下記の@DavidClarkeの回答を参照してください。関連する[msdn link](https://msdn.microsoft.com/en-us/library/system.security.securestring(v = vs.110) ).aspx) – Matt

16

以下は、実際に文字列を暗号化/復号化してディスクに格納したいと思っていることを前提にしています。これはパスワードを使用しないことに注意してください。ログインしたユーザーのセキュリティコンテキストを使用してSystem.Security.Cryptography.DataProtectionScope.CurrentUserデータを保護します。

public class SecureIt 
{ 
    static byte[] entropy = System.Text.Encoding.Unicode.GetBytes("Salt Is Not A Password"); 

    public static string EncryptString(System.Security.SecureString input) 
    { 
     byte[] encryptedData = System.Security.Cryptography.ProtectedData.Protect(
      System.Text.Encoding.Unicode.GetBytes(ToInsecureString(input)), 
      entropy, 
      System.Security.Cryptography.DataProtectionScope.CurrentUser); 
     return Convert.ToBase64String(encryptedData); 
    } 

    public static SecureString DecryptString(string encryptedData) 
    { 
     try 
     { 
      byte[] decryptedData = System.Security.Cryptography.ProtectedData.Unprotect(
       Convert.FromBase64String(encryptedData), 
       entropy, 
       System.Security.Cryptography.DataProtectionScope.CurrentUser); 
      return ToSecureString(System.Text.Encoding.Unicode.GetString(decryptedData)); 
     } 
     catch 
     { 
      return new SecureString(); 
     } 
    } 

    public static SecureString ToSecureString(string input) 
    { 
     SecureString secure = new SecureString(); 
     foreach (char c in input) 
     { 
      secure.AppendChar(c); 
     } 
     secure.MakeReadOnly(); 
     return secure; 
    } 

    public static string ToInsecureString(SecureString input) 
    { 
     string returnValue = string.Empty; 
     IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(input); 
     try 
     { 
      returnValue = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr); 
     } 
     finally 
     { 
      System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr); 
     } 
     return returnValue; 
    } 

} 

は、次に文字列を暗号化する:

var clearText = "Some string to encrypt"; 
    var cypherText = SecureIt.EncryptString(SecureIt.ToSecureString(clearText)); 

をし、その後復号化するために:

var clearText = SecureIt.ToInsecureString(SecureIt.DecryptString(cypherText)); 
+2

安全な文字列を解読する場合、安全な文字列を使用する必要はありません。全体的な目的は、完全なストリングを単一のメモリブロックから守ることです。文字列を受け取り、それを暗号化しただけの場合よりも、このメソッドを使うほうが良いでしょう。 '機密データがすでにメモリの永続性の影響を受けているため、SecureStringオブジェクトを文字列から構築しないでください。不変のStringクラス。 SecureStringオブジェクトを構築する最善の方法は、コンソールなどの管理されていない一意のソースからのものです。ReadKeyメソッド。 – Matt

+0

それは良い点です。私はすべてのメソッドが同じアプリケーションで使われるべきであると示唆していません。私は別のコンソールアプリケーションを使用して文字列をキャプチャし、ユニットテストプロジェクトの設定に安全に保存する前にそれを暗号化していました。その意図は、それが使用されている状況に十分なセキュリティを提供することでした。 –

1

私は私がメモリを保護することが重要ではありませんようSecureStringを使用しないようにJesse C. Slicerソリューションを修正私の目的のために:

string cypherText; 
string clearText; 

using (var secureString = "Some string to encrypt".ToSecureString()) 
{ 
    cypherText = secureString.EncryptString(); 
} 

using (var secureString = cypherText.DecryptString()) 
{ 
    clearText = secureString.ToInsecureString(); 
} 

ここで更新されたコードです。私は暗号化された文字列をシリアル化する必要があります。この作業プロジェクトを作成するには、System.Securityへの参照が必要です(ステートメントの使用だけでなく)。

public static class StringSecurityHelper 
{ 
    private static readonly byte[] entropy = Encoding.Unicode.GetBytes("5ID'&mc %[email protected]%n!G^ fiVn8 *tNh3eB %rDaVijn!.c b"); 

    public static string EncryptString(this string input) 
    { 
     if (input == null) 
     { 
      return null; 
     } 

     byte[] encryptedData = ProtectedData.Protect(Encoding.Unicode.GetBytes(input), entropy, DataProtectionScope.CurrentUser); 

     return Convert.ToBase64String(encryptedData); 
    } 

    public static string DecryptString(this string encryptedData) 
    { 
     if (encryptedData == null) 
     { 
      return null; 
     } 

     try 
     { 
      byte[] decryptedData = ProtectedData.Unprotect(Convert.FromBase64String(encryptedData), entropy, DataProtectionScope.CurrentUser); 

      return Encoding.Unicode.GetString(decryptedData); 
     } 
     catch 
     { 
      return null; 
     } 
    } 
} 

そして、それを使用する:

string cypherText = "My string".EncryptString(); 
string clearText = cypherText.DecryptString(); 
関連する問題