Question

I would like to implement AWS like HMAC-SHA Signature algorithm for REST API service on Asp.Net MVC 3. Are there any best practices to generate user's public key and secret?

Was it helpful?

Solution

We've built a similar system. The question that @James references gives very good information. Be sure to read it. If possible, only deploy your service over SSL/TLS.

With HMAC-SHA signature you don't need a public key. There is one secret key shared by the server (service) and the client that is used to compute the signature. Per the question on the security site referenced above, make sure you have different keys for each client.

For each client you should also have service client id of some sort that is different than any other Ids you have to identify the client. This service client id is sent in the request header so you can identify the client. Once you've identified the client, you can obtain the required information about the client including the client's service key.

In addition to the service client id, the request header should contain the actual signature that was generated. I would also recommend including a time stamp in the header as well (more on this below). So your request would have headers similar to these:

MySvc-Clientid: ServiceId
MySvc-Signature: Signature
MySvc-Timestamp: TimeStamp

To generate client keys using .NET/C# you can create a method that generates a string representation of a Rijndael key which can be delivered to the client. Here is an example.

    public string CreateServiceClientKey()
    {
        SymmetricAlgorithm symAlg = SymmetricAlgorithm.Create("Rijndael");

        symAlg.KeySize = 128;

        byte[] key = symAlg.Key;

        StringBuilder sb = new StringBuilder(key.Length * 2);

        foreach (byte b in key)
        {
            sb.AppendFormat("{0:x2}", b);
        }

        return sb.ToString();
    }

In our system, when a new service client is enabled, a service client id and service key are generated and stored in the database for the client. The service client id could just be a GUID.

The client's service key is a shared secret between you and the client. Only deliver it to the client via a secure mechanism, such as a authenticated portion of your website running on SSL/TLS. Otherwise, you open yourself up to someone else obtaining the secret key.

The timestamp should be generated by the client and be included in the string to sign from which the signature is generated. This adds time specific variability to the signature. AWS does this as well.

In regard to the string to sign, on your side I'd also recommend defining an interface that you program to for building your string to sign when comparing against the request signature. This will allow you to build to different implementations for different services or even different operations. This came in handy for our implementation. Here is an example:

public interface IStringToSignBuilder
{
    string Build(ServiceSignatureDetails details);
}

/// <summary>
/// Class is a data entity that defines the specific details
/// required for a Service Signature
/// </summary>
public class ServiceSignatureDetails
{
    public string HttpMethod { get; set; }
    public string ServiceClientId { get; set; }
    public string ServiceClientKey { get; set; }
    public string UriAbsolutePath { get; set; }
    public string DomainName { get; set; }
    public string CompanyName { get; set; }
    public string DateTimeStamp { get; set; }
    public string Data { get; set; }
}

You can then build specific implementations of IStringToSignBuilder that meet your needs and inject the correct one into your code accordingly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top