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

标签 c# .net encryption xamarin.ios rijndaelmanaged

在将数据从 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/

相关文章:

c# - 如何防止 .NET 库在关闭时发送 RST 数据包

c# - EF 4.3.1 在 LinqToEntities 查询中包含继承的导航属性

javascript - 将数据从javascript传递到asp.net core 2 razor page方法

c# - 在 JavaScript 中将 C# .NET DateTime.ticks 转换为天/小时/分钟

c# - 与多个版本的 Word 互操作

c# - 为什么在我的相同代码的可执行文件正在工作时在我的 c# 脚本中得到 System.NullReferenceException?

.net - 与 |Pipe-delimited| 有什么关系?连接字符串中的变量?

java - 如何在 hibernate.cfg.xml 中将 hibernate.connection.password 设置为加密值,然后将其解密以在配置中使用?

android - 2021 年在 Android 中加密字符串的最佳和最安全的方法是什么?

swift - 使用 RNCryptor 解密 base64 编码和 aes 加密的字符串