为什么我不能在MonoTouch上使用一个加密器加密多个字符串?

Nie*_*est 5 .net c# encryption rijndaelmanaged xamarin.ios

我正在使用以下(修剪)类来加密某些数据,然后再将其从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();
    }
}
Run Code Online (Sandbox Code Playgroud)

当我在服务器和iPad上运行以下代码时,两者都打印相同的加密字符串.

var algorithm = new FlawedAlgorithm();

Console.WriteLine(algorithm.Encrypt("Some string"));
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试加密第二个值时,服务器和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"));
Run Code Online (Sandbox Code Playgroud)

当我解密服务器上偏离的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"));
Run Code Online (Sandbox Code Playgroud)

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

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

有没有其他人遇到类似的问题?是RijndaelManaged类存在缺陷?或者MonoTouch中是否存在一些流和内存管理陷阱,与此加密示例无关?

PS:我已经在iPad和iPad模拟器上测试了这个; 都表现出这种奇怪的行为.

pou*_*pou 7

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

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

您可以使用以下内容:

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

从加密例程的调用者隐藏这种复杂性.