I am running the following code in order to sign a string in c# using an rsa private key. I extracted the private key from an X.509 certificate and converted it with openssl rsa command.
public static byte[] doSign(string text)
{
RSACryptoServiceProvider csp = CreateRsaProviderFromPrivateKey(File.ReadAllText(@"Security\private.pem"));
SHA1Managed sha1 = new SHA1Managed();
byte[] data = Encoding.ASCII.GetBytes(text);
byte[] hash = sha1.ComputeHash(data);
return csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));
}
private static RSACryptoServiceProvider CreateRsaProviderFromPrivateKey(string privateKey)
{
List<string> lines = privateKey.Split('\n').ToList();
string key = string.Join("",
(
from s in lines
where !string.IsNullOrEmpty(s) && s[0] != '-'
select s
).ToList().ToArray()).Replace("\n", "").Replace("\r", "");
var privateKeyBits = System.Convert.FromBase64String(key);
var RSA = new RSACryptoServiceProvider();
var RSAparams = new RSAParameters();
using (BinaryReader binr = new BinaryReader(new MemoryStream(privateKeyBits)))
{
byte bt = 0;
ushort twobytes = 0;
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130)
binr.ReadByte();
else if (twobytes == 0x8230)
binr.ReadInt16();
else
throw new Exception("Unexpected value read binr.ReadUInt16()");
twobytes = binr.ReadUInt16();
if (twobytes != 0x0102)
throw new Exception("Unexpected version");
bt = binr.ReadByte();
if (bt != 0x00)
throw new Exception("Unexpected value read binr.ReadByte()");
RSAparams.Modulus = binr.ReadBytes(GetIntegerSize(binr));
RSAparams.Exponent = binr.ReadBytes(GetIntegerSize(binr));
RSAparams.D = binr.ReadBytes(GetIntegerSize(binr));
RSAparams.P = binr.ReadBytes(GetIntegerSize(binr));
RSAparams.Q = binr.ReadBytes(GetIntegerSize(binr));
RSAparams.DP = binr.ReadBytes(GetIntegerSize(binr));
RSAparams.DQ = binr.ReadBytes(GetIntegerSize(binr));
RSAparams.InverseQ = binr.ReadBytes(GetIntegerSize(binr));
}
RSA.ImportParameters(RSAparams);
return RSA;
}
I am then converting the signed string to an hexadecimal string and send it to a php page:
private void toPhp(string timestamp)
{
string data = idMachine + numberOfSignal + timestamp;
//string signature = new Sign().IngApiGetToken(data);
byte[] signatureBytes = Sign.doSign(data);
string signature = Sign.toHex(Encoding.UTF8.GetString(signatureBytes));
using (HttpClient client = new HttpClient())
{
string uri = "http://localhost/GCS/";
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("data", data),
new KeyValuePair<string, string>("signature", signature)
});
var res = client.PostAsync(uri, formContent).Result.Content.ReadAsStringAsync().Result;
//textBox1.Text += "Hex: " + signature;
textBox1.Text += Environment.NewLine;
textBox1.Text += "---- Sending request to PHP ----";
textBox1.Text += Environment.NewLine;
textBox1.Text += res;
}
}
The php page verifies the signed string using the certificate and tries to sign itself the original data:
$data = $_POST["data"];
$signature = $_POST["signature"];
$bin = $_POST["bin"];
if(!isset($_POST['bin'])){
$signature = hex2bin($signature);
}
$pub_key = openssl_pkey_get_public("file://cert.pem");
echo "Data: ";
echo $data;
echo "\r\nSignature: ";
echo $signature;
echo "\r\nSignature to hex: ";
echo strtoupper(bin2hex($signature));
echo "\r\nResult: ";
echo openssl_verify ( $data , $signature , $pub_key);
//Re-sign
$res = openssl_get_privatekey("file://private.pem");
openssl_sign($data, $newSignature, $res);
$hex = strtoupper(bin2hex($newSignature));
echo "\r\nString signed hex: $newSignature";
echo "\r\nString signed hex: $hex";
echo "\r\nResult: ";
echo openssl_verify ( $data , $newSignature , $pub_key);
echo "\r\nComparing signed: ";
echo strcmp ($signature,$newSignature);
Below you can see the result printed by the php echos. As you can see, the signed strings are apparently identical, but the hexadecimal values are different.
---- Sending request to PHP ---- Data: 22-530057097401597056984 Signature: B���p E]%��.qנ�[��؋�� GX�%0�!f-�e"�+�Ӎ�lf�q�^��!����yN51�C�!��V�n�i���eECx������Q�=H33���9�#��Aw�ݘ�sa=f=6A�~��u��i/ui6�[�Z�F�+DБH����N�K�-/v�=�I�HM7� |Ҧ��e/v�����}vxB,k��Z4s�E��$ߘ�rVU^^}�:�)i�������X��"�68�X�Ӝ2{{sH Signature to hex: 42EFBFBDEFBFBDEFBFBD700D45175D250CEFBFBDEFBFBD2E0371D7A0EFBFBD5BEFBFBDEFBFBDD88BEFBFBDEFBFBD0D4758EFBFBD2530EFBFBD21662DEFBFBD106522EFBFBD2BEFBFBDD38DEFBFBD6C66EFBFBD71EFBFBD5EEFBFBD1FEFBFBD2110EFBFBDEFBFBDEFBFBDEFBFBD794E3531EFBFBD7F43EFBFBD21EFBFBDEFBFBD56EFBFBD6EEFBFBD69EFBFBDEFBFBDEFBFBD6545430578EFBFBDEFBFBDEFBFBDEFBFBDEFBFBD1613EFBFBD0C0251EFBFBD3D483333EFBFBDEFBFBDEFBFBD39EFBFBD23EFBFBDEFBFBD4177EFBFBDDD98EFBFBD7302613D663D3641EFBFBD7EEFBFBD11EFBFBD751AEFBFBDEFBFBD692F04756936EFBFBD5B111BEFBFBD5AEFBFBD0546EFBFBD2B44D09148EFBFBDEFBFBD04EFBFBDEFBFBD4EEFBFBD4BEFBFBD2D2F76EFBFBD3DEFBFBD49EFBFBD12484D37EFBFBD0A7CD2A6EFBFBDEFBFBD652F76EFBFBDEFBFBD1CEFBFBDEFBFBDEFBFBD7D7678422C106BEFBFBDEFBFBD5A3473EFBFBD45EFBFBDEFBFBD24DF98EFBFBD7256555E5E7DEFBFBD053AEFBFBD0B142969EFBFBDEFBFBDEFBFBDEFBFBDEFBFBDEFBFBDEFBFBD58EFBFBDEFBFBD2218EFBFBD3638EFBFBD58EFBFBDD39C327B7B1D13731348 Result: 0 String signed hex: B���p E]%��.qנ�[��؋�� GX�%0�!f-�e"�+�Ӎ�lf�q�^��!����yN51�C�!��V�n�i���eECx������Q�=H33���9�#��Aw�ݘ�sa=f=6A�~��u��i/ui6�[�Z�F�+DБH����N�K�-/v�=�I�HM7� |Ҧ��e/v�����}vxB,k��Z4s�E��$ߘ�rVU^^}�:�)i�������X��"�68�X�Ӝ2{{sH String signed hex: 4289AAE2700D45175D250C85ED9C2E0371D7A0D45BAEDDD88BA2F70D4758DC2530EC21662DA6106522E62BC2D38DAA6C668671975EF481BE1F8921108796ABBA794E3531C27F43BF2196DA56D96EB269B490B36545430578BDFA9CE2D91613850C0251D53D4833338FFDEF398D239FBD4177FCDD98A67302613D663D3641EB7EB611D8751ADAE6692F04756936B75B111B8D5AEB860546F92B44D0914888CB04F8EC4EA14BBC2D2F76AC3D84498D12484D37D30A7CD2A6C4ED652F76DAF11CD1F7A97D7678422C106B9B965A3473CC45819724DF98B77256555E5E7D87053ACD0B142969868ED5C0A3CDE65898D122188E3638E95897D39C327B7B1D13731348 Result: 1 Comparing signed: 1
Anyone can help about signing in C# in order to make the openssl_verify return 1? Thank you very much!