3

私はSuomenVerkkomaksutと呼ばれるデジタル決済サービスのインターフェースを実装しています。支払いに関する情報は、HTMLフォームを介して送信されます。転送中に誰も情報を台無しにしないようにするために、MD5ハッシュは、送信されない特別なキーを使用して両端で計算されます。

私の問題は、何らかの理由で、着信データがUTF-8ではなくISO-8859-1でエンコードされていると判断したように見えることです。私が彼らに送ったハッシュはUTF-8文字列で計算されるため、彼らが計算するハッシュとは異なります。

私は次のコードでこれを試しました:

String prehash = "6pKF4jkv97zmqBJ3ZL8gUw5DfT2NMQ|13466|123456||Testitilaus|EUR|http://www.esimerkki.fi/success|http://www.esimerkki.fi/cancel|http://www.esimerkki.fi/notify|5.1|fi_FI|0412345678|0412345678|esimerkki@esimerkki.fi|Matti|Meikäläinen||Testikatu 1|40500|Jyväskylä|FI|1|2|Tuote #101|101|1|10.00|22.00|0|1|Tuote #202|202|2|8.50|22.00|0|1";
String prehashIso = new String(prehash.getBytes("ISO-8859-1"), "ISO-8859-1");

String hash = Crypt.md5sum(prehash).toUpperCase(); 
String hashIso = Crypt.md5sum(prehashIso).toUpperCase();

残念ながら、両方のハッシュは値C83CF67455AF10913D54252737F30E21と同じです。この例の場合の正しい値は、SuomenVerkkomaksutのドキュメントによると975816A41B9EB79B18B3B4526569640Eです。

ISO-8859-1文字列を使用してJavaでMD5ハッシュを計算する方法はありますか?

更新: Suomen Verkkomaksutからの回答を待っている間に、ハッシュを作成する別の方法を見つけました。Michael Borgwardtは、文字列とエンコーディングの理解を修正し、byte[]からハッシュを作成する方法を探しました。

Apache Commonsはライブラリの優れたソースであり、byte[]入力を受け取って32文字の16進文字列を返すmd5hex関数を持つDigestUtilsクラスを見つけました。

何らかの理由で、これはまだ機能しません。これらは両方とも同じ値を返します。

DigestUtils.md5Hex(prehash.getBytes());
DigestUtils.md5Hex(prehash.getBytes("ISO-8859-1"));
4

4 に答える 4

9

文字列エンコーディングがどのように機能するかを誤解しているようで、CryptクラスのAPIが疑わしいです。

文字列は実際には「エンコーディングを持っている」わけではありません。エンコーディングは、文字列とバイトの間で変換するために使用するものです。

Java文字列は内部でUTF-16として格納されますが、MD5は文字列ではなくバイトで機能するため、これは実際には重要ではありません。メソッドCrypt.md5sum()は、最初に渡された文字列をバイトに変換する必要があります-それを行うためにどのエンコーディングを使用しますか?それがおそらくあなたの問題の原因です。

この行の唯一の効果として、サンプルコードはかなり無意味です。

String prehashIso = new String(prehash.getBytes("ISO-8859-1"), "ISO-8859-1");

ISO-8859-1で表現できない文字を疑問符に置き換えることです。

于 2009-12-03T10:43:55.143 に答える
2

問題を解決したかどうかはわかりませんが、ISO-8859-1でエンコードされた、北欧のä&ö文字を含む文字列と、ドキュメント内のものと比較するためのSHA-256ハッシュの計算で同様の問題が発生しました。次のスニペットは私のために働きました:

import java.security.MessageDigest;
//imports omitted

@Test
public void test() throws ProcessingException{
String test = "iamastringwithäöchars";           
System.out.println(this.digest(test));      
}

public String digest(String data) throws ProcessingException {
    MessageDigest hash = null;

    try{
        hash = MessageDigest.getInstance("SHA-256");
    }
    catch(Throwable throwable){
        throw new ProcessingException(throwable);
    }
    byte[] digested = null;
    try {
        digested = hash.digest(data.getBytes("ISO-8859-1"));
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    String ret = BinaryUtils.BinToHexString(digested);
    return ret;
}

バイトを16進文字列に変換するには、このスレッドで言及されているapache commonscodecHexクラスを含む多くのオプションがあります。

于 2011-07-12T09:08:56.580 に答える
2

Javaには、さまざまなハッシュを計算するための標準のjava.security.MessageDigestクラスがあります。

これがサンプルコードです

include java.security.MessageDigest;

// Exception handling not shown

String prehash = ...

final byte[] prehashBytes= prehash.getBytes( "iso-8859-1" );

System.out.println( prehash.length( ) );
System.out.println( prehashBytes.length );

final MessageDigest digester = MessageDigest.getInstance( "MD5" );

digester.update( prehashBytes );

final byte[] digest = digester.digest( );

final StringBuffer hexString = new StringBuffer();

for ( final byte b : digest ) {
    final int intByte = 0xFF & b;

    if ( intByte < 10 )
    {
        hexString.append( "0" );
    }

    hexString.append(
        Integer.toHexString( intByte )
    );
}

System.out.println( hexString.toString( ).toUpperCase( ) );

残念ながら、同じ「C83CF67455AF10913D54252737F30E21」ハッシュが生成されます。だから、あなたの暗号クラスは免罪されていると思います。prehashと長さのプリントアウトを具体的に追加してprehashBytes、実際に「ISO-8859-1」が使用されていることを確認しました。この場合、両方とも328です。

私がやったときpresash.getBytes( "utf-8" )、それは「9CC2E0D1D41E67BE9C2AB4AABDB6FD3」を生成しました(そしてバイト配列の長さは332になりました)。繰り返しますが、あなたが探している結果ではありません。

ですから、Suomen Verkkomaksutはprehash、彼らが文書化していない、またはあなたが見落としている文字列のマッサージを行っていると思います。

于 2009-12-03T12:06:08.257 に答える
1

ISO-8859-1として扱われるUTF-8でエンコードされたデータを送信する場合、それが問題の原因である可能性があります。ISO-8859-1でデータを送信するか、UTF-8を送信していることをSuomenVerkkomaksutに伝えてみることをお勧めします。httpベースのプロトコルでは、HTTPヘッダーのContent-Typeにcharset=utf-8を追加することでこれを行います。

いくつかの問題を除外する方法は、UTF-8とISO-8859-1で同じようにエンコードされた文字のみを含むプレハッシュ文字列を試すことです。私が見ることができることから、あなたが使用している文字列のすべての「ä」文字を削除することによってこれを達成することができます。

于 2009-12-03T10:33:59.007 に答える