Skip to main content

C# HMAC signing example

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

You can download the code for this example from Veracode Tools.

HmacAuthHeader.cs

using System;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace Veracode.HmacExample.App.Core_50
{
public abstract class HmacAuthHeader
{
private static readonly RandomNumberGenerator RngRandom = RandomNumberGenerator.Create();

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 static byte[] NewNonce(int size)
{
var 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)
{
var kNonce = ComputeHash(nonceBytes, apiKeyBytes);
var kDate = ComputeHash(Encoding.GetEncoding(GetTextEncoding()).GetBytes(dateStamp), kNonce);
var kSignature = ComputeHash(Encoding.GetEncoding(GetTextEncoding()).GetBytes(GetRequestVersion()), kDate);

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

public string CreateSigningData(string id, string host, string url, string method)
{
var idTokens = id.Split('-');
var hexId = idTokens[idTokens.Length - 1];
var result = $"id={hexId.ToLower()}&host={host.ToLower()}&url={url}&method={method.ToUpper()}";
return result.ToString(CultureInfo.GetCultureInfo("en-US"));
}


public string CalculateAuthorizationHeader(string apiId, string apiKey, string hostName, string uriString, string urlQueryParams, string httpMethod)
{
if (string.IsNullOrEmpty(urlQueryParams))
uriString += (urlQueryParams);

if (string.IsNullOrEmpty(apiId) || string.IsNullOrEmpty(apiKey) || string.IsNullOrEmpty(hostName) ||
string.IsNullOrEmpty(uriString) || string.IsNullOrEmpty(httpMethod))
throw new ArgumentException("Null or Empty value provided");

var data = CreateSigningData(apiId, hostName, uriString, httpMethod);
var dateStamp = CurrentDateStamp();
var nonceBytes = NewNonce(GetNonceSize());

var kToken = apiKey.Split("-");
var key = kToken[kToken.Length - 1];
var dataSignature = CalculateDataSignature(FromHexBinary(key), nonceBytes, dateStamp, data);

var idToken = apiId.Split("-");
var hexId = idToken[idToken.Length - 1];
var authorizationParam = $"id={hexId},ts={dateStamp},nonce={ToHexBinary(nonceBytes)},sig={ToHexBinary(dataSignature)}";

return GetAuthorizationScheme() + " " + authorizationParam;
}

public static string ToHexBinary(byte[] bytes)
{
return Convert.ToHexString(bytes);
}

public static byte[] FromHexBinary(string hexBinaryString)
{
return Convert.FromHexString(hexBinaryString);
}

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

return false;
}

public static bool IsValidAuthHeaderToken(string authHeaderToken)
{
if (string.IsNullOrEmpty(authHeaderToken))
{
// For valid Authorization header token syntax see https://www.ietf.org/rfc/rfc2617.txt, https://www.ietf.org/rfc/rfc2068.txt
var 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.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;

namespace Veracode.HmacExample.App.Core_50
{
public class Program
{
private const string AuthorizationHeader = "Authorization";

public static void Main(string[] args)
{
try
{
const string urlBase = "analysiscenter.veracode.com";

var getapp = GetAppList(urlBase).GetAwaiter().GetResult();
Console.WriteLine(getapp);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.ReadKey();
}
}

public async static Task<string> GetAppList(string baseUrl)
{
const string urlPath = "/api/5.0/getapplist.do";
var urlParams = string.Empty;
const string httpVerb = "GET";
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile($"appsettings.json", true, true)
.Build();
var ApiId = config["settings:apiId"];
var ApiKey = config["settings:apiKey"];

using (var client = new HttpClient())
{
var uri = $"https://{baseUrl}";
client.BaseAddress = new Uri(uri, UriKind.Absolute);

var authHeader = HmacAuthHeader.HmacSha256.CalculateAuthorizationHeader(ApiId, ApiKey, baseUrl, urlPath, urlParams, httpVerb);
client.DefaultRequestHeaders.Add(AuthorizationHeader, authHeader);

using (var response = await client.GetAsync(urlPath).ConfigureAwait(false))
{
return await response.Content.ReadAsStringAsync();
}
}
}
}
}

appsettings.json

{
"settings": {
"apiId": "VERACODE_SECRET_ID_GOES_HERE",
"apiKey": "VERACODE_SECRET_KEY_GOES_HERE"
}
}