2011-08-11 36 views
5

Tôi đang sử dụng lớp sau (được cắt xuống) để mã hóa một số dữ liệu trước khi gửi nó từ một ứng dụng iPad đến một dịch vụ web WCF.Tại sao tôi không thể mã hóa nhiều chuỗi bằng cách sử dụng một bộ mã hóa trên MonoTouch?

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(); 
    } 
} 

Khi tôi chạy mã sau trên máy chủ và iPad, cả hai đều in cùng một chuỗi được mã hóa.

var algorithm = new FlawedAlgorithm(); 

Console.WriteLine(algorithm.Encrypt("Some string")); 

Tuy nhiên, khi tôi cố gắng mã hóa giá trị thứ hai, kết quả trên máy chủ và iPad là khác nhau.

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

Khi tôi giải mã kết quả sai lệch iPad trên máy chủ, một phần của chuỗi giải mã được tiếng vô nghia. Các kết quả được mã hóa từ máy chủ giải mã chính xác.

Vấn đề không biểu lộ chính nó nếu tôi có thể tạo một FlawedAlgorithm dụ mới cho mỗi cuộc gọi, ví dụ .:

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

Điều này dẫn tôi nghĩ rằng vấn đề nằm ở đâu đó trong trạng thái của các đối tượng liên quan. Tôi đã kiểm tra biến số buffer trong phương pháp Encrypt(string) và các giá trị được tạo ra bởi cá thể UTF8Encoding là chính xác. Điều này ngụ ý rằng trường encryptor (hoặc triển khai cơ bản của nó) là thủ phạm.

Khi tôi bắt đầu thay đổi kích thước của giá trị được mã hóa đầu tiên, tôi có thể thấy các thay đổi trong kết quả của cuộc gọi mã hóa thứ hai. Điều này có thể có nghĩa là một số phần của luồng không bị xóa hoặc ghi đè đúng cách. Nhưng các dòng sử dụng lớp FlawedAlgorithm, không phải là một phần của trạng thái của nó; chúng được tạo lại trên mỗi cuộc gọi phương thức. Và đối tượng encryptor dường như không phải là loại quản lý luồng của riêng nó.

Có ai khác đã gặp sự cố tương tự với vấn đề này không? Lớp học RijndaelManaged có thiếu sót không? Hoặc có một số cạm bẫy quản lý luồng và bộ nhớ trong MonoTouch lúc chơi ở đây, không liên quan đến ví dụ mã hóa này?

P .: Tôi đã thử nghiệm điều này trên cả iPad và iPad Simulator; cả hai đều hiển thị hành vi kỳ lạ này.

Trả lời

6

Khi sử dụng mã hóa .NET, bạn phải luôn kiểm tra ICryptoTransform.CanReuseTransform (hoặc giả sử nó sẽ trả về false). Nếu nó trả về false thì bạn không thể tái sử dụng cùng một bộ mã hóa/giải mã và phải tạo các cá thể mới.

Bỏ qua kiểm tra này có nghĩa là mọi thay đổi trong khung (hoặc thông qua tệp cấu hình, vì mật mã là có thể cắm được) có thể sẽ làm hỏng ứng dụng của bạn trong tương lai.

Bạn có thể sử dụng một cái gì đó như:

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

để che giấu sự phức tạp này từ người gọi của thói quen mật mã của bạn.

+0

Cảm ơn bạn đã chỉ cho tôi thuộc tính 'CanReuseTransform'. Trong .NET nó trả về false, trong Mono nó trả về, quả thật, đúng. Đó là một sai lầm tôi sẽ không làm lại! –

+1

Những ngày này CanReuseTransform là sai trên iOS 10 MonoTouch, đúng trên Android 7 MonoDroid. Tuy nhiên, câu hỏi OP và câu trả lời này đã cứu tôi từ một ngày cuối tuần đau khổ không ngừng. Cảm ơn cả hai bạn! –

Các vấn đề liên quan