在将数据从 iPad 应用程序发送到 WCF 网络服务之前,我使用以下(精简版)类来加密一些数据。
public class FlawedAlgorithm
{
protected static byte[] key = { 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
protected static byte[] vector = { 13, 37, 13, 37, 13, 37, 13, 37, 13, 37, 13, 37, 13, 37, 13, 37 };
protected ICryptoTransform encryptor, decryptor;
protected UTF8Encoding encoder;
public FlawedAlgorithm()
{
using (var rijndael = new RijndaelManaged())
{
this.encryptor = rijndael.CreateEncryptor(key, vector);
this.decryptor = rijndael.CreateDecryptor(key, vector);
}
this.encoder = new UTF8Encoding();
}
public string Encrypt(string unencrypted)
{
var buffer = this.encoder.GetBytes(unencrypted);
return Convert.ToBase64String(Encrypt(buffer));
}
public string Decrypt(string encrypted)
{
var buffer = Convert.FromBase64String(encrypted);
return this.encoder.GetString(Decrypt(buffer));
}
private byte[] Encrypt(byte[] buffer)
{
var encryptStream = new MemoryStream();
using (var cryptoStream = new CryptoStream(encryptStream, this.encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(buffer, 0, buffer.Length);
}
return encryptStream.ToArray();
}
private byte[] Decrypt(byte[] buffer)
{
var decryptStream = new MemoryStream();
using (var cryptoStream = new CryptoStream(decryptStream, this.decryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(buffer, 0, buffer.Length);
}
return decryptStream.ToArray();
}
}
当我在服务器和 iPad 上运行以下代码时,两者都打印出相同的加密字符串。
var algorithm = new FlawedAlgorithm();
Console.WriteLine(algorithm.Encrypt("Some string"));
但是,当我尝试加密第二个值时,服务器和 iPad 上的结果不同。
var algorithm = new FlawedAlgorithm();
// The first encryption still functions correctly.
Console.WriteLine(algorithm.Encrypt("Some string"));
// This second encryption produces a different value on the iPad.
Console.WriteLine(algorithm.Encrypt("This text is a bit longer"));
当我在服务器上解密有偏差的 iPad 结果时,部分解密字符串是乱码。服务器的加密结果正确解密。
如果我为每次调用创建一个新的 FlawedAlgorithm
实例,问题不会自行显现,例如:
// These statements produce the correct results on the iPad.
Console.WriteLine(new FlawedAlgorithm().Encrypt("Some string"));
Console.WriteLine(new FlawedAlgorithm().Encrypt("This text is a bit longer"));
这让我认为问题出在所涉及对象的状态中。我检查了 Encrypt(string)
方法中的 buffer
变量,UTF8Encoding
实例生成的值是正确的。这意味着 encryptor
字段(或其底层实现)是罪魁祸首。
当我开始改变第一个加密值的大小时,我可以看到第二个加密调用结果的变化。这可能意味着流的某些部分没有被正确清除或覆盖。但是 FlawedAlgorithm
类使用的流不是其状态的一部分;它们在每次方法调用时重新创建。而且 encryptor
对象看起来不像是管理自己的流的类型。
有没有人遇到过类似的问题? RijndaelManaged
类是否存在缺陷?还是 MonoTouch 中存在一些与此密码学示例无关的流和内存管理陷阱?
P.S.:我已经在 iPad 和 iPad Simulator 上测试过了;两者都表现出这种奇怪的行为。
最佳答案
使用 .NET 加密时,您必须始终检查 ICryptoTransform.CanReuseTransform(或假设它将返回 false)。如果它返回 false,则您不能重复使用相同的加密器/解密器,必须创建新实例。
跳过此检查意味着框架中的任何更改(或通过配置文件,因为密码学是可插入的)将来可能会破坏您的应用程序。
你可以使用类似的东西:
ICryptoTransform Decryptor {
get {
if (decryptor == null || !decryptor.CanReuseTransform)
decryptor = rijndael.CreateDecryptor (key, vector);
return decryptor;
}
}
向您的加密例程的调用者隐藏这种复杂性。
关于c# - 为什么我不能在 MonoTouch 上使用一个加密器加密多个字符串?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7028040/