ProtectedData.Protect прерывистый сбой - PullRequest
2 голосов
/ 29 октября 2008

Я пишу процедуру шифрования пароля. Я написал приложение ниже, чтобы проиллюстрировать мою проблему. Примерно в 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;
            }
        }
    }
}

Ответы [ 6 ]

6 голосов
/ 29 октября 2008

По совету коллеги я выбрал 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;
            }
        }
    }
}
1 голос
/ 03 марта 2017

Этот класс должен помочь:

public static class StringEncryptor
{
    private static readonly byte[] key = { 0x45, 0x4E, 0x3A, 0x8C, 0x89, 0x70, 0x37, 0x99, 0x58, 0x31, 0x24, 0x98, 0x3A, 0x87, 0x9B, 0x34 };

    public static string EncryptString(this string sourceString)
    {
        if (string.IsNullOrEmpty(sourceString))
        {
            return string.Empty;
        }

        var base64String = Base64Encode(sourceString);
        var protectedBytes = ProtectedData.Protect(Convert.FromBase64String(base64String), key, DataProtectionScope.CurrentUser);
        return Convert.ToBase64String(protectedBytes);
    }

    public static string DecryptString(this string sourceString)
    {
        if (string.IsNullOrEmpty(sourceString))
        {
            return string.Empty;
        }

        var unprotectedBytes = ProtectedData.Unprotect(Convert.FromBase64String(sourceString), key, DataProtectionScope.CurrentUser);
        var base64String = Convert.ToBase64String(unprotectedBytes);
        return Base64Decode(base64String);
    }

    private static string Base64Encode(string plainText)
    {
        var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
        return Convert.ToBase64String(plainTextBytes);
    }

    private static string Base64Decode(string base64EncodedData)
    {
        var base64EncodedBytes = Convert.FromBase64String(base64EncodedData);
        return Encoding.UTF8.GetString(base64EncodedBytes);
    }
}
1 голос
/ 30 декабря 2011

Никогда не используйте ни один из классов System.Text.Encoding для шифрования текста. Вы будете испытывать периодические ошибки. Вы должны использовать кодировку Base64 и методы класса System.Convert.

  1. Чтобы получить зашифрованный string из зашифрованного byte[], вы должны использовать:

    Convert.ToBase64String(byte[] bytes)
    
  2. Чтобы получить необработанный byte[] из string для шифрования, вы должны использовать:

    Convert.FromBase64String(string data)
    

Дополнительную информацию см. В сообщении гуру безопасности MS Шона Фаннинга.

1 голос
/ 29 октября 2008

Проблема заключается в преобразовании в Unicode и в конце метода шифрования Encoding.Unicode.GetString работает только в том случае, если предоставленные вами байты образуют допустимую строку UTF-16.

Я подозреваю, что иногда результат ProtectedData.Protect не является допустимой строкой UTF-16 - поэтому Encoding.Unicode.GetString отбрасывает байты, которые не имеют смысла, из возвращаемой строки, в результате чего строка не может быть преобразована обратно в зашифрованные данные.

1 голос
/ 29 октября 2008

Лучшим решением является преобразование байтового массива в строку из 64 строк .

Вы также можете использовать Latin-1 или ISO-8859-1 или кодовую страницу 28591 для этого сценария, так как он отображает значения в диапазоне 0-255 без изменений. Следующие являются взаимозаменяемыми:

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

С помощью этой кодировки вы всегда сможете конвертировать byte [] -> string -> byte [] без потерь.

См. этот пост для примера, который иллюстрирует использование этой кодировки.

0 голосов
/ 29 октября 2008

Я сильно подозреваю, что это вызов Encoding.Unicode.GetString, который вызывает проблему. Необходимо убедиться, что данные, передаваемые вызову Unprotect, равны точно так же, как и данные, возвращенные вызовом Protect. Если вы кодируете двоичные данные как текст Unicode в качестве промежуточного шага, вы не можете гарантировать это. В любом случае, зачем вам этот шаг - почему бы просто не сохранить байт []?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...