Я использую следующий (урезанный) класс для шифрования некоторых данных перед их отправкой из приложения 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; оба демонстрируют это странное поведение.