在C#中为HMAC SHA1生成公钥和密钥

时间:2012-12-04 13:14:25

标签: c# asp.net asp.net-mvc-3 hmacsha1

我想在Asp.Net MVC 3上为REST API服务的HMAC-SHA签名算法实现AWS。是否有任何最佳实践来生成用户的公钥和秘密?

1 个答案:

答案 0 :(得分:5)

我们已经建立了一个类似的系统。 @James引用的question提供了非常好的信息。一定要读它。如果可能,仅通过SSL / TLS部署您的服务。

使用HMAC-SHA签名,您不需要公钥。服务器(服务)和用于计算签名的客户端共享一个密钥。根据上面引用的安全站点上的问题,确保每个客户端都有不同的密钥。

对于每个客户端,您还应该具有某种服务客户端ID,这与您必须识别客户端的任何其他ID不同。此服务客户端ID在请求标头中发送,因此您可以标识客户端。一旦确定了客户端,就可以获得有关客户端的必要信息,包括客户端的服务密钥。

除了服务客户端ID之外,请求标头还应包含生成的实际签名。我还建议在标题中加入一个时间戳(下面有更多内容)。因此,您的请求将包含与以下内容类似的标题:

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

要使用.NET / C#生成客户端密钥,您可以创建一个方法,生成可以传递给客户端的Rijndael密钥的字符串表示。这是一个例子。

    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();
    }

在我们的系统中,当启用新服务客户端时,将生成服务客户端ID和服务密钥,并将其存储在客户端的数据库中。服务客户端ID可以只是GUID。

客户端的服务密钥是您和客户之间的共享密钥。仅通过安全机制将其传递给客户端,例如在SSL / TLS上运行的网站的经过身份验证的部分。否则,你会向其他人开放获取密钥。

时间戳应由客户端生成,并包含在要从中生成签名的字符串中。这增加了签名的时间特定可变性。 AWS也是这样做的。

关于要签名的字符串,在您身边我还建议您定义一个接口,您可以编程以在与请求签名进行比较时构建要签名的字符串。这将允许您构建不同的服务甚至不同的操作的不同实现。这对我们的实施很有用。这是一个例子:

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

然后,您可以构建满足您需求的IStringToSignBuilder的特定实现,并相应地将正确的实现注入到您的代码中。