Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate HMAC-SHA1 in C#?

Tags:

java

c#

php

ruby

hmac

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 my 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(); 
like image 219
jessegavin Avatar asked May 20 '11 05:05

jessegavin


People also ask

Is SHA1 a HMAC?

Remarks. HMACSHA1 is a type of keyed hash algorithm that is constructed from the SHA1 hash function and used as an HMAC, or hash-based message authentication code.

Is SHA1 secure for HMAC?

Description. The remote SSH server is configured to enable SHA-1 HMAC algorithms. Although NIST has formally deprecated use of SHA-1 for digital signatures, SHA-1 is still considered secure for HMAC as the security of HMAC does not rely on the underlying hash function being resistant to collisions.

Is hmacsha256 stronger than SHA1?

To the best of our knowledge, there is essentially no security difference between HMAC-SHA256 and HMAC-SHA1; with a sufficiently long key, both are impervious to brute force, and with a reasonably long tag, both will catch any forged messages with the expected probability.

Is HMAC deprecated?

Additional Information. NetSuite is deprecating the HMAC-SHA1 signature algorithm as a valid signature method for token-based authentication (TBA) as of these versions: Non-Production Accounts: NetSuite version 2021.2 and later. Production Accounts: NetSuite version 2023.1 and later.


1 Answers

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.

like image 169
VolkerK Avatar answered Oct 01 '22 11:10

VolkerK