2012-10-12 230 views
1

我正在使用以下代码来加密和解密asp.net中的密码。加密完美的作品,但解密时,它抛出这个错误Invalid length for a Base-64 char array.加密和解密密码

我的密码是123,我用它作为后续加密:HttpUtility.UrlEncode(CryptorEngine.Encrypt(strpassword, true)); ,我用它作为后续解密:

CryptorEngine.Decrypt(HttpUtility.UrlDecode(strpassword), true)); 

这里是代码:

public class CryptorEngine 
    { 
     /// <summary> 
     /// Encrypt a string using dual encryption method. Return a encrypted cipher Text 
     /// </summary> 
     /// <param name="toEncrypt">string to be encrypted</param> 
     /// <param name="useHashing">use hashing? send to for extra secirity</param> 
     /// <returns></returns> 
     public static string Encrypt(string toEncrypt, bool useHashing) 
     { 
      byte[] keyArray; 
      byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt); 

      System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader(); 
      // Get the key from config file 
      string key = (string)settingsReader.GetValue("SecurityKey", typeof(String)); 
      //System.Windows.Forms.MessageBox.Show(key); 
      if (useHashing) 
      { 
       MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider(); 
       keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key)); 
       hashmd5.Clear(); 
      } 
      else 
       keyArray = UTF8Encoding.UTF8.GetBytes(key); 

      TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider(); 
      tdes.Key = keyArray; 
      tdes.Mode = CipherMode.ECB; 
      tdes.Padding = PaddingMode.PKCS7; 

      ICryptoTransform cTransform = tdes.CreateEncryptor(); 
      byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); 
      tdes.Clear(); 
      return Convert.ToBase64String(resultArray, 0, resultArray.Length); 
     } 
     /// <summary> 
     /// DeCrypt a string using dual encryption method. Return a DeCrypted clear string 
     /// </summary> 
     /// <param name="cipherString">encrypted string</param> 
     /// <param name="useHashing">Did you use hashing to encrypt this data? pass true is yes</param> 
     /// <returns></returns> 
     public static string Decrypt(string cipherString, bool useHashing) 
     { 
      byte[] keyArray; 
      byte[] toEncryptArray = Convert.FromBase64String(cipherString); 

      System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader(); 
      //Get your key from config file to open the lock! 
      string key = (string)settingsReader.GetValue("SecurityKey", typeof(String)); 

      if (useHashing) 
      { 
       MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider(); 
       keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key)); 
       hashmd5.Clear(); 
      } 
      else 
       keyArray = UTF8Encoding.UTF8.GetBytes(key); 

      TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider(); 
      tdes.Key = keyArray; 
      tdes.Mode = CipherMode.ECB; 
      tdes.Padding = PaddingMode.PKCS7; 

      ICryptoTransform cTransform = tdes.CreateDecryptor(); 
      byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); 

      tdes.Clear(); 
      return UTF8Encoding.UTF8.GetString(resultArray); 
     } 
    } 
+4

您是否考虑过不解密密码,而是检查哈希匹配而不是解密密码以检查输入是否与加密密码匹配?正如索尼发现的,如果加密密码是可解密的,我认为它不是安全的。只是一个建议。 – LukeHennerley

+0

我叫你调试和检查进出各种函数的值?Base64编码的字符串与加密解密函数所传递的字符串相比如何? base64字符串应该是长度的四个字符的倍数... – Chris

+0

我的123加密密码是VCZaNZapEXY%3d,但无法在登录时看到它,当提供123作为密码时,它在此行上失败yte [] toEncryptArray = Convert.FromBase64String (cipherString); Decrpt方法 – Zaki

回答

2

在URL中有人物来与加密输出冲突,至少在我的代码,THI问题是什么造成的。所以我使用这两个函数来改变这些字符并避免这种情况。

public static string ChangeSPChart(string sTheInput) 
{ 
    StringBuilder sRetMe = new StringBuilder(sTheInput); 

    sRetMe.Replace('+', '-'); 
    sRetMe.Replace('/', '*'); 
    sRetMe.Replace('=', '!'); 

    return sRetMe.ToString(); 
} 

public static string FixSPChart(string sTheInput) 
{ 
    StringBuilder sRetMe = new StringBuilder(sTheInput); 

    sRetMe.Replace('-', '+'); 
    sRetMe.Replace('*', '/'); 
    sRetMe.Replace('!', '='); 

    return sRetMe.ToString(); 
} 

和加密/解密代码将是:

public static string Encrypt(string toEncrypt, bool useHashing) 
{ 
    byte[] keyArray; 
    byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt); 

    System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader(); 
    // Get the key from config file 
    string key = (string)settingsReader.GetValue("SecurityKey", typeof(String)); 
    //System.Windows.Forms.MessageBox.Show(key); 
    if (useHashing) 
    { 
     MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider(); 
     keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key)); 
     hashmd5.Clear(); 
    } 
    else 
     keyArray = UTF8Encoding.UTF8.GetBytes(key); 

    TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider(); 
    tdes.Key = keyArray; 
    tdes.Mode = CipherMode.ECB; 
    tdes.Padding = PaddingMode.PKCS7; 

    ICryptoTransform cTransform = tdes.CreateEncryptor(); 
    byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); 

    tdes.Clear(); 
    var encrypted = Convert.ToBase64String(resultArray, 0, resultArray.Length); 

    // here I change it 
    return ChangeSPChart(encrypted); 
} 
/// <summary> 
/// DeCrypt a string using dual encryption method. Return a DeCrypted clear string 
/// </summary> 
/// <param name="cipherString">encrypted string</param> 
/// <param name="useHashing">Did you use hashing to encrypt this data? pass true is yes</param> 
/// <returns></returns> 
public static string Decrypt(string cipherString, bool useHashing) 
{ 
    cipherString = FixSPChart(cipherString); 

    byte[] keyArray; 
    byte[] toEncryptArray = Convert.FromBase64String(cipherString); 

    System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader(); 
    //Get your key from config file to open the lock! 
    string key = (string)settingsReader.GetValue("SecurityKey", typeof(String)); 

    if (useHashing) 
    { 
     MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider(); 
     keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key)); 
     hashmd5.Clear(); 
    } 
    else 
     keyArray = UTF8Encoding.UTF8.GetBytes(key); 

    TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider(); 
    tdes.Key = keyArray; 
    tdes.Mode = CipherMode.ECB; 
    tdes.Padding = PaddingMode.PKCS7; 

    ICryptoTransform cTransform = tdes.CreateDecryptor(); 
    byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); 

    tdes.Clear(); 
    return UTF8Encoding.UTF8.GetString(resultArray); 
} 
+0

我试过你的方法,但我仍然得到相同的错误 – Zaki

+0

@ Sam1处理它一下,调试它找到并查看字符串是否中断。 – Aristos

+0

我是否需要使用HttpUtility.UrlDecode和HttpUtility.UrlEncode来包围我的密码 – Zaki

1

您提供的代码工作正常。我用这个小程序对它进行了测试:

void Main() 
{ 
    var cryptB64 =CryptorEngine.Encrypt("123", true); 
    var encoded = HttpUtility.UrlEncode(cryptB64); 
    var decoded = HttpUtility.UrlDecode(encoded); 
    var decrypted = CryptorEngine.Decrypt(decoded, true); 

    bool matches = (decrypted=="123"); 
    Console.WriteLine(matches); 
} 

并且它按预期返回了真值。

这个问题可能是你在某个时刻损坏了你的加密值。我猜想它是通过HTTP传输的,我猜想是问题发生的地方。

附加说明:

当调用CryptorEngine.Decrypt(HttpUtility.UrlDecode(strpassword), true));,那么你需要确保strpassword是密码的加密形式,不是你是比较反对的明文密码。

+0

当你把它放在url上,然后从url得到结果,如果它包含象'+','='这样的符号就是break。你的测试是工作的,因为你实际上并没有把它放在网址上。 – Aristos

+0

@Aristos:是的。完全正确。我的观点是,问题中的代码与问题无关,而且他看错了位置。你的回答解决了传输问题,我正在解决问题中的错误,并试图鼓励他自己学习如何调试这类问题(通过检查方法的进出情况)。 (对你来说+1,因为我认为你的技术可能是解决方案的关键)。 – Chris

+0

@Aristos:我真的回想起你解决问题的答案。 urlencoding应该已经处理您正在讨论的传输问题。 – Chris

1

HIII请使用此代码,这个工程很好

//加密方法进行信用卡

public string EncryptTripleDES(string Plaintext, string Key) 
{ 

    System.Security.Cryptography.TripleDESCryptoServiceProvider DES = 

    new System.Security.Cryptography.TripleDESCryptoServiceProvider(); 

    System.Security.Cryptography.MD5CryptoServiceProvider hashMD5 = 

    new System.Security.Cryptography.MD5CryptoServiceProvider(); 

    DES.Key = hashMD5.ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(Key)); 

    DES.Mode = System.Security.Cryptography.CipherMode.ECB; 

    System.Security.Cryptography.ICryptoTransform DESEncrypt = DES.CreateEncryptor(); 

    Buffer = System.Text.ASCIIEncoding.ASCII.GetBytes(Plaintext); 
    string TripleDES = Convert.ToBase64String(DESEncrypt.TransformFinalBlock(Buffer, 0, Buffer.Length)); 

    return TripleDES; 

} 
//Decryption Method 

public string DecryptTripleDES(string base64Text, string Key) 
{ 

    System.Security.Cryptography.TripleDESCryptoServiceProvider DES = 

    new System.Security.Cryptography.TripleDESCryptoServiceProvider(); 

    System.Security.Cryptography.MD5CryptoServiceProvider hashMD5 = 

    new System.Security.Cryptography.MD5CryptoServiceProvider(); 
    DES.Key = hashMD5.ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(Key)); 
    DES.Mode = System.Security.Cryptography.CipherMode.ECB; 
    System.Security.Cryptography.ICryptoTransform DESDecrypt = DES.CreateDecryptor(); 
    Buffer = Convert.FromBase64String(base64Text); 

    string DecTripleDES = System.Text.ASCIIEncoding.ASCII.GetString(DESDecrypt.TransformFinalBlock(Buffer, 0, Buffer.Length)); 
    return DecTripleDES; 

} 
+0

你有试过吗? –

0

晚了一点,但这里的问题可能是别的东西(这是对我来说)。

Request.Querystring已经做了一些解码。在我的情况下,我基本上解码两次。添加第二个“HttpUtility.UrlEncode”做了诀窍(至少在20次不同的测试之后)。

我还没有确切这种行为找到公司文档从微软,以及旧书被存放(我尽量不留下我的椅子),但这些联系是有益的:

does Request.Querystring automatically url decode a string?

http://forums.asp.net/t/1354726.aspx?Request+Querystring+without+decoding+possible+