在C#中有简单的方法吗?
openssl_sign($input, $output, $privateKey, OPENSSL_ALGO_SHA1)
$input
是要签名的字符串$output
-如果调用成功,则在此变量中返回签名。这是一个字节[] $privateKey
是PEM私钥(字符串)参考:http://php.net/manual/en/function.openssl-sign.php
我从XML中获取input
字符串,它被扁平化,如下所示:
<foo><bar1>qux1</bar1><bar2>qux2</bar2></foo>
我从XML中privateKey
标记的内容中获得了<RSASK>
字符串:
<?xml version="1.0"?>
<bla1>foo</bla1>
<bla2>bar</bla2>
<RSASK>-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAMo8SSYPCvFBDgCqFv8o8UzznvcXO6FwUKmbDFogNIA5yQKTJc8i
VIYt6oXLfes+q5i+4oQWb6MJgTIZvcjmCL8CAQMCQQCG0ttutLH2K16rHA9UxfYz
TRSkuifA9YsbasdLmwCMAJVWbScsJcXdecXfWJJVcFTo5fFf6PIigPACHUZlSo8xb
AiEA9vjXy5u74OBS3ekQdMuKrUv5fi6z+EChhhCclVtFwhMCIQDRoMyppTxAmDDY
24QpFZQm9orgXgeqcg0vVoLCcaqUJQIhAKSl5TJn0pXq4elGCviHscjdUP7JzVAr
FuC1vbjng9a3AiEAi8CIcRjS1brLOz0Cxg5ixKRclZQFHEwIyjmsgaEcYsMCIEFT
oGduMC3vOMtKHEo8SAfDFeirfubo+FAZteQ0pyFF
-----END RSA PRIVATE KEY-----
</RSASK>
答案 0 :(得分:1)
这并不容易:
首先,我需要将输入字符串转换为字节[]
ASCIIEncoding ByteConverter = new ASCIIEncoding();
byte[] inputBytes = ByteConverter.GetBytes(input);
计算其SHA1哈希值
byte[] inputHash = new SHA1CryptoServiceProvider().ComputeHash(inputBytes);
删除RSA PRIVATE KEY的开头和结尾并将其转换为byte []
byte[] privateKeyBytes = Convert.FromBase64String(privateKey
.Replace("-----BEGIN RSA PRIVATE KEY-----", string.Empty)
.Replace("-----END RSA PRIVATE KEY-----", string.Empty)
.Replace("\n", string.Empty));
然后我必须从RSACryptoServiceProvider
创建一个privateKeyBytes
,但必须使用Internet上的一个复杂类:
RSACryptoServiceProvider rsa = RSAUtils.DecodeRSAPrivateKey(privateKeyBytes);
// ^
// Found on Internet
然后我终于可以签名
byte[] output = rsa.SignHash(inputHash, "SHA1");
在Internet上找到的代码:
public class RSAUtils
{
public static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
{
byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
// --------- Set up stream to decode the asn.1 encoded RSA private key ------
MemoryStream mem = new MemoryStream(privkey);
BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading
byte bt = 0;
ushort twobytes = 0;
int elems = 0;
try
{
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if (twobytes == 0x8230)
binr.ReadInt16(); //advance 2 bytes
else
return null;
twobytes = binr.ReadUInt16();
if (twobytes != 0x0102) //version number
return null;
bt = binr.ReadByte();
if (bt != 0x00)
return null;
//------ all private key components are Integer sequences ----
elems = GetIntegerSize(binr);
MODULUS = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
E = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
D = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
P = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
Q = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
DP = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
DQ = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
IQ = binr.ReadBytes(elems);
// ------- create RSACryptoServiceProvider instance and initialize with public key -----
CspParameters CspParameters = new CspParameters();
CspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(1024, CspParameters);
RSAParameters RSAparams = new RSAParameters();
RSAparams.Modulus = MODULUS;
RSAparams.Exponent = E;
RSAparams.D = D;
RSAparams.P = P;
RSAparams.Q = Q;
RSAparams.DP = DP;
RSAparams.DQ = DQ;
RSAparams.InverseQ = IQ;
RSA.ImportParameters(RSAparams);
return RSA;
}
catch (Exception ex)
{
return null;
}
finally
{
binr.Close();
}
}
private static int GetIntegerSize(BinaryReader binr)
{
byte bt = 0;
byte lowbyte = 0x00;
byte highbyte = 0x00;
int count = 0;
bt = binr.ReadByte();
if (bt != 0x02) //expect integer
return 0;
bt = binr.ReadByte();
if (bt == 0x81)
count = binr.ReadByte(); // data size in next byte
else
if (bt == 0x82)
{
highbyte = binr.ReadByte(); // data size in next 2 bytes
lowbyte = binr.ReadByte();
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
count = BitConverter.ToInt32(modint, 0);
}
else
{
count = bt; // we already have the data size
}
while (binr.ReadByte() == 0x00)
{ //remove high order zeros in data
count -= 1;
}
binr.BaseStream.Seek(-1, SeekOrigin.Current); //last ReadByte wasn't a removed zero, so back up a byte
return count;
}
}
测试它是否有效。
Php测试
$input = "<DD><RE>97975000-5</RE><TD>33</TD><F>27</F><FE>2003-09-08</FE><RR>8414240-9</RR><RSR>JORGE GONZALEZ LTDA</RSR><MNT>502946</MNT><IT1>Cajon AFECTO</IT1><CAF version=\"1.0\"><DA><RE>97975000-5</RE><RS>RUT DE PRUEBA</RS><TD>33</TD><RNG><D>1</D><H>200</H></RNG><FA>2003-09-04</FA><RSAPK><M>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</M><E>Aw==</E></RSAPK><IDK>100</IDK></DA><FRMA algoritmo=\"SHA1withRSA\">g1AQX0sy8NJugX52k2hTJEZAE9Cuul6pqYBdFxj1N17umW7zG/hAavCALKByHzdYAfZ3LhGTXCai5zNxOo4lDQ==</FRMA></CAF><TSTED>2003-09-08T12:28:31</TSTED></DD>";
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIBOwIBAAJBANGuDuim8fEI9yuIlkj+MOyp3mWHifoP6a4oWLSBKJSrd3MpEsZdczvL0l7t/e0IU5rF+0gRLnU1Mfvtsw1wYWcCAQMCQQCLyV9FxKFLW09yWw7bVCCdxpRDr7FRX/EexZB4VhsNxm/vtJfDZyYle0Lfy42LlcsXxPm1w6Q6NnjuW+AeBy67AiEA7iMi5q5xjswqq+49RP55o//jqdZL/pC9rdnUKxsNRMMCIQDhaHdIctErN2hCIP9knS3+9zra4R+5jSXOvI+3xVhWjQIhAJ7CF0R0S7SIHHKe04NUURf/7RvkMqm108k74sdnXi3XAiEAlkWk2vc2HM+a1sCqQxNz/098ketqe7NuidMKeoOQObMCIQCkFAMS9IcPcMjk7zI2r/4EEW63PSXyN7MFAX7TYe25mw==\n-----END RSA PRIVATE KEY-----";
openssl_sign($input, $output, $privateKey, OPENSSL_ALGO_SHA1);
echo(base64_encode($output));
PHP输出为:
pqjXHHQLJmyFPMRvxScN7tYHvIsty0pqL2LLYaG43jMmnfiZfllLA0wb32lP+HBJ/tf8nziSeorvjlx410ZImw==
C#测试
string input = "<DD><RE>97975000-5</RE><TD>33</TD><F>27</F><FE>2003-09-08</FE><RR>8414240-9</RR><RSR>JORGE GONZALEZ LTDA</RSR><MNT>502946</MNT><IT1>Cajon AFECTO</IT1><CAF version=\"1.0\"><DA><RE>97975000-5</RE><RS>RUT DE PRUEBA</RS><TD>33</TD><RNG><D>1</D><H>200</H></RNG><FA>2003-09-04</FA><RSAPK><M>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</M><E>Aw==</E></RSAPK><IDK>100</IDK></DA><FRMA algoritmo=\"SHA1withRSA\">g1AQX0sy8NJugX52k2hTJEZAE9Cuul6pqYBdFxj1N17umW7zG/hAavCALKByHzdYAfZ3LhGTXCai5zNxOo4lDQ==</FRMA></CAF><TSTED>2003-09-08T12:28:31</TSTED></DD>";
string privateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIBOwIBAAJBANGuDuim8fEI9yuIlkj+MOyp3mWHifoP6a4oWLSBKJSrd3MpEsZdczvL0l7t/e0IU5rF+0gRLnU1Mfvtsw1wYWcCAQMCQQCLyV9FxKFLW09yWw7bVCCdxpRDr7FRX/EexZB4VhsNxm/vtJfDZyYle0Lfy42LlcsXxPm1w6Q6NnjuW+AeBy67AiEA7iMi5q5xjswqq+49RP55o//jqdZL/pC9rdnUKxsNRMMCIQDhaHdIctErN2hCIP9knS3+9zra4R+5jSXOvI+3xVhWjQIhAJ7CF0R0S7SIHHKe04NUURf/7RvkMqm108k74sdnXi3XAiEAlkWk2vc2HM+a1sCqQxNz/098ketqe7NuidMKeoOQObMCIQCkFAMS9IcPcMjk7zI2r/4EEW63PSXyN7MFAX7TYe25mw==\n-----END RSA PRIVATE KEY-----";
ASCIIEncoding ByteConverter = new ASCIIEncoding();
byte[] inputBytes = ByteConverter.GetBytes(input);
byte[] inputHash = new SHA1CryptoServiceProvider().ComputeHash(inputBytes);
byte[] privateKeyBytes = Convert.FromBase64String(privateKey
.Replace("-----BEGIN RSA PRIVATE KEY-----", string.Empty)
.Replace("-----END RSA PRIVATE KEY-----", string.Empty)
.Replace("\n", string.Empty));
RSACryptoServiceProvider rsa = RSAUtils.DecodeRSAPrivateKey(privateKeyBytes);
byte[] output = rsa.SignHash(inputHash, "SHA1");
Console.WriteLine(Convert.ToBase64String(output));
C#输出为:
pqjXHHQLJmyFPMRvxScN7tYHvIsty0pqL2LLYaG43jMmnfiZfllLA0wb32lP+HBJ/tf8nziSeorvjlx410ZImw==