Я использую следующий (урезанный) класс для шифрования некоторых данных перед их отправкой из приложения 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"));
Это наводит меня на мысль, что проблема где-то в состоянии задействованных объектов. Я проверил переменную buffer
в методе Encrypt (string)
, и значения, созданные экземпляром UTF8Encoding
, верны. Это означает, что виновником является поле encryptor
(или его базовая реализация) .
Когда я начинаю изменять размер первого зашифрованного значения, я вижу изменения в результате второго вызова шифрования. Это, вероятно, означает, что некоторая часть потока не очищается или не перезаписывается должным образом. Но потоки, которые использует класс FlawedAlgorithm
, не являются частью его состояния; они воссоздаются при каждом вызове метода. И объект encryptor
не похож на тип, который управляет своими собственными потоками.
Кто-нибудь еще сталкивался с подобной проблемой? Является ли класс RijndaelManaged
некорректным? Или здесь присутствуют некоторые подводные камни управления потоком и памятью в MonoTouch, не связанные с этим примером криптографии?
P.S .: Я тестировал это как на iPad, так и на iPad Simulator; оба демонстрируют это странное поведение.