Kum*_*mar 5 c# encryption aes visual-studio-2012 windows-phone-8
我想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();
}
}
Run Code Online (Sandbox Code Playgroud)
编辑1:
当我在最后一行解密我的加密字符串时
byte[] data = Convert.FromBase64String(dataToDecrypt);
Run Code Online (Sandbox Code Playgroud)
转移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
Run Code Online (Sandbox Code Playgroud)
我认为问题是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
}
}
Run Code Online (Sandbox Code Playgroud)
您链接到的字符串不是Base -64。它看起来好像是原始加密字节,被解释为字符。要么在加密端工作以输出原始字节的 Base-64 字符串编码,要么在解密端工作以将密文读取为原始字节,而不是文本,并且忘记删除 Base-64。
一般来说,在加密方面工作会更好,因为传递 Base-64 文本比传递原始字节更不容易出错。
| 归档时间: |
|
| 查看次数: |
2806 次 |
| 最近记录: |