Ich versuche, eine REST-API mit C # zu verwenden. Der API-Ersteller hat Beispielbibliotheken in PHP, Ruby und Java bereitgestellt. Ich hänge an einem Teil davon fest, wo ich eine generieren muss HMAC
.
So wird es in den von ihnen bereitgestellten Beispielbibliotheken gemacht.
PHP
hash_hmac('sha1', $signatureString, $secretKey, false);
Rubin
digest = OpenSSL::Digest::Digest.new('sha1')
return OpenSSL::HMAC.hexdigest(digest, secretKey, signatureString)
Java
SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes(), HMAC_SHA1_ALGORITHM);
Mac mac = null;
mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(signingKey);
byte[] bytes = mac.doFinal(signatureString.getBytes());
String form = "";
for (int i = 0; i < bytes.length; i++)
{
String str = Integer.toHexString(((int)bytes[i]) & 0xff);
if (str.length() == 1)
{
str = "0" + str;
}
form = form + str;
}
return form;
Hier ist mein Versuch in C#. Es funktioniert nicht. AKTUALISIEREN: Das folgende C#-Beispiel funktioniert einwandfrei. Ich fand heraus, dass das eigentliche Problem auf einigen plattformübergreifenden Unterschieden bei den Zeilenumbruchzeichen in meinem lag signatureString
.
var enc = Encoding.ASCII;
HMACSHA1 hmac = new HMACSHA1(enc.GetBytes(secretKey));
hmac.Initialize();
byte[] buffer = enc.GetBytes(signatureString);
return BitConverter.ToString(hmac.ComputeHash(buffer)).Replace("-", "").ToLower();
eine Erweiterung der Antwort von Vimvq1987:
return hashValue.ToString();
erzeugt nicht die Ausgabe, die Sie wollen/brauchen. Sie müssen die Bytes im Array konvertieren hashValue
zu ihrer Hex-String-Darstellung.
Kann so einfach sein wie return BitConverter.toString(hashValue);
(druckt Großbuchstaben AF) oder wer es etwas komplexer mag:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
public static string Encode(string input, byte[] key)
{
HMACSHA1 myhmacsha1 = new HMACSHA1(key);
byte[] byteArray = Encoding.ASCII.GetBytes(input);
MemoryStream stream = new MemoryStream(byteArray);
return myhmacsha1.ComputeHash(stream).Aggregate("", (s, e) => s + String.Format("{0:x2}",e), s => s );
}
static void Main(string[] args)
{
byte[] key = Encoding.ASCII.GetBytes("abcdefghijklmnopqrstuvwxyz");
string input = "";
foreach (string s in new string[] { "Marry", " had", " a", " little", " lamb" })
{
input += s;
System.Console.WriteLine( Encode(input, key) );
}
return;
}
}
}
was druckt
3545e064fb59bc4bfc02b6e1c3d4925c898aa504
3249f4c8468d4d67f465937da05b809eaff22fdb
87baaadf5d096677f944015e53d283834eb1e943
6325376820c29a09e3ab30db000033aa71d6927d
54579b0146e2476595381d837ee38863be358213
und ich bekomme genau das gleiche Ergebnis für
<?php
$secretKey = 'abcdefghijklmnopqrstuvwxyz';
$signatureString = '';
foreach( array('Marry',' had',' a',' little',' lamb') as $s ) {
$signatureString .= $s;
echo hash_hmac('sha1', $signatureString, $secretKey, false), "\n";
}
Bearbeiten: Dmitriy Nemykin schlug die folgende Bearbeitung vor
public static string Encode(string input, byte[] key)
{
byte[] byteArray = Encoding.ASCII.GetBytes(input);
using(var myhmacsha1 = new HMACSHA1(key))
{
var hashArray = myhmacsha1.ComputeHash(byteArray);
return hashArray.Aggregate("", (s, e) => s + String.Format("{0:x2}",e), s => s );
}
}
was abgelehnt wurde. Aber wie James bereits in einem Kommentar zu dieser Antwort anmerkte, zumindest das using-Anweisung ist ein guter Punkt.
Diese Seite hat einige ziemlich gute Beispiele für Sprachen: http://jokecamp.wordpress.com/2012/10/21/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/
Die c#-Implementierung zum Zeitpunkt des Schreibens ist:
private string CreateToken(string message, string secret)
{
secret = secret ?? "";
var encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(secret);
byte[] messageBytes = encoding.GetBytes(message);
using (var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
return Convert.ToBase64String(hashmessage);
}
}
Versuche dies:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.hmacsha1.aspx
schneller und schmutziger Code:
public string Encode(string input, byte [] key)
{
HMACSHA1 myhmacsha1 = new HMACSHA1(key);
byte[] byteArray = Encoding.ASCII.GetBytes( input );
MemoryStream stream = new MemoryStream( byteArray );
byte[] hashValue = myhmacsha1.ComputeHash(stream);
return hashValue.ToString();
}
Es stellt sich heraus, dass mein C#-Code einwandfrei funktioniert. Das eigentliche Problem lag an einigen plattformübergreifenden Unterschieden bei Zeilenumbrüchen in meinem the
signatureString
. Ich werde diese Frage zum Löschen markieren.– Jessegavin
20. Mai 2011 um 17:07 Uhr
Anstatt die Frage zu löschen, posten Sie Ihren Code als Antwort und akzeptieren Sie ihn. Diese Frage ist sehr nützlich, wenn Sie dasselbe tun möchten.
– Serhat Özgel
4. Dezember 2015 um 11:08 Uhr
Ich habe ein weiteres Update zum Text “Die API antwortet…” hinzugefügt, um mögliche Missverständnisse zu vermeiden
– Ciro Corvino
27. Oktober 2016 um 9:39 Uhr