2011-08-11 5 views
5

私は、次の(トリムダウン)クラスを使用して、iPadアプリからWCF Webサービスにデータを送信する前に、データを暗号化しています。MonoTouchで1つの暗号化装置を使用して複数の文字列を暗号化できないのはなぜですか?

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

ただし、2番目の値を暗号化しようとすると、サーバーと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フィールド(またはその基礎となる実装)が原因であることを意味します

最初の暗号化された値のサイズを変更すると、2番目の暗号化呼び出しの結果に変化が見られます。これはおそらく、ストリームの一部が適切に消去または上書きされていないことを意味します。しかし、FlawedAlgorithmクラスが使用するストリームは、その状態の一部ではありません。それぞれのメソッド呼び出しで再作成されます。 encryptorオブジェクトは、独自のストリームを管理するタイプのようには見えません。

誰かにこれに類似した問題が発生しましたか? RijndaelManagedクラスに欠陥がありますか?または、この暗号化の例とは無関係に、MonoTouchにストリームやメモリ管理の落とし穴がありますか?

P .:私はこれをiPadとiPad Simulatorの両方でテストしました。どちらもこの奇妙な動作を表示します。

答えて

6

.NET暗号化を使用する場合は、常にICryptoTransform.CanReuseTransformをチェックする必要があります(またはfalseを返すと仮定します)。 falseを返した場合、同じ暗号化/復号化を再利用することはできず、新しいインスタンスを作成する必要があります。

このチェックをスキップすると、フレームワーク(または設定ファイルを介して暗号化がプラグ可能であるため)の変更によって、将来アプリケーションが壊れる可能性があります。あなたの暗号化ルーチンの呼び出し元からこの複雑さを隠すために

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

次のようなものを使用することができます。

+0

私に 'CanReuseTransform'プロパティを指摘してくれてありがとう。 .NETでは、falseを返します。モノで、実際にはtrueを返します。それは私が再び作ってくれる間違いです! –

+1

最近、CanReuseTransformはiOS 10 MonoTouchではfalse、Android 7 MonoDroidではtrueです。それでもOPの質問とこの答えは、さらに無礼な苦痛の週末から私を救った。両方のおかげで! –

関連する問題