2008-10-29 2 views
2

암호 암호화 루틴을 쓰고 있습니다. 내 문제를 설명하기 위해 아래 응용 프로그램을 작성했습니다. 약 20 %의 시간 동안이 코드는 예상대로 작동합니다. 나머지 시간에는 암호 해독에서 암호 예외가 발생합니다. "데이터가 유효하지 않습니다."ProtectedData.Protect intermittent failure

해독 부분이 매번 동일하게 작동하기 때문에 문제가 암호화 부분에 있다고 생각합니다. 즉, 암호화 루틴이 해독 루틴이 해독 할 수있는 값을 산출하는 경우, 해독 루틴은 해독 루틴을 해독 할 수 있습니다. 그러나 암호화 루틴이 암호 해독 루틴을 중단시키는 값을 생성하는 경우, 항상 칙칙합니다. 따라서 해독 루틴은 일관성이 있습니다. 암호화 루틴은 그렇지 않습니다.

유니 코드 인코딩을 사용하는 것이 잘못된 것 같지만 동일한 결과를 얻은 다른 사람이 시도했습니다.

내가 뭘 잘못하고 있니?

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

이 코드는 여전히 버그가 있습니다 ... 내 대답은 아래 참조하십시오. –

+0

Base64 문자열로 변환하거나 Base64 문자열로 변환하는 동작이 내 문제를 해결했습니다. Previusly 유니 코드 문자열로 변환 중입니다. 정말 유용합니다. 감사 – rideintothesun

0

나는이 문제를 일으키는 Encoding.Unicode.GetString에 대한 호출이라고 강력히 의심합니다. 보호 해제 통화로 전달 된 데이터가 이고 정확히이고 보호 호출에서 반환 된 데이터인지 확인해야합니다. 중간 단계로 이진 데이터를 유니 코드 텍스트로 인코딩하는 경우이를 보장 할 수 없습니다. 어쨌든이 단계가 필요한 이유는 무엇입니까? 바이트 []를 저장하는 것이 어떨까요?

+0

나는 문자열로 다시 변환하고 있습니다. – Eric

0

가장 좋은 해결책은 convert the byte array to a base 64 string입니다.

이 시나리오에서는 0-255 범위의 값을 변경하지 않으므로 Latin-1 ISO-8859-1 일명 코드 페이지 28591을 사용할 수도 있습니다. 다음은 서로 바꿔 사용할 수 있습니다.

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

이 인코딩을 사용하면 항상 [] -> string -> byte []를 손실없이 변환 할 수 있습니다.

이 인코딩의 사용을 보여주는 샘플은 this post을 참조하십시오.

1

문제는 유니 코드로 변환 및 암호화 방법의 끝, Encoding.Unicode.GetString 당신이 그것을 줄 바이트가 유효한 UTF-16 문자열을 형성 할 경우에만 작동합니다.

때때로 ProtectedData.Protect의 결과가 유효한 UTF-16 문자열이 아닌 것으로 의심됩니다. Encoding.Unicode.GetString은 변환 할 수없는 문자열로 인해 반환 된 문자열에서 의미가없는 바이트를 삭제합니다. 다시 암호화 된 데이터로.

1

암호문에는 System.Text.Encoding 클래스를 사용하지 마십시오. 에 간헐적 인 오류가 발생합니다. Base64 인코딩과 System.Convert 클래스 메서드를 사용해야합니다.암호화 된 byte[]에서 암호화 된 string을 얻으려면

  1. , 당신은 사용해야합니다

    Convert.ToBase64String(byte[] bytes) 
    
  2. string에서 AA 원시 byte[]을 얻으려면 암호화 할, 당신은 사용해야합니다

    Convert.FromBase64String(string data) 
    

알타미 리터 정보는,이 클래스가 도움이 MS Security guru Shawn Fanning's post.

0

를 참조하십시오 : 나는 VARCHAR와 같은 데이터베이스에 저장해야하기 때문에

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); 
    } 
} 
관련 문제