2012-03-04 9 views
3

私はAndroidにWindowsアプリケーションを移植しており、エンディアンに関する問題が発生しています。このアプリケーションはユーザーから一連のテキストフィールドを受け取り、MD5に基づいてパスワードを生成します。問題は、MD5ダイジェストメソッドに渡すためにバイト配列を作成するときです。Androidアプリのバイトはビッグエンディアン形式です。したがって、MD5出力は2つのプラットフォーム間で一致しません。AndroidリトルエンディアンMD5

ByteBufferを使用してリトルエンディアンに変換し、その値をByteBuffer.get()を使用してバイト配列にコピーしてみました。悲しいことに、それは注文設定を維持していないので動作しません。これは、ByteBuffersを扱う際に知られている "つかの間"のようです。 ByteBuffer.getLong()の値とWindows版の同等の値を比較すると、値は一致しますが、正しい順序でByteBufferから配列を戻す方法はわかりません。

編集:私は以下のjava関数とC#関数の両方を添付しました。

以下

順/エンディアンを修正しようとしないJavaのバージョンです:

public static final long md5(final String input) { 
    try { 
     // Create MD5 
     MessageDigest md5 = MessageDigest.getInstance("MD5"); 

     // Read in string as an array of bytes. 
     byte[] originalBytes = input.getBytes("US-ASCII"); 
     byte[] encodedBytes = md5.digest(originalBytes); 

     long output = 0; 
     long multiplier = 1; 

     // Create 64 bit integer from the MD5 hash of the input 
     for (int i = 0; i < encodedBytes.length; i++) { 
      output = output + encodedBytes[i] * multiplier; 
      multiplier = multiplier * 255; 
     } 
     return output; 

    } 
    catch (NoSuchAlgorithmException e) { 
     e.printStackTrace(); 
    } 
    catch (UnsupportedEncodingException e) { 
     e.printStackTrace(); 
    } 
    return 0; 
} 

そしてここでは、C#バージョン

private Int64 MD5(string input) 
{ 
    MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider(); 

    byte[] originalBytes = ASCIIEncoding.ASCII.GetBytes(input); 
    byte[] encodedBytes = md5.ComputeHash(originalBytes); 
    Int64 output = 0; 
    Int64 Multiplyer = 1; 
    for (int i = 0; i < encodedBytes.Length; i++) 
    { 
    output = output + encodedBytes[i] * Multiplyer; 
    Multiplyer = Multiplyer * 255; 
    } 
    return output; 
} 
+1

私はあなたが問題について混乱していると思う - テキストからバイナリへの変換とMD5アルゴリズムの両方で単純なバイト配列が生成されます。 –

+0

しかし、ダイジェストメソッドに入るバイトの順序は関係ありませんか? – quesauce

+0

はい、そうです。 Windows版に入った最初のバイトは、アンドロイドに入る最初のバイトでなければなりません。しかし、エンディアンは、バイトストリームではなく、ワード内のバイトの順序に関係します。 –

答えて

2

問題は、Javaの次の行ということである。

  output = output + encodedBytes[i] * multiplier; 

は、C#コードのこの行から微妙に異なっている。具体的には

output = output + encodedBytes[i] * Multiplyer; 

longからbyteからencodedBytes[i]の暗黙の変換(ジャワ)またはInt64(C#)は少し異なります。あなたが見

は、Javaで、byteは、C#で、それは0255符号なし値だのに対しは、-128127値に署名しています。

encodedBytes[i]B21011 0010)であれば、例えば、その後、JavaはC#は178

としてJavaでC#の解釈をエミュレートすることを解釈しながら-78として、あなたはこのような何かを書くことができると解釈します

  output = output + ((encodedBytes[i] + 256) % 256) * multiplier; 

(幸いなことに、Javaは明らかにあなたが使用しているものであるC#の "未チェック」モード、などの整数オーバーフローのために同じ取り扱いを持っています。ことをエミュレートするために非常にトリッキーだったでしょう、あなたが持っていた場合に。)

+0

あなたはロックスターです。アンドロイドアプリは今や期待どおりに動作します。私はバイトの実装の違いを比較することは考えていませんでした!どうもありがとうございました。 – quesauce

+0

@quesauce:あなたは大歓迎です! – ruakh

+0

@quesauce:ところで、「b2」が 'ffffffb2 'と表示されるまで、つまり' 1011 0010'が '1111 1111 1111 1111 1111 1111 1011 0010' - [記号の拡張子]の明確な証拠(http://en.wikipedia.org/wiki/Sign_extension)。 – ruakh

0

128ビット値のためのMD5 standard呼び出しがあり、 64ビットではありません。まず第一に、署名private Int64 MD5(string input)は意味をなさない。これらを整数に変換して比較しようとするべきではありません。ちょうどbyte[]の参照を渡し、それらを比較してください。

+1

残念ながら、私には選択肢がありません。元のWindowsバージョンは既に展開されており、使用中です。私はちょうどそれが何かをエミュレートする必要があります(それが間違っている場合でも)。 – quesauce

関連する問題