我想AES/CBC/Nopadding
在c#Windows Phone 8应用程序中解密加密Sting .我的字符串在IsolatedSorage
.我粘贴了垃圾桶HERE.
从这篇文章我使用AesManaged类来解密.但是如何设置填充,NoPadding
因为默认情况下填充设置为PKCS7
从这里开始.
string fileName = "titlepage.xhtml"; if (fileStorage.FileExists(fileName)) { IsolatedStorageFileStream someStream = fileStorage.OpenFile(fileName, System.IO.FileMode.Open, FileAccess.Read); using (StreamReader reader = new StreamReader(someStream)) { str1 = reader.ReadToEnd(); MessageBox.Show(str1); try { string text = Decrypt(str1, "****************", "****************"); MessageBox.Show(text); } catch (CryptographicException cryptEx) { MessageBox.Show(cryptEx.Message, "Encryption Error", MessageBoxButton.OK); } catch (Exception ex) { MessageBox.Show(ex.Message, "General Error", MessageBoxButton.OK); } } } public string Decrypt(string dataToDecrypt, string password, string salt) { AesManaged aes = null; MemoryStream memoryStream = null; try { //Generate a Key based on a Password and HMACSHA1 pseudo-random number generator //Salt must be at least 8 bytes long //Use an iteration count of at least 1000 Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt), 10000); //Create AES algorithm aes = new AesManaged(); //Key derived from byte array with 32 pseudo-random key bytes aes.Key = rfc2898.GetBytes(32); //IV derived from byte array with 16 pseudo-random key bytes aes.IV = rfc2898.GetBytes(16); //Create Memory and Crypto Streams memoryStream = new MemoryStream(); CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Write); byte[] data = Convert.FromBase64String(dataToDecrypt); cryptoStream.Write(data, 0, data.Length); cryptoStream.FlushFinalBlock(); //Return Decrypted String byte[] decryptBytes = memoryStream.ToArray(); //Dispose if (cryptoStream != null) cryptoStream.Dispose(); //Retval return Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length); } finally { if (memoryStream != null) memoryStream.Dispose(); if (aes != null) aes.Clear(); } }
编辑1:
当我在最后一行解密我的加密字符串时
byte[] data = Convert.FromBase64String(dataToDecrypt);
转移Finally block
并获得例外The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters in decrypted string.
这有点混乱,这是在Windows Phone中支持Decrypt的类.
如果我完全错误,请向我建议关于Windows Phone中算法的文章
编辑2:
如下面的答案所示"我将cyperText作为字节获得,它在解密方面很好.但它给出了描述的例外
[Cryptography_SSD_InvalidDataSize] Arguments: Debugging resource strings are unavailable. Often the key and arguments provide sufficient information to diagnose the problem
我认为问题是IV [盐键]或设置填充到AesManged.但是我无法在Windows Phone 中将填充属性更改为AesManaged.默认情况下,填充到AesManged是PKCS7
.我想换到NoPadding
.因为我的cyperText使用AES/CBC/NoPadding算法加密"
如果我理解了这个问题,那么您的数据已经在AES CBC模式下加密,没有填充.但是在要解密数据的手机上,唯一的选择是PKCS#7填充.
好吧,你是幸运的!您可以使用PKCS#7填充来解密密文.您需要做的就是将填充添加到手机上的密文,然后解密.
要在事后添加填充,您将加密一小部分数据并将其附加到密文.然后,您解密修改后的密文,并关闭那一小段数据,并获得原始明文.
这是你如何做到的:
在手机上取一个密文.即使没有填充,这也是16个字节的倍数.没有其他可能性 - AES密文始终是16字节的倍数.
将密文的最后16个字节放在一边,并将其设置为AES ENCRYPT的IV.(加密,而不是解密.)使用您将要用于稍后解密的相同密钥.
现在加密小于16字节的内容,例如字符'$'.手机将为此添加PKCS#7填充.
将生成的16字节密文附加到步骤1中的原始密文,现在您有一个正确的PKCS#7填充密文,其中包括原始明文和添加的"$".
使用原来的IV,和相同的密钥,现在DECRYPT这个组合的密文.您现在可以删除将出现在明文末尾的"$"(或者您在步骤3中添加的任何内容).
当使用原始密文的最后16个字节对小位进行加密时,实际上是在真正的AES CBC模式下扩展密文,而您恰好使用PKCS#7填充进行加密,因此您现在可以解密整个密文并取消一点点.你将拥有没有填充的原始明文.
我认为在代码中展示会很有趣:
var rfc2898 = new Rfc2898DeriveBytes("password", new byte[8]); using (var aes = new AesManaged()) { aes.Key = rfc2898.GetBytes(32); aes.IV = rfc2898.GetBytes(16); var originalIV = aes.IV; // keep a copy // Prepare sample plaintext that has no padding aes.Padding = PaddingMode.None; var plaintext = Encoding.UTF8.GetBytes("this plaintext has 32 characters"); byte[] ciphertext; using (var encryptor = aes.CreateEncryptor()) { ciphertext = encryptor.TransformFinalBlock(plaintext, 0, plaintext.Length); Console.WriteLine("ciphertext: " + BitConverter.ToString(ciphertext)); } // From this point on we do everything with PKCS#7 padding aes.Padding = PaddingMode.PKCS7; // This won't decrypt -- wrong padding try { using (var decryptor = aes.CreateDecryptor()) { var oops = decryptor.TransformFinalBlock(ciphertext, 0, ciphertext.Length); } } catch (Exception e) { Console.WriteLine("caught: " + e.Message); } // Last block of ciphertext is used as IV to encrypt a little bit more var lastBlock = new byte[16]; var modifiedCiphertext = new byte[ciphertext.Length + 16]; Array.Copy(ciphertext, ciphertext.Length - 16, lastBlock, 0, 16); aes.IV = lastBlock; using (var encryptor = aes.CreateEncryptor()) { var dummy = Encoding.UTF8.GetBytes("$"); var padded = encryptor.TransformFinalBlock(dummy, 0, dummy.Length); // Set modifiedCiphertext = ciphertext + padded Array.Copy(ciphertext, modifiedCiphertext, ciphertext.Length); Array.Copy(padded, 0, modifiedCiphertext, ciphertext.Length, padded.Length); Console.WriteLine("modified ciphertext: " + BitConverter.ToString(modifiedCiphertext)); } // Put back the original IV, and now we can decrypt... aes.IV = originalIV; using (var decryptor = aes.CreateDecryptor()) { var recovered = decryptor.TransformFinalBlock(modifiedCiphertext, 0, modifiedCiphertext.Length); var str = Encoding.UTF8.GetString(recovered); Console.WriteLine(str); // Now you can remove the '$' from the end } }