2008-10-29 74 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的調用導致的問題。您需要確保傳遞給解除保護呼叫的數據是,確切地說與從保護呼叫返回的數據相同。如果您將二進制數據編碼爲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") 

使用此編碼,您將始終能夠無損地轉換byte [] - > string - > byte []。

請參閱this post瞭解說明使用此編碼的示例。

1

的問題是轉換爲Unicode和加密方法的結束,Encoding.Unicode.GetString只能如果你給它字節形成有效的UTF-16字符串。

我懷疑有時候ProtectedData.Protect的結果不是一個有效的UTF-16字符串 - 所以Encoding.Unicode.GetString會丟棄在返回的字符串中沒有意義的字節,從而導致無法轉換的字符串回到加密數據中。

1

您不應該使用任何System.Text.Encoding類作爲密文。您遇到間歇性錯誤。您應該使用Base64編碼和System.Convert類方法。

  1. 要獲得加密byte[]加密string,你應該使用:

    Convert.ToBase64String(byte[] bytes) 
    
  2. 要從string獲得AA原料byte[]進行加密,您應該使用:

    Convert.FromBase64String(string data) 
    

For additiona升信息,請參閱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); 
    } 
}