支払いプロバイダーの場合、HMAC-SHA256を使用して、ハッシュベースのメッセージ認証コードを計算する必要があります。それは私にかなりのトラブルを引き起こしています。
支払いプロバイダーは、正しく計算された認証コードの2つの例を擬似コードで提供します。すべてのキーは16進数です。
key = 57617b5d2349434b34734345635073433835777e2d244c31715535255a366773755a4d70532a5879793238235f707c4f7865753f3f446e633a21575643303f66
message = "amount=100¤cy=EUR"
MAC = HMAC-SHA256( hexDecode(key), message )
result = b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
message = "amount=100¤cy=EUR"
Ki = 61574d6b157f757d02457573556645750e0341481b127a07476303136c005145436c7b46651c6e4f4f040e1569464a794e534309097258550c17616075060950
Ko = 0b3d27017f151f17682f1f193f0c2f1f64692b227178106d2d096979066a3b2f2906112c0f760425256e647f032c2013243929636318323f667d0b0a1f6c633a
MAC = SHA256( hexDecode(Ko) + SHA256( hexDecode(Ki) + message ) )
result = b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
いくつかの調査を行った後、これを行うためのコードを記述しようとしましたが、さまざまな結果を出し続けています。
private static void Main(string[] args)
{
var key = "57617b5d2349434b34734345635073433835777e2d244c31715535255a366773755a4d70532a5879793238235f707c4f7865753f3f446e633a21575643303f66";
var ki = "61574d6b157f757d02457573556645750e0341481b127a07476303136c005145436c7b46651c6e4f4f040e1569464a794e534309097258550c17616075060950";
var ko = "0b3d27017f151f17682f1f193f0c2f1f64692b227178106d2d096979066a3b2f2906112c0f760425256e647f032c2013243929636318323f667d0b0a1f6c633a";
var mm = "amount=100¤cy=EUR";
var result1 = CalcHMACSHA256Hash(HexDecode(key), mm);
var result2 = CalcSha256Hash(string.Format("{0}{1}", HexDecode(ko), CalcSha256Hash(HexDecode(ki) + mm)));
Console.WriteLine("Expected: b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905");
Console.WriteLine("Actual 1: " + result1);
Console.WriteLine("Actual 2: " + result2);
Console.WriteLine("------------------------------");
Console.ReadKey();
}
private static string HexDecode(string hex)
{
var sb = new StringBuilder();
for (int i = 0; i <= hex.Length - 2; i += 2)
{
sb.Append(Convert.ToString(Convert.ToChar(Int32.Parse(hex.Substring(i, 2), System.Globalization.NumberStyles.HexNumber))));
}
return sb.ToString();
}
private static string CalcHMACSHA256Hash(string plaintext, string salt)
{
string result = "";
var enc = Encoding.Default;
byte[]
baText2BeHashed = enc.GetBytes(plaintext),
baSalt = enc.GetBytes(salt);
System.Security.Cryptography.HMACSHA256 hasher = new HMACSHA256(baSalt);
byte[] baHashedText = hasher.ComputeHash(baText2BeHashed);
result = string.Join("", baHashedText.ToList().Select(b => b.ToString("x2")).ToArray());
return result;
}
public static string CalcSha256Hash(string input)
{
SHA256 sha256 = new SHA256Managed();
byte[] sha256Bytes = Encoding.Default.GetBytes(input);
byte[] cryString = sha256.ComputeHash(sha256Bytes);
string sha256Str = string.Empty;
for (int i = 0; i < cryString.Length; i++)
{
sha256Str += cryString[i].ToString("x2");
}
return sha256Str;
}
そして、これは私が得る結果です:
Expected: b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
Actual 1: 421ce16f2036bb9f2a3770c16f01e9220f0232d45580584ca41768fd16c15fe6
Actual 2: 290f14398bf8c0959dfc963e2fd9c377534c6fec1983025d2ab192382f132b92
そのため、2つの方法のいずれも使用せずに、プロバイダーの例が望む結果を得ることができます。
ここで何が欠けていますか?エンコードですか? hexDecodeがねじ込まれていますか?
支払いプロバイダーのテストツール: http://tech.dibs.dk/dibs_api/other_features/hmac_tool/
PHPサンプルコード: http://tech.dibspayment.com/dibs_api/other_features/mac_calculation/
私はあなたの問題に対する完全な解決策を作りました(おそらくあなたが探していたものだからです)。方法1と2の両方を使用して正しいハッシュを計算します。
プログラムは、次の3つのセクションに編成できます。
byte[]
_を使用してハッシュを計算する実際の関数ですstring
-> _byte[]
_byte[]
_-> hex string
string
-> _byte[]
_(ありがとう@bobince!)開始する前に、次のusingステートメントがあることを確認して、それらを含めないことで大量のエラーが発生しないようにしてください。
_using System;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
_
これにより、HMAC-SHA256が計算されます(方法1)。ご覧のとおり、方法2よりもはるかに単純ですが、結果は同じです。
_private static byte[] HashHMAC(byte[] key, byte[] message)
{
var hash = new HMACSHA256(key);
return hash.ComputeHash(message);
}
_
トンSHAハッシュ(メソッド2))を使用してハッシュを計算するには、もう少し複雑です。これは、16進デコードおよび使用のない擬似コードと基本的に同じです代わりに、入力用の_byte[]
_これは次のようになります。
_MAC = SHA256( outerKey + SHA256( innerKey + message ) )
_
あなたの代わりに:
_MAC = SHA256( hexDecode(outerKey) + SHA256( hexDecode(innerKey) + message ) )
_
ここで、outerKey
、innerKey
、およびmessage
はすべて_byte[]
_ sです。もちろん、この場合、すべてのキーはすでに16進文字列からデコードされていますが、_byte[]
_ sである可能性もあります。
そのため、コードは次の手順に分類できます。
byte[] innerData
_に保存しますinnerKey
とmessage
を_byte[] innerData
_にコピーしますinnerData
のSHA256ハッシュを計算し、_byte[] innerHash
_に保存しますbyte[] data
_にそのためのバッファーを作成しますouterKey
とinnerHash
(以前に計算されたハッシュ(#3から))をdata
にコピーしますdata
の最終ハッシュを計算し、result
に保存して返します。バイトコピーを行うには、 Buffer.BlockCopy()
関数を使用しています。これは、他の方法より明らかに高速であるためです( source )。これらの手順は、次のようなコードで記述できます。
_private static byte[] HashSHA(byte[] innerKey, byte[] outerKey, byte[] message)
{
var hash = new SHA256Managed();
// Compute the hash for the inner data first
byte[] innerData = new byte[innerKey.Length + message.Length];
Buffer.BlockCopy(innerKey, 0, innerData, 0, innerKey.Length);
Buffer.BlockCopy(message, 0, innerData, innerKey.Length, message.Length);
byte[] innerHash = hash.ComputeHash(innerData);
// Compute the entire hash
byte[] data = new byte[outerKey.Length + innerHash.Length];
Buffer.BlockCopy(outerKey, 0, data, 0, outerKey.Length);
Buffer.BlockCopy(innerHash, 0, data, outerKey.Length, innerHash.Length);
byte[] result = hash.ComputeHash(data);
return result;
}
_
ハッシュ16進数関数に進む前に、概要で述べたように、物事間の変換を支援するいくつかの関数が必要です。
string
-> _byte[]
_文字列のエンコードは、テキストがプレーンASCIIであり、今のところ)動作しているように見えます。その場合は、 ASCIIEncoding
with _UTF8Encoding
_ または使用しているエンコーディングを切り替えます。
_private static byte[] StringEncode(string text)
{
var encoding = new ASCIIEncoding();
return encoding.GetBytes(text);
}
_
byte[]
_-> hex string
これは、バイトの配列を取り、小文字の16進文字列に変換するだけです。ものすごく単純。
_private static string HashEncode(byte[] hash)
{
return BitConverter.ToString(hash).Replace("-", "").ToLower();
}
_
string
-> _byte[]
_最後に、16進文字列からバイト配列への変換があります。これは@bobinceの答えから来たので、私のものではありません。クレジットが支払われるべき場所にクレジットを与える。
_private static byte[] HexDecode(string hex)
{
var bytes = new byte[hex.Length / 2];
for (int i = 0; i < bytes.Length; i++)
{
bytes[i] = byte.Parse(hex.Substring(i * 2, 2), NumberStyles.HexNumber);
}
return bytes;
}
_
前に述べたように、これらは代わりに16進データと文字列を使用するハッシュ関数と連携するヘルパー関数です。それらは一目瞭然です:
_private static string HashHMACHex(string keyHex, string message)
{
byte[] hash = HashHMAC(HexDecode(keyHex), StringEncode(message));
return HashEncode(hash);
}
_
_private static string HashSHAHex(string innerKeyHex, string outerKeyHex, string message)
{
byte[] hash = HashSHA(HexDecode(innerKeyHex), HexDecode(outerKeyHex), StringEncode(message));
return HashEncode(hash);
}
_
すべての機能を一緒にラップするために、機能を呼び出して実際に正常に機能していることを示すコンソールプログラムを次に示します。
_static void Main(string[] args)
{
string message = "amount=100¤cy=EUR";
string expectedHex = "b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905";
Console.WriteLine("Ref : " + expectedHex);
// Test out the HMAC hash method
string key = "57617b5d2349434b34734345635073433835777e2d244c31715535255a366773755a4d70532a5879793238235f707c4f7865753f3f446e633a21575643303f66";
string hashHMACHex = HashHMACHex(key, message);
Console.WriteLine("HMAC: " + hashHMACHex);
// Test out the SHA hash method
string innerKey = "61574d6b157f757d02457573556645750e0341481b127a07476303136c005145436c7b46651c6e4f4f040e1569464a794e534309097258550c17616075060950";
string outerKey = "0b3d27017f151f17682f1f193f0c2f1f64692b227178106d2d096979066a3b2f2906112c0f760425256e647f032c2013243929636318323f667d0b0a1f6c633a";
string hashSHAHex = HashSHAHex(innerKey, outerKey, message);
Console.WriteLine("SHA : " + hashSHAHex);
Console.ReadLine();
}
_
すべてが正常に実行され、エラーなしで実行された場合、すべてのハッシュが正しいことを示す次の出力を取得する必要があります(ref
は予想されるハッシュです):
_Ref : b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
HMAC: b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
SHA : b436e3e86cb3800b3864aeecc8d06c126f005e7645803461717a8e4b2de3a905
_
最後に、すべてが正常に機能することを確認するために、コードは次の場所にあります。
http://Pastebin.com/xAAuZrJX
かなり標準的なHMAC SHA 256トークンを特定の文字列に取得するための文字列拡張メソッドです:
使用法:
myMessageString.HmacSha256Digest(mySecret)
文字列拡張メソッド:
public static string HmacSha256Digest(this string message, string secret)
{
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] keyBytes = encoding.GetBytes(secret);
byte[] messageBytes = encoding.GetBytes(message);
System.Security.Cryptography.HMACSHA256 cryptographer = new System.Security.Cryptography.HMACSHA256(keyBytes);
byte[] bytes = cryptographer.ComputeHash(messageBytes);
return BitConverter.ToString(bytes).Replace("-", "").ToLower();
}
この方法をHMACSHA256に使用できます。
string key = "your key";
string message = "your message";
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(key);
HMACSHA256 hmacsha256 = new HMACSHA256(keyByte);
byte[] messageBytes = encoding.GetBytes(message);
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
return ByteToString(hashmessage);
ByteToStringメソッドは次のとおりです。
public static string ByteToString(byte[] buff)
{
string sbinary = "";
for (int i = 0; i < buff.Length; i++)
{
sbinary += buff[i].ToString("X2"); // hex format
}
return (sbinary);
}
SHAハッシュはバイトシーケンスで計算されます。バイトは文字とはまったく異なるデータ型です。ハッシュなどのバイナリデータを格納するために文字列を使用しないでください。
sb.Append(Convert.ToString(Convert.ToChar(Int32.Parse(hex.Substring(i、2)...
これは、エンコードされた各バイトを読み取り、同じUnicodeコードポイント番号の文字に変換することにより、文字列を作成します。これは、Unicodeの最初の256コードポイントに一致するというエンコードのプロパティのため、ISO-8859-1(Latin1)エンコードを使用してバイト0-255をデコードすることと同等です。
var enc = Encoding.Default; [...] baSalt = enc.GetBytes(salt);
byte [] sha256Bytes = Encoding.Default.GetBytes(input);
これらは両方とも、システムのデフォルトのエンコーディングを使用して、文字をバイトに変換します。このエンコードはインストールごとに異なりますが、ISO-8859-1になることはありません-同様の西ヨーロッパコードページ1252でさえ、0x80-0x9Fの範囲の異なる文字があります。
したがって、使用しているバイト配列には、16進数シーケンスの例で示されているバイトは含まれていません。安価な修正方法は、デフォルトのエンコーディングの代わりにEncoding.GetEncoding("ISO-8859-1")
を使用することですが、実際にはStringの代わりにbytes配列を使用してデータを格納する必要があります。たとえば:
byte[] key= new byte[] { 0x57, 0x61, 0x7b, 0x5d, 0x23, 0x49, ... };
ComputeHash
に直接渡します。
16進文字列からデータを初期化する必要がある場合は、バイト配列に直接解析します。例:
private static byte[] HexDecode(string hex) {
var bytes= new byte[hex.Length/2];
for (int i= 0; i<bytes.Length; i++) {
bytes[i]= byte.Parse(hex.Substring(i*2, 2), NumberStyles.HexNumber);
}
return bytes;
}
私は質問に答えていることを理解していますが、他の人が必要とする場合に備えてこれを投稿しています。以下は、支払いプロバイダー(DIBS)によって作成されたコードのスニペットです。
/**
* calculateMac
* Calculates the MAC key from a Dictionary<string, string> and a secret key
* @param params_dict The Dictionary<string, string> object containing all keys and their values for MAC calculation
* @param K_hexEnc String containing the hex encoded secret key from DIBS Admin
* @return String containig the hex encoded MAC key calculated
**/
public static string calculateMac(Dictionary<string, string> paramsDict, string kHexEnc)
{
//Create the message for MAC calculation sorted by the key
var keys = paramsDict.Keys.ToList();
keys.Sort();
var msg = "";
foreach (var key in keys)
{
if (key != keys[0]) msg += "&";
msg += key + "=" + paramsDict[key];
}
//Decoding the secret Hex encoded key and getting the bytes for MAC calculation
var kBytes = new byte[kHexEnc.Length / 2];
for (var i = 0; i < kBytes.Length; i++)
{
kBytes[i] = byte.Parse(kHexEnc.Substring(i * 2, 2), NumberStyles.HexNumber);
}
//Getting bytes from message
var msgBytes = Encoding.Default.GetBytes(msg);
//Calculate MAC key
var hash = new HMACSHA256(kBytes);
var macBytes = hash.ComputeHash(msgBytes);
var mac = BitConverter.ToString(macBytes).Replace("-", "").ToLower();
return mac;
}
おかげで私の時間を節約できました。
request.Method = "GET";
string signature = "";
string strtime = DateTime.UtcNow.ToString("yyyy-MM-ddTHH\\:mm\\:ssZ");
string secret = "xxxx";
string message = "sellerid:email:" + strtime;
var encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(secret);
byte[] messageBytes = encoding.GetBytes(message);
using (var hmacsha256 = new HMACSHA256(keyByte))
{
var hash = new HMACSHA256(keyByte);
byte[] signature1 = hash.ComputeHash(messageBytes);
signature = BitConverter.ToString(signature1).Replace("-", "").ToLower();
}
request.Headers.Add("authorization", "HMAC-SHA256" + " " +
"[email protected],timestamp=" + strtime + ",signature=" + signature);
HttpWebResponse response = request.GetResponse() as HttpWebResponse;