【发布时间】:2017-05-13 08:21:03
【问题描述】:
我一直在努力了解 C# 的 RSACryptoServiceProvider 究竟是如何签署数据的,或者寻找任何关于它如何签署数据的文档。
我尝试遵循here 指定的签名方案,但似乎无法生成与 .NET 实现匹配的签名。
RSACryptoServiceProvider 究竟是如何生成签名的,或者为什么我的任何 manualSignedData 都不匹配下面示例代码中的 RSACryptoServiceProviderSignedData?
public void ManualSignatureTest(byte[] data, X509Certificate2 cert)
{
var sha256 = new SHA256CryptoServiceProvider();
var rsa = (RSACryptoServiceProvider)cert.PrivateKey;
var RSACryptoServiceProviderSignedData = rsa.SignData(data, "SHA256");
var manualSignedDataLittle = ManualSignDataSha256(data, rsa, true, false);
var manualSignedDataBig = ManualSignDataSha256(data, rsa, false, false);
//https://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider(v=vs.110).aspx
//the RSACryptoServiceProvider class reverses the order of an encrypted array of bytes after encryption and before decryption
var manualSignedDataReversedLittle = ManualSignDataSha256(data, rsa, true, true);
var manualSignedDataReversedBig = ManualSignDataSha256(data, rsa, false, true);
}
public byte[] ManualSignDataSha256(byte[] data, RSACryptoServiceProvider rsa, bool littleEndian, bool reverseArray)
{
//https://www.rfc-editor.org/rfc/rfc8017#section-8.2.1
//EM = EMSA-PKCS1-V1_5-ENCODE (M, k)
var emsaEncodedMessage = EmsaPkcs1V1_5Encode_SHA256(data, 245);
if (reverseArray) Array.Reverse(emsaEncodedMessage);
//m = OS2IP (EM)
var intMessageRepresentative = OS2IP(emsaEncodedMessage, littleEndian);
//s = RSASP1 (K, m)
var intSignatureRepresentative = RSASP1(rsa, intMessageRepresentative);
//S = I2OSP (s, k)
var signature = I2OSP(intSignatureRepresentative, 256, littleEndian);
return signature;
}
public byte[] HexToByte(string hex)
{
return Enumerable.Range(0, hex.Length / 2).Select(x => Convert.ToByte(hex.Substring(x * 2, 2), 16)).ToArray();
}
public byte[] EmsaPkcs1V1_5Encode_SHA256(byte[] message, int emLen)
{
var digest = new SHA256CryptoServiceProvider().ComputeHash(message);
var digestAlgorithm = HexToByte("3031300d060960864801650304020105000420");
var digestInfo = digest.Concat(digestAlgorithm).ToArray();
var paddingLength = emLen - digestInfo.Length - 3;
var paddingHexString = "";
for (int i = 0; i < paddingLength; i++)
{
paddingHexString += "FF";
}
return HexToByte("0001" + paddingHexString + "00").Concat(digestInfo).ToArray();
}
public BigInteger OS2IP(byte[] data, bool isLittleEndian)
{
BigInteger bi = 0;
if (isLittleEndian)
{
for (int i = 0; i < data.Length; i++)
{
bi += BigInteger.Pow(256, i) * data[i];
}
}
else
{
for (int i = 1; i <= data.Length; i++)
{
bi += BigInteger.Pow(256, i - 1) * data[data.Length - i];
}
}
return bi;
}
public BigInteger RSASP1(RSACryptoServiceProvider rsa, BigInteger message)
{
var keyParameters = rsa.ExportParameters(true);
var n = new BigInteger(keyParameters.Modulus);
var d = new BigInteger(keyParameters.D);
return BigInteger.ModPow(message, d, n);
return default(BigInteger);
}
public byte[] I2OSP(BigInteger x, int xLen, bool makeLittleEndian)
{
byte[] result = new byte[xLen];
int index = 0;
while ((x > 0) && (index < result.Length))
{
result[index++] = (byte)(x % 256);
x /= 256;
}
if (!makeLittleEndian)
Array.Reverse(result);
return result;
}
【问题讨论】:
-
C# 调用在哪里?你不是把它和PSS比较错了吗?我没有看到任何示例输入、输出或您尝试过的东西(例如打印出十六进制的中间值并验证它们)。
标签: c# encryption cryptography certificate rsa