困惑,如何使用密钥并对称地签署文档?

时间:2011-01-18 06:41:17

标签: c# encryption

我试图找出如何在c#中执行以下操作。

发表了几次关于这一点似乎非常令人困惑。我有一个xml文档,我希望能够对称地签署文档,并在最后创建一个签名。

首先:

需要使用

创建签名

1)文档中的数据 2)唯一键(我们创建的字或字节数组)

然后我需要编写一个程序,它会使用上面的数据和密钥发出我们可以随文档一起提供的签名。

第二

在另一端,客户将运行具有唯一密钥的程序(上面的步骤2中的密钥),它将查看我们发送的签名。然后它将能够判断数据是否使用该密钥签名。如果数据已更改,则测试将失败。这样我们就知道客户没有篡改xml文件。

注意:我不认为这不是非常安全,但现在对我们来说已经足够了。

这是怎么做到的?似乎无法获得加密的基础知识: - )

2 个答案:

答案 0 :(得分:2)

你应该看一下MAC(消息认证码) https://secure.wikimedia.org/wikipedia/en/wiki/Message_authentication_code

没有必要不安全。问题在于密钥的每一个都可以创建有效的签名。这意味着每个必须能够验证签名的人也可以创建它们,而您无法确定谁实际签署了数据。

答案 1 :(得分:0)

对于“相当不错”的安全性,我建议HMAC-SHA1使用至少160位(20字节)长的密钥。要了解更高级的加密技术,我强烈推荐经典的Schneier书籍Applied Cryptography

要生成HMAC,您可以使用方便的HMACSHA1类。

例如:

/// Pass in the xml text to sign, along with a hex or Base64-encoded, 160-bit secret key
public string GenerateSignature(string xml, string secretKey)
{
  using (HMACSHA1 encoder = new HMACSHA1(secretKey.ToAscii(), true))
  {
    return encoder.ComputeHash(xml.ToUtf8()).ToBase64();
  }
}

...使用这些扩展方法:

public static byte[] ToUtf8(this string str)
{
  return Encoding.UTF8.GetBytes(str);
}

public static byte[] ToAscii(this string str)
{
  return Encoding.ASCII.GetBytes(str);
}

public static string ToBase64(this byte[] bytes)
{
  return Convert.ToBase64String(bytes);
}

要生成密钥,您可以转到random.org(不完全安全,但可能已满足您的需求),或者以编程方式执行此操作:

System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
byte[] key = new byte[20];

rng.GetBytes(key);
string secretKey = key.ToBase64()

以下是您可能会找到的更多扩展方法:

public static string ToHex(this byte[] bytes)
{
  char[] c = new char[bytes.Length * 2];

  byte b;

  for(int bx = 0, cx = 0; bx < bytes.Length; ++bx, ++cx) 
  {
    b = ((byte)(bytes[bx] >> 4));
    c[cx] = (char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30);

    b = ((byte)(bytes[bx] & 0x0F));
    c[++cx]=(char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30);
  }

  return new string(c);
}

public static byte[] HexToBytes(this string str)
{
  if (str.Length == 0 || str.Length % 2 != 0)
    return new byte[0];

  byte[] buffer = new byte[str.Length / 2];
  char c;
  for (int bx = 0, sx = 0; bx < buffer.Length; ++bx, ++sx)
  {
    // Convert first half of byte
    c = str[sx];
    buffer[bx] = (byte)((c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0')) << 4);

    // Convert second half of byte
    c = str[++sx];
    buffer[bx] |= (byte)(c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0'));
  }

  return buffer;
}