5

在将数据从 iPad 应用程序发送到 WCF Web 服务之前,我正在使用以下(精简的)类来加密一些数据。

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 结果时,解密字符串的一部分是 gibberish。来自服务器的加密结果正确解密。

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"));

这使我认为问题出在所涉及对象的状态中。我检查了方法中的buffer变量,实例Encrypt(string)产生的值是正确的。UTF8Encoding这意味着该encryptor领域(或其底层实现)是罪魁祸首

当我开始改变第一个加密值的大小时,我可以看到第二个加密调用结果的变化。这可能意味着流的某些部分没有被正确清除或覆盖。但是FlawedAlgorithm该类使用的流不是其状态的一部分;它们在每次方法调用时重新创建。而且该encryptor对象看起来不像管理自己的流的类型。

有没有其他人遇到过类似的问题?RijndaelManaged班级有问题吗?或者 MonoTouch 中是否存在一些流和内存管理缺陷,与这个密码学示例无关?

PS:我已经在 iPad 和 iPad Simulator 上测试过了;两者都表现出这种奇怪的行为。

4

1 回答 1

8

使用 .NET 加密时,您必须始终检查 ICryptoTransform.CanReuseTransform(或假设它将返回 false)。如果它返回 false,那么您不能重用相同的加密器/解密器,并且必须创建新实例。

跳过此检查意味着框架中的任何更改(或通过配置文件,因为密码学是可插入的)将来可能会破坏您的应用程序。

你可以使用类似的东西:

 ICryptoTransform Decryptor {
    get {
       if (decryptor == null || !decryptor.CanReuseTransform)
          decryptor = rijndael.CreateDecryptor (key, vector);
        return decryptor;
    }
 }

向您的加密例程的调用者隐藏这种复杂性。

于 2011-08-11T15:35:07.927 回答