2008-10-29 6 views
2

Я пишу процедуру шифрования паролей. Я написал приложение ниже, чтобы проиллюстрировать мою проблему. Примерно в 20% случаев этот код работает так, как ожидалось. В остальное время дешифрование генерирует криптографическое исключение - «Данные недействительны».ProtectedData.Protect прерывистый сбой

Я считаю, что проблема заключается в части шифрования, поскольку часть дешифрования работает одинаково каждый раз. То есть, если подпрограмма шифрования дает значение, которое может расшифровать подпрограмма расшифровки, оно всегда может расшифровать его. Но если подпрограмма шифрования дает значение, которое зажимает процедуру дешифрования, оно всегда задыхается. Таким образом, процедура дешифрования является последовательной; подпрограмма шифрования - нет.

Я подозреваю, что использование кодировки 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; 
      } 
     } 
    } 
} 

ответ

5

По совету коллеги я выбрал 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; 
      } 
     } 
    } 
} 
+0

Этот код по-прежнему содержит ошибку ... см. Мой ответ ниже. – 2011-12-30 19:10:27

0

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

+0

Я преобразования обратно в строку, потому что нужно хранить в базе данных, как VARCHAR. – Eric 2008-10-29 14:04:05

0

Лучшее решение для convert the byte array to a base 64 string.

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

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

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

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

1

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

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

1

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

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

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

    Convert.FromBase64String(string data) 
    

Для дополнительной информации л информация, пожалуйста, обратитесь к MS Security guru Shawn Fanning's post.

0

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^