C# 中的 RSA 签名以获取许可
RSA signing in C# for licensing
(方法#2)
我需要做一个软件激活机制。所以我最终采用了这个方案:应用程序根据计算机的硬件创建一个唯一的 ID。买家通过电子邮件将此 ID 发给我。我用我的私钥签名,然后发回签名的字符串。应用程序验证字符串(使用包含的 public 密钥对其进行解码并将其与硬件 ID 进行比较)。
到目前为止我已经完成了硬件 ID 并且我已经使用 openssl 创建了密钥(1024 位),这是两个文件 private.pem 和 public.pem.
我尝试应用 http://www.christian-etter.de/?p=771 中描述的解决方案
但是验证总是失败。
代码:
private void Generate_Click(object sender, EventArgs e)
{
byte[] SignedData;
byte[] UnsignedData = Encoding.UTF8.GetBytes(CompID.Text);
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.PersistKeyInCsp = false;
rsa.LoadPrivateKeyPEM(PrivateKey.Text);
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
SignedData = rsa.SignData(UnsignedData, sha1);
ActCode.Text = Encoding.UTF8.GetString(SignedData, 0, SignedData.Length);
}
}
//--------------------------------------------------------------------
private void Verify_Click(object sender, EventArgs e)
{
byte[] UnsignedData = Encoding.UTF8.GetBytes(CompID.Text);
byte[] SignedData = Encoding.UTF8.GetBytes(ActCode.Text);
bool VerifOK;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.PersistKeyInCsp = false;
rsa.LoadPublicKeyPEM(PublicKey.Text);
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
VerifOK = rsa.VerifyData(UnsignedData, sha1, SignedData);
}
if (VerifOK) verif.Text = "verification ok";
else verif.Text = "verification error";
}
您将一些任意字节视为 UTF-8 编码字符串 (SignedData
) 这是不正确的,因为并非所有字节序列都是有效的。我怀疑编码器丢弃了无效字节,导致验证失败。您应该使用 Base64 编码以字符串格式保存二进制数据而不会丢失任何内容。所以这个:
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
SignedData = rsa.SignData(UnsignedData, sha1);
ActCode.Text = Encoding.UTF8.GetString(SignedData, 0, SignedData.Length);
变成
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
SignedData = rsa.SignData(UnsignedData, sha1);
ActCode.Text = Convert.ToBase64String(SignedData);
同样在验证过程中你需要使用Convert.FromBase64String
来获得SignedData
。 CompID 可以使用 UTF-8,因为它是字符串数据,您需要将其转换为二进制形式进行签名。
(方法#2) 我需要做一个软件激活机制。所以我最终采用了这个方案:应用程序根据计算机的硬件创建一个唯一的 ID。买家通过电子邮件将此 ID 发给我。我用我的私钥签名,然后发回签名的字符串。应用程序验证字符串(使用包含的 public 密钥对其进行解码并将其与硬件 ID 进行比较)。
到目前为止我已经完成了硬件 ID 并且我已经使用 openssl 创建了密钥(1024 位),这是两个文件 private.pem 和 public.pem.
我尝试应用 http://www.christian-etter.de/?p=771 中描述的解决方案 但是验证总是失败。
代码:
private void Generate_Click(object sender, EventArgs e)
{
byte[] SignedData;
byte[] UnsignedData = Encoding.UTF8.GetBytes(CompID.Text);
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.PersistKeyInCsp = false;
rsa.LoadPrivateKeyPEM(PrivateKey.Text);
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
SignedData = rsa.SignData(UnsignedData, sha1);
ActCode.Text = Encoding.UTF8.GetString(SignedData, 0, SignedData.Length);
}
}
//--------------------------------------------------------------------
private void Verify_Click(object sender, EventArgs e)
{
byte[] UnsignedData = Encoding.UTF8.GetBytes(CompID.Text);
byte[] SignedData = Encoding.UTF8.GetBytes(ActCode.Text);
bool VerifOK;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.PersistKeyInCsp = false;
rsa.LoadPublicKeyPEM(PublicKey.Text);
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
VerifOK = rsa.VerifyData(UnsignedData, sha1, SignedData);
}
if (VerifOK) verif.Text = "verification ok";
else verif.Text = "verification error";
}
您将一些任意字节视为 UTF-8 编码字符串 (SignedData
) 这是不正确的,因为并非所有字节序列都是有效的。我怀疑编码器丢弃了无效字节,导致验证失败。您应该使用 Base64 编码以字符串格式保存二进制数据而不会丢失任何内容。所以这个:
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
SignedData = rsa.SignData(UnsignedData, sha1);
ActCode.Text = Encoding.UTF8.GetString(SignedData, 0, SignedData.Length);
变成
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
SignedData = rsa.SignData(UnsignedData, sha1);
ActCode.Text = Convert.ToBase64String(SignedData);
同样在验证过程中你需要使用Convert.FromBase64String
来获得SignedData
。 CompID 可以使用 UTF-8,因为它是字符串数据,您需要将其转换为二进制形式进行签名。