4

パスワード暗号化ルーチンを書いています。私の問題を説明するために、以下のアプリを作成しました。約 20% の確率で、このコードは期待どおりに機能します。それ以外の場合、復号化は暗号化例外をスローします - 「データが無効です」。

復号化部分は毎回同じように機能するため、問題は暗号化部分にあると思います。つまり、暗号化ルーチンが、復号化ルーチンが復号化できる値を生成する場合、常にそれを復号化できます。しかし、暗号化ルーチンが復号化ルーチンをチョークする値を生成する場合、常にチョークします。したがって、復号化ルーチンは一貫しています。暗号化ルーチンはそうではありません。

Unicode エンコーディングの使用が間違っていると思われますが、他のものを試しても同じ結果が得られました。

私は何を間違っていますか?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Security.Cryptography;

namespace DataProtectionTest
{
    public partial class Form1 : Form
    {
        private static readonly byte[] entropy = { 1, 2, 3, 4, 1, 2, 3, 4 };
        private string password;
        public Form1()
        {
            InitializeComponent();
        }

        private void btnEncryptIt_Click(object sender, EventArgs e)
        {
            Byte[] pw = Encoding.Unicode.GetBytes(textBox1.Text);
            Byte[] encryptedPw = ProtectedData.Protect(pw, entropy, DataProtectionScope.LocalMachine);
            password = Encoding.Unicode.GetString(encryptedPw);     
        }

        private void btnDecryptIt_Click(object sender, EventArgs e)
        {
            Byte[] pwBytes = Encoding.Unicode.GetBytes(password);
            try
            {
                Byte[] decryptedPw = ProtectedData.Unprotect(pwBytes, entropy, DataProtectionScope.LocalMachine);
                string pw = Encoding.Unicode.GetString(decryptedPw);
                textBox2.Text = pw;
            }
            catch (CryptographicException ce)
            {
                textBox2.Text = ce.Message;
            }
        }
    }
}
4

6 に答える 6

9

同僚のアドバイスで、Convert.ToBase64String を選びました。うまくいきます。以下のプログラムを修正しました。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Security.Cryptography;

namespace DataProtectionTest
{
    public partial class Form1 : Form
    {
        private static readonly byte[] entropy = { 1, 2, 3, 4, 1, 2, 3, 4 };
        private string password;
        public Form1()
        {
            InitializeComponent();
        }

        private void btnEncryptIt_Click(object sender, EventArgs e)
        {
            Byte[] pw = Encoding.Unicode.GetBytes(textBox1.Text);
            Byte[] encryptedPw = ProtectedData.Protect(pw, entropy, DataProtectionScope.LocalMachine);
            //password = Encoding.Unicode.GetString(encryptedPw);       
            password = Convert.ToBase64String(encryptedPw);
        }

        private void btnDecryptIt_Click(object sender, EventArgs e)
        {
            //Byte[] pwBytes = Encoding.Unicode.GetBytes(password);
            Byte[] pwBytes = Convert.FromBase64String(password);
            try
            {
                Byte[] decryptedPw = ProtectedData.Unprotect(pwBytes, entropy, DataProtectionScope.LocalMachine);
                string pw = Encoding.Unicode.GetString(decryptedPw);
                textBox2.Text = pw;
            }
            catch (CryptographicException ce)
            {
                textBox2.Text = ce.Message;
            }
        }
    }
}
于 2008-10-29T14:45:38.570 に答える
2

System.Text.Encoding暗号文にクラスを使用しないでください。断続的なエラーが発生します。Base64エンコーディングとSystem.Convertクラスメソッドを使用する必要があります。

  1. string暗号化されたものから暗号化されたものを取得するbyte[]には、次を使用する必要があります。

    Convert.ToBase64String(byte[] bytes)
    
  2. byte[]暗号化するaからarawを取得stringするには、次を使用する必要があります。

    Convert.FromBase64String(string data)
    

詳細については、MSセキュリティの第一人者であるShawnFanningの投稿を参照してください。

于 2011-12-30T18:29:53.850 に答える
1

問題は、Unicode への変換と、暗号化メソッドの終わりである Encoding.Unicode.GetString は、指定したバイトが有効な UTF-16 文字列を形成する場合にのみ機能します。

ProtectedData.Protect の結果が有効な UTF-16 文字列ではない場合があると思われます。そのため、Encoding.Unicode.GetString は、返された文字列から意味をなさないバイトを削除し、暗号化された文字列に変換できない文字列になります。データ。

于 2008-10-29T15:13:36.097 に答える
1

最善の解決策は、バイト配列を base 64 文字列に変換することです。

このシナリオでは、Latin-1 別名 ISO-8859-1 別名コードページ 28591 を使用することもできます。これは、0 ~ 255 の範囲の値を変更せずにマップするためです。以下は交換可能です。

Encoding.GetEncoding(28591)
Encoding.GetEncoding("Latin1")
Encoding.GetEncoding("iso-8859-1")

このエンコーディングを使用すると、いつでも byte[] -> string -> byte[] を損失なく変換できます。

このエンコーディングの使用法を示すサンプルについては、この投稿を参照してください。

于 2008-10-29T14:31:30.143 に答える
0

問題を引き起こしているのは Encoding.Unicode.GetString の呼び出しであると強く疑っています。Unprotect 呼び出しに渡されるデータが、Protect 呼び出しから返されるデータとまったく同じであることを確認する必要があります。中間ステップとしてバイナリ データを Unicode テキストとしてエンコードしている場合は、これを保証できません。とにかく、なぜこのステップが必要なのですか? byte[] を保存しないのはなぜですか?

于 2008-10-29T13:56:09.747 に答える