9

私はJavaで次のコードを持っています:

byte[] secretKey = secretAccessKey.getBytes("UTF-8");
SecretKeySpec signingKey = new SecretKeySpec(secretKey, "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
byte[] bytes = data.getBytes("UTF-8");
byte[] rawHmac = mac.doFinal(bytes);
String result = javax.xml.bind.DatatypeConverter.printBase64Binary(rawHmac);

および C# の次のコード:

UTF8Encoding enc = new UTF8Encoding();
byte[] secretKey = enc.GetBytes(secretAccessKey);
HMACSHA256 hmac = new HMACSHA256(secretKey);
hmac.Initialize();
byte[] bytes = enc.GetBytes(data);
byte[] rawHmac = hmac.ComputeHash(bytes);
string result = Convert.ToBase64String(rawHmac);

バイト配列「secretKey」と「bytes」は同等ですが、バイト配列「rawHmac」が異なり、文字列「result」が異なります。誰でも理由がわかりますか?

4

2 に答える 2

17

これをしないでください:

byte[] bytes = data.getBytes();

これは、プラットフォームのデフォルトのエンコーディングを使用して、文字列をバイト配列に変換します。それはプラットフォームによって異なる可能性がありますが、再現可能なものが必要です。私はUTF-8をお勧めします:

byte[] bytes = data.getBytes("UTF-8");

(もちろんキーも同様です。)

非 ASCII 文字を本当に処理したくない場合を除き、ASCII ではなく、C# で同じエンコーディングを使用する必要があります。

byte[] bytes = Encoding.UTF8.GetBytes(data);

後で結果を比較する方法も明確ではありませんbyte.Javaでは署名されていますが、C#では署名されていないことを忘れないでください. 比較のためにハッシュを 16 進数または base64 に変換するのがおそらく最も簡単です。

編集:最後の部分が問題だったと強く思います-結果を比較します。

同じ base64 出力を生成する 2 つの短いが完全なプログラム (Java で iharder.net base64 コンバーターを使用) を次に示します。

ジャワ:

import java.util.*;
import javax.crypto.*;
import javax.crypto.spec.*;

public class Test {
    public static void main (String[] args) throws Exception {
        String secretAccessKey = "mykey";
        String data = "my data";
        byte[] secretKey = secretAccessKey.getBytes();
        SecretKeySpec signingKey = new SecretKeySpec(secretKey, "HmacSHA256");
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(signingKey);
        byte[] bytes = data.getBytes();
        byte[] rawHmac = mac.doFinal(bytes);
        System.out.println(Base64.encodeBytes(rawHmac));
    }
}

C#:

using System;
using System.Security.Cryptography;
using System.Text;

class Test
{
    static void Main()
    {
        String secretAccessKey = "mykey";
        String data = "my data";
        byte[] secretKey = Encoding.UTF8.GetBytes(secretAccessKey);
        HMACSHA256 hmac = new HMACSHA256(secretKey);
        hmac.Initialize();
        byte[] bytes = Encoding.UTF8.GetBytes(data);
        byte[] rawHmac = hmac.ComputeHash(bytes);
        Console.WriteLine(Convert.ToBase64String(rawHmac));
    }
}

両方からの出力:

ivEyFpkagEoghGnTw/LmfhDOsiNbcnEON50mFGzW9/w=
于 2012-11-05T17:44:57.057 に答える
1

示されているように、これは問題ではありませんでした。ハッシュは常に同じです。

私の場合の問題は無関係でした。JavaはUrlEncoderでパーセントエンコーディングを大文字にしますが、.NETはそうではありません。

単独でテストすることがいかに重要であるかを示します!

于 2012-11-06T15:16:00.190 に答える