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"
}
}