HMAC Signing Example in C#

Veracode APIs

This is a C# example of how to enable HMAC signing within your application shows how to authenticate when using the Veracode APIs.

You can download the code for this example from tools.veracode.com/integrations/Microsoft/Microsoft/VisualStudio/update/Veracode.HmacExample.zip.

HmacAuthHeader.cs

 using System;
 using System.Runtime.Remoting.Metadata.W3cXsd2001;
 using System.Security.Cryptography;
 using System.Text;
 using System.Text.RegularExpressions;

 namespace Veracode.HmacExample.App {
   public abstract class HmacAuthHeader {
     private static readonly RNGCryptoServiceProvider RngRandom = new RNGCryptoServiceProvider();

     public static readonly HmacAuthHeader HmacSha256 = new HmacSha256AuthHeader();

     private sealed class HmacSha256AuthHeader: HmacAuthHeader {
       protected override string GetHashAlgorithm() {
         return "HmacSHA256";
       }

       protected override string GetAuthorizationScheme() {
         return "VERACODE-HMAC-SHA-256";
       }

       protected override string GetRequestVersion() {
         return "vcode_request_version_1";
       }

       protected override string GetTextEncoding() {
         return "UTF-8";
       }

       protected override int GetNonceSize() {
         return 16;
       }

       internal HmacSha256AuthHeader() {}
     }

     protected abstract string GetHashAlgorithm();
     protected abstract string GetAuthorizationScheme();
     protected abstract string GetRequestVersion();
     protected abstract string GetTextEncoding();
     protected abstract int GetNonceSize();

     protected string CurrentDateStamp() {
       return ((long)((TimeSpan)(DateTime.UtcNow - new DateTime(1970, 1, 1))).TotalMilliseconds).ToString();
     }

     protected byte[] NewNonce(int size) {
       byte[] nonceBytes = new byte[size];
       RngRandom.GetBytes(nonceBytes);

       return nonceBytes;
     }

     protected byte[] ComputeHash(byte[] data, byte[] key) {
       HMAC mac = HMAC.Create(GetHashAlgorithm());
       mac.Key = key;

       return mac.ComputeHash(data);
     }

     protected byte[] CalculateDataSignature(byte[] apiKeyBytes, byte[] nonceBytes, string dateStamp, string data) {
       byte[] kNonce = ComputeHash(nonceBytes, apiKeyBytes);
       byte[] kDate = ComputeHash(Encoding.GetEncoding(GetTextEncoding()).GetBytes(dateStamp), kNonce);
       byte[] kSignature = ComputeHash(Encoding.GetEncoding(GetTextEncoding()).GetBytes(GetRequestVersion()), kDate);

       return ComputeHash(Encoding.GetEncoding(GetTextEncoding()).GetBytes(data), kSignature);
     }

     public string CalculateAuthorizationHeader(string apiId, string apiKey, string hostName, string uriString, string urlQueryParams, string httpMethod) {
       try {
         if (urlQueryParams != null) {
           uriString += (urlQueryParams);
         }
         string data = $ "id={apiId}&host={hostName}&url={uriString}&method={httpMethod}";
         string dateStamp = CurrentDateStamp();
         byte[] nonceBytes = NewNonce(GetNonceSize());
         byte[] dataSignature = CalculateDataSignature(FromHexBinary(apiKey), nonceBytes, dateStamp, data);
         string authorizationParam = $ "id={apiId},ts={dateStamp},nonce={ToHexBinary(nonceBytes)},sig={ToHexBinary(dataSignature)}";

         return GetAuthorizationScheme() + " " + authorizationParam;
       } catch (Exception e) {
         throw new Exception(e.Message, e);
       }
     }

     public static string ToHexBinary(byte[] bytes) {
       return new SoapHexBinary(bytes).ToString();
     }

     public static byte[] FromHexBinary(string hexBinaryString) {
       return SoapHexBinary.Parse(hexBinaryString).Value;
     }

     public static bool IsValidHexBinary(string hexBinaryString) {
       if (hexBinaryString != null) {
         try {
           byte[] bytes = FromHexBinary(hexBinaryString);
           return bytes != null;
         } catch (Exception) {}
       }

       return false;
     }

     public static bool IsValidAuthHeaderToken(string authHeaderToken) {
       if (authHeaderToken != null) {
         // For valid Authorization header token syntax see https://www.ietf.org/rfc/rfc2617.txt, https://www.ietf.org/rfc/rfc2068.txt
         bool isMatch = Regex.IsMatch(authHeaderToken, "^[\\x21\\x23-\\x27\\x2A-\\x2B\\x2D-\\x2E\\x30-\\x39\\x41-\\x5A\\x5E-\\x7A\\x7C\\x7E]+$");

         return isMatch;
       }

       return false;
     }

     private HmacAuthHeader() {}
   }
 }

Program.cs

using System;
using System.Net;

namespace Veracode.HmacExample.App {
  public class Program {
    private
    const string AuthorizationHeader = "Authorization";
    private
    const string ApiId = "VERACODE_API_ID_GOES_HERE";
    private
    const string ApiKey = "VERACODE_SECRET_KEY_GOES_HERE";

    public static void Main(string[] args) {
      try {
        const string urlBase = "analysiscenter.veracode.com";
        const string urlPath = "/api/5.0/getapplist.do";
        var urlParams = string.Empty;
        const string httpVerb = "GET";

        var webClient = new WebClient {
          BaseAddress = $ "https://{urlBase}"
        };

        var authorization = HmacAuthHeader.HmacSha256.CalculateAuthorizationHeader(ApiId, ApiKey, urlBase, urlPath, urlParams, httpVerb);

        webClient.Headers.Add(AuthorizationHeader, authorization);

        var result = webClient.DownloadString(urlPath);

        Console.WriteLine(result);
      } catch (Exception ex) {
        Console.WriteLine(ex.Message);
      } finally {
        Console.WriteLine("Press any key to continue.");
        Console.ReadKey();
      }
    }
  }
}