How to generate HMAC-SHA1 in C#?
Solution 1
an extension to Vimvq1987's answer:
return hashValue.ToString();
doesn't produce the output you want/need. You have to convert the bytes in the array hashValue
to their hex-string representation.
Can be as simple as return BitConverter.toString(hashValue);
(prints upper-case letters A-F) or if you like it a bit more complex:
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;
}
}
}
which prints
3545e064fb59bc4bfc02b6e1c3d4925c898aa504
3249f4c8468d4d67f465937da05b809eaff22fdb
87baaadf5d096677f944015e53d283834eb1e943
6325376820c29a09e3ab30db000033aa71d6927d
54579b0146e2476595381d837ee38863be358213
and I get the exact same result for
<?php
$secretKey = 'abcdefghijklmnopqrstuvwxyz';
$signatureString = '';
foreach( array('Marry',' had',' a',' little',' lamb') as $s ) {
$signatureString .= $s;
echo hash_hmac('sha1', $signatureString, $secretKey, false), "\n";
}
edit: Dmitriy Nemykin suggested the following edit
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 );
}
}
which was rejected. But as James already pointed out in a comment to this answer at the very least the using statement is a good point.
Solution 2
This site has some pretty good examples across languages: http://jokecamp.wordpress.com/2012/10/21/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/
The c# implementation at the time of writing is:
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);
}
}
Solution 3
Try this:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.hmacsha1.aspx
quick and dirty 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();
}
jessegavin
I am a Senior Software Developer at Dow Jones. Formerly vmware, Thomson Reuters.
Updated on July 09, 2022Comments
-
jessegavin almost 2 years
I am trying to make use of a REST API using C#. The API creator has provided sample libraries in PHP, Ruby and Java. I am getting hung up on one part of it where I need to generate an
HMAC
.Here's how it is done in the sample libraries they have provided.
PHP
hash_hmac('sha1', $signatureString, $secretKey, false);
Ruby
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;
Here's my attempt in C#.
It is not working.UPDATE: The C# example below works just fine. I found out that the real problem was due to some cross-platform differences in newline characters in mysignatureString
.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();
-
jessegavin about 13 yearsThanks for the answer. However your code returns the string
System.Byte[]
. So I modified the last line toreturn BitConverter.ToString(hashValue).Replace("-","").ToLower()
but I am still unable to get this c# code to generate the same hash as the other languages. -
Roee Gavirel over 12 years
myhmacsha1.ComputeHash(stream).Aggregate
give an error: that Aggregate isn't define for System.array . Am I missing anything? -
VolkerK over 12 yearsDepends on the .net version you're using, see msdn.microsoft.com/en-us/library/bb548651%28v=VS.90%29.aspx
-
Roee Gavirel over 12 yearsho. that's the thing. Thanks.
-
James almost 12 yearsIs the
MemoryStream
necessary here? Can't your code be shortened tomyhmacsha1.ComputeHash(byteArray)
? Also you should consider wrapping your yourHMACSHA1
with ausing
block (and theMemoryStream
if it is required). -
Jason Larke over 11 yearsSuper late but
string.Join("", Array.ConvertAll(hashValue, b => b.ToString("x2")))
should work. -
Joe Schmucker over 3 yearsVolkerK = hero status