63

現在、クリア テキストで書いています、社内プログラムなので悪くはないのですが、ちゃんとやりたいです。レジストリへの書き込み時にこれを暗号化するにはどうすればよいですか? また、暗号化を解除するにはどうすればよいですか?

OurKey.SetValue("Password", textBoxPassword.Text);
4

12 に答える 12

137

認証パスワードを復号化しません。

SHA256 プロバイダーなどを使用してそれらをハッシュし、チャレンジする必要がある場合は、ユーザーからの入力をハッシュして、2 つのハッシュが一致するかどうかを確認します。

byte[] data = System.Text.Encoding.ASCII.GetBytes(inputString);
data = new System.Security.Cryptography.SHA256Managed().ComputeHash(data);
String hash = System.Text.Encoding.ASCII.GetString(data);

パスワードを可逆のままにしておくのは、本当に恐ろしいモデルです。

Edit2: 最前線の認証について話しているだけだと思っていました。確かに、元に戻す必要がある他のもののためにパスワードを暗号化したい場合がありますが、その上に一方向ロックが必要です (ごくわずかな例外を除いて)。

ハッシュ アルゴリズムをアップグレードしましたが、最大限の強度を得るために、プライベート ソルトを保持し、それをハッシュする前に入力に追加することをお勧めします。比較するときは、これをもう一度行います。これにより、別のレイヤーが追加され、誰かが元に戻すのがさらに難しくなります.

于 2008-10-17T15:00:18.303 に答える
25

ハッシュを「塩漬け」することも検討してください(料理の概念ではありません!)。基本的に、これはパスワードをハッシュする前にランダムなテキストをパスワードに追加することを意味します。

"ソルト値は、資格情報ストアが危険にさらされた場合に攻撃者が辞書攻撃を実行するのを遅らせるのに役立ち、侵害を検出して対応するための追加の時間を提供します。 "

パスワード ハッシュを保存するには:

a) ランダムなソルト値を生成します:

byte[] salt = new byte[32];
System.Security.Cryptography.RNGCryptoServiceProvider.Create().GetBytes(salt);

b) パスワードにソルトを追加します。

// Convert the plain string pwd into bytes
byte[] plainTextBytes = System.Text UnicodeEncoding.Unicode.GetBytes(plainText);
// Append salt to pwd before hashing
byte[] combinedBytes = new byte[plainTextBytes.Length + salt.Length];
System.Buffer.BlockCopy(plainTextBytes, 0, combinedBytes, 0, plainTextBytes.Length);
System.Buffer.BlockCopy(salt, 0, combinedBytes, plainTextBytes.Length, salt.Length);

c) 組み合わせたパスワードとソルトをハッシュします。

// Create hash for the pwd+salt
System.Security.Cryptography.HashAlgorithm hashAlgo = new System.Security.Cryptography.SHA256Managed();
byte[] hash = hashAlgo.ComputeHash(combinedBytes);

d) 結果のハッシュにソルトを追加します。

// Append the salt to the hash
byte[] hashPlusSalt = new byte[hash.Length + salt.Length];
System.Buffer.BlockCopy(hash, 0, hashPlusSalt, 0, hash.Length);
System.Buffer.BlockCopy(salt, 0, hashPlusSalt, hash.Length, salt.Length);

e) 結果をユーザー ストア データベースに保存します。

このアプローチは、ソルトを個別に保存してから、ソルト値とユーザーから取得したプレーンテキストのパスワード値を使用してハッシュを再計算する必要がないことを意味します。

編集: 生のコンピューティング パワーが安価で高速になるにつれて、ハッシュ (ソルティング ハッシュ) の価値は低下しています。Jeff Atwood は 2012 年の優れたアップデートを提供しており、長すぎてここですべてを繰り返すことはできません。

これ (salted ハッシュを使用) は、実際のセキュリティよりもセキュリティの錯覚を提供します。ハッシュを生成し、ハッシュをチェックするには、salt とハッシュ アルゴリズムの選択の両方が必要なので、攻撃者が一方を持っていて他方を持っていない可能性は低いです。攻撃者があなたのパスワード データベースを入手するところまで侵害された場合、攻撃者があなたの秘密の隠しソルトを持っているか、入手できると考えるのが妥当です。

セキュリティの第一のルールは、常に最悪の事態を想定して計画することです。ソルト、理想的には各ユーザーにランダムなソルトを使用する必要がありますか? 確かに、これは間違いなく良い習慣であり、少なくとも、同じパスワードを持つ 2 人のユーザーを明確にすることができます。しかし最近では、ソルトだけではビデオ カード ハードウェアに数千ドルを費やす人からあなたを救うことはできなくなりました。

于 2008-10-17T15:13:10.087 に答える
12

これはあなたがしたいことです:

OurKey.SetValue("Password", StringEncryptor.EncryptString(textBoxPassword.Text));
OurKey.GetValue("Password", StringEncryptor.DecryptString(textBoxPassword.Text));

これを使用して、次のクラスを実行できます。このクラスはジェネリック クラスであり、クライアント エンドポイントです。Ninjectを使用して、さまざまな暗号化アルゴリズムの IOC を有効にします。

public class StringEncryptor
{
    private static IKernel _kernel;

    static StringEncryptor()
    {
        _kernel = new StandardKernel(new EncryptionModule());
    }

    public static string EncryptString(string plainText)
    {
        return _kernel.Get<IStringEncryptor>().EncryptString(plainText);
    }

    public static string DecryptString(string encryptedText)
    {
        return _kernel.Get<IStringEncryptor>().DecryptString(encryptedText);
    }
}

この次のクラスは、さまざまなアルゴリズムを注入できる ninject クラスです。

public class EncryptionModule : StandardModule
{
    public override void Load()
    {
        Bind<IStringEncryptor>().To<TripleDESStringEncryptor>();
    }
}

これは、文字列を暗号化/復号化するためにアルゴリズムを実装する必要があるインターフェイスです。

public interface IStringEncryptor
{
    string EncryptString(string plainText);
    string DecryptString(string encryptedText);
}

これは、TripleDES アルゴリズムを使用した実装です。

public class TripleDESStringEncryptor : IStringEncryptor
{
    private byte[] _key;
    private byte[] _iv;
    private TripleDESCryptoServiceProvider _provider;

    public TripleDESStringEncryptor()
    {
        _key = System.Text.ASCIIEncoding.ASCII.GetBytes("GSYAHAGCBDUUADIADKOPAAAW");
        _iv = System.Text.ASCIIEncoding.ASCII.GetBytes("USAZBGAW");
        _provider = new TripleDESCryptoServiceProvider();
    }

    #region IStringEncryptor Members

    public string EncryptString(string plainText)
    {
        return Transform(plainText, _provider.CreateEncryptor(_key, _iv));
    }

    public string DecryptString(string encryptedText)
    {
        return Transform(encryptedText, _provider.CreateDecryptor(_key, _iv));
    }

    #endregion

    private string Transform(string text, ICryptoTransform transform)
    {
        if (text == null)
        {
            return null;
        }
        using (MemoryStream stream = new MemoryStream())
        {
            using (CryptoStream cryptoStream = new CryptoStream(stream, transform, CryptoStreamMode.Write))
            {
                byte[] input = Encoding.Default.GetBytes(text);
                cryptoStream.Write(input, 0, input.Length);
                cryptoStream.FlushFinalBlock();

                return Encoding.Default.GetString(stream.ToArray());
            }
        }
    }
}

私のビデオを見て、このコードをダウンロードできます: http://www.wrightin.gs/2008/11/how-to-encryptdecrypt-sensitive-column-contents-in-nhibernateactive-record-video.html

于 2008-11-07T14:31:40.667 に答える
10

1 つのオプションは、クリアテキスト パスワードの代わりにパスワードのハッシュ (SHA1、MD5) を保存することです。パスワードが適切かどうかを確認したい場合は、そのハッシュと比較するだけです。

安全なストレージが必要な場合 (サービスへの接続に使用するパスワードなど)、問題はさらに複雑になります。

認証のみの場合は、ハッシュを使用するだけで十分です。

于 2008-10-17T14:59:43.467 に答える
9

パスワードを解読できるようにしたい場合は、DPAPI (ユーザー ストア モード) を使用して暗号化/解読するのが最も簡単な方法だと思います。この方法では、暗号化キーをいじったり、どこかに保存したり、コードにハードコーディングしたりする必要はありません。どちらの場合も、誰かがレジストリ、ユーザー設定を調べたり、Reflector を使用したりすることでそれらを発見できます。

それ以外の場合は、他の人がここで言ったように、ハッシュ SHA1 または MD5 を使用します。

于 2008-10-17T15:02:23.353 に答える
6

ligget78 が言ったように、DPAPI はパスワードを保存するための良い方法です。使用例については、MSDN の ProtectedData クラスを確認してください

于 2009-03-23T17:04:57.070 に答える
6

暗号化と復号化のプロセスの良い例を隅々まで調べましたが、ほとんどが過度に複雑でした。

とにかく、誰かがパスワードを含むいくつかのテキスト値を解読したいと思うかもしれない多くの理由があります. 私が現在取り組んでいるサイトでパスワードを解読する必要があるのは、パスワードの有効期限が切れたときに誰かがパスワードの変更を強制されたときに、同じパスワードの類似した変種でパスワードを変更させないようにしたいからです。彼らは過去 x か月に使用しました。

そこで、これを簡単な方法で行うプロセスを作成しました。このコードが誰かにとって有益であることを願っています。私が知っている限りでは、別の会社/サイトでこれを別の時間に使用することになるかもしれません.

public string GenerateAPassKey(string passphrase)
    {
        // Pass Phrase can be any string
        string passPhrase = passphrase;
        // Salt Value can be any string(for simplicity use the same value as used for the pass phrase)
        string saltValue = passphrase;
        // Hash Algorithm can be "SHA1 or MD5"
        string hashAlgorithm = "SHA1";
        // Password Iterations can be any number
        int passwordIterations = 2;
        // Key Size can be 128,192 or 256
        int keySize = 256;
        // Convert Salt passphrase string to a Byte Array
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
        // Using System.Security.Cryptography.PasswordDeriveBytes to create the Key
        PasswordDeriveBytes pdb = new PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations);
        //When creating a Key Byte array from the base64 string the Key must have 32 dimensions.
        byte[] Key = pdb.GetBytes(keySize / 11);
        String KeyString = Convert.ToBase64String(Key);

        return KeyString;
    }

 //Save the keystring some place like your database and use it to decrypt and encrypt
//any text string or text file etc. Make sure you dont lose it though.

 private static string Encrypt(string plainStr, string KeyString)        
    {            
        RijndaelManaged aesEncryption = new RijndaelManaged();
        aesEncryption.KeySize = 256;
        aesEncryption.BlockSize = 128;
        aesEncryption.Mode = CipherMode.ECB;
        aesEncryption.Padding = PaddingMode.ISO10126;
        byte[] KeyInBytes = Encoding.UTF8.GetBytes(KeyString);
        aesEncryption.Key = KeyInBytes;
        byte[] plainText = ASCIIEncoding.UTF8.GetBytes(plainStr);
        ICryptoTransform crypto = aesEncryption.CreateEncryptor();
        byte[] cipherText = crypto.TransformFinalBlock(plainText, 0, plainText.Length);
        return Convert.ToBase64String(cipherText);
    }

 private static string Decrypt(string encryptedText, string KeyString) 
    {
        RijndaelManaged aesEncryption = new RijndaelManaged(); 
        aesEncryption.KeySize = 256;
        aesEncryption.BlockSize = 128; 
        aesEncryption.Mode = CipherMode.ECB;
        aesEncryption.Padding = PaddingMode.ISO10126;
        byte[] KeyInBytes = Encoding.UTF8.GetBytes(KeyString);
        aesEncryption.Key = KeyInBytes;
        ICryptoTransform decrypto = aesEncryption.CreateDecryptor(); 
        byte[] encryptedBytes = Convert.FromBase64CharArray(encryptedText.ToCharArray(), 0, encryptedText.Length); 
        return ASCIIEncoding.UTF8.GetString(decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length)); 
    }

 String KeyString = GenerateAPassKey("PassKey");
 String EncryptedPassword = Encrypt("25Characterlengthpassword!", KeyString);
 String DecryptedPassword = Decrypt(EncryptedPassword, KeyString);
于 2011-05-27T20:20:15.873 に答える
5

それがアプリケーションによる認証に使用されるパスワードである場合は、他の人が提案するようにパスワードをハッシュしてください。

外部リソースのパスワードを保存している場合、多くの場合、ユーザーにこれらの資格情報の入力を求め、パスワードを安全に保存する機会を与えたいと思うでしょう。Windows では、この目的のために Credentials UI (CredUI) が提供されています。これを .NET で使用する方法を示すサンプルが多数あり、MSDNのサンプルも含まれています。

于 2008-10-17T17:21:49.330 に答える
1

..NET は、System.Security.Cryptography 名前空間に含まれるクラスで暗号化サービスを提供します。

于 2008-10-17T15:02:36.520 に答える
1

接続文字列 (データベースへの接続用) を保護するなど、これ以上のことが必要な場合は、この記事を確認してください。

文字列のハッシュを作成する方法を示しているため、Oli の回答も適切です。

于 2008-10-17T15:06:47.323 に答える
-1

暗号化/復号化するのではなく、ハッシュ アルゴリズム、md5/sha512、または同様の方法でパスワードを渡す必要があります。理想的には、パスワードをハッシュしてハッシュを保存し、パスワードが必要なときにエントリをハッシュしてエントリを比較します。パスワードは決して「復号化」されず、単純にハッシュされてから比較されます。

于 2008-10-17T15:01:09.690 に答える