我一直在努力查看C#RSACryptoServiceProvider如何签署数据,或者找到有关如何签署数据的任何文档。
我已尝试遵循指定的here签名方案,但我似乎无法生成符合.NET实施的签名。
RSACryptoServiceProvider究竟是如何生成签名的,或者为什么我的任何manualSignedDatas都不匹配下面示例代码中的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://tools.ietf.org/html/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;
}
答案 0 :(得分:0)
你有......相当多的错误。对于初学者,您的EmsaPkcs1V1_5Encode_SHA256函数向后构建digestInfo变量(您使用digestAlgorithm
作为后缀,当它应该是前缀时)。您也应该在RSASP1
中使用OS2IP,因为您向后调用了BigInteger ctor。
重点:
这是一个为您准备的例子。 byte []值以十六进制表示,BigInteger值(OS2IP输出)以十进制表示。使用上面的项目符号和RFC 3447,您应该能够匹配它。
Generated Key:
n:
C2311FC5FA31D333A409BB4CE95B20D21CFCE3753871725653A28425AF6DE97DF
2020B23633F458DF12A63627121BFF4E23CE5787E077898057861D1AE60AC2F
e: 010001
d:
0D916719EB103E24768AA3868D2B6BD0A26BDCEC9CC3F86C25ADCE33DFDCFB1A4
D503E073D7FF5FD748E43F8DF02A60ED73053143E591E708DF72C2793E22B69
p: F7EF37E67FA6685AC1788B01CF38DA20CA4BDE5D8B01A71BD28C65B409C36E4D
q: C88257603FB8A5E25E9DDB553A73B647A3ECA6E9ABC6C440DBC705F82ED4DA6B
dp: 72E79E0BA85B51FFC5AC7D17F096D398E0C87A9CF5C0655722A448BA40D01EFD
dq: 4C0CABC954C1DB211DD3EFB1C6C6C6972B8481D65511C1B3FBE7E3CABB307E5B
iq: B94CB9F83D4C145BE43EA96509FF187176F72E9B82F91B8BC49121FB6B9990F0
data: 01010203
hash (SHA256):
9184ABD2BB318731D717E972057240EAE26CCA202A8D35DBE9D2176F526886A0
EMSA_PKCS1_V1_5_ENCODE: T=
3031300D0609608648016503040201050004209184ABD2BB318731D717E9720572
40EAE26CCA202A8D35DBE9D2176F526886A0
EMSA_PKCS1_V1_5_ENCODE: EM=
0001FFFFFFFFFFFFFFFFFFFF003031300D060960864801650304020105000420918
4ABD2BB318731D717E972057240EAE26CCA202A8D35DBE9D2176F526886A0
OS2IP: x=
4091738259870177337516485429975660299381480466173929813897514081197
4001006075637088431241046394626562124424487751622623819494959348458
9402025699608224
RSASP1: n=
1017065459787822195711481708900267786564376023809569193509899981293
9461386629891828226910128922059886444866797206179548218910539391071
517068232388857867311
RSASP1: d=
7106127440023861077197422440841549345679963704508929821447170322634
5108395833416072981045532865581744327586076884716186753729887110610
3233084086814911337
RSASP1: s=
4575492210354332473521217556428951379558271601925254480118287259959
6454886403001827141625402256685452319478955175598933868230853388418
44638909194871101390
I2OSP: X=
575C8A4109ED6EA2A7086338D150A5BB8205142E778547B50CC6019868070243BF4
9DE7C60390160E392FACA18F4A05D3A7A88A4DE86DD99F030EB4AA755D7CE
rsa.SignHash:
575C8A4109ED6EA2A7086338D150A5BB8205142E778547B50CC6019868070243B
F49DE7C60390160E392FACA18F4A05D3A7A88A4DE86DD99F030EB4AA755D7CE
Manual:
575C8A4109ED6EA2A7086338D150A5BB8205142E778547B50CC6019868070243B
F49DE7C60390160E392FACA18F4A05D3A7A88A4DE86DD99F030EB4AA755D7CE