AlejTech/Blog/ASP.NET openssl_sign a openssl_verify
Prejsť na navigáciu

ASP.NET openssl_sign a openssl_verify

ASP.NET openssl_sign a openssl_verify

Nedávno som dostal za úlohu implementovať online platobnú metódu GP webpay (www.gpe.cz). Túto metódu používa ČSOB a Volksbank banka. Jej súčasťou je podpisovanie SHA1 hashu reťazca pomocou RSA algoritmu.

V návode na implementáciu sa píše:

Calculating the electronic signature
Inputs: Data message (message), Private RSA key (with a K length module)
Outputs: Electronic signature (BASE64 encoded), approximate length K*1.5

The electronic signature is calculated as follows:

  1. The value of the function SHA-1 is derived from the message.
  2. The hash is encrypted into the input value for the RSA signature, using the EMSA-PKCS1-v1_5-ENCODE algorithm as described in paragraph 9.2.1.The following is the encryption: 01 | FF* | 00 | 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14 | hash where FF characters repeat as many times as necessary for the total length of the string to be one octet shorter than the key modulus. The character | is used for the strings concatenation.
  3. The RSA signature is calculated using the output value from b), as described in 8.1.1 RSASSA-PKCS1-V1_5-SIGN
  4. The output from c) is encoded using BASE64.

Na toto podpisovanie existuje v PHP jednoriadková funkcia openssl_sign(). V .NET ale žiadna takáto funkcia neexistuje. Nikde som ani nenašiel ako na to. Problém tiež bol, ako správne načitať vygenerovaný a zaheslovaný certifikát a ako z neho získať privátny kľúč.

PHP na tento účel využíva openssl knižnicu (http://www.openssl.org), pre ktorú našťastie existuje .NET port. Po preskúmaní zdrojového kódu PHP a niekoľkých hodinách trápenia sa s knižnicou ManagedOpenSsl sa mi konečne podarilo správne podpisovať a verifikovať reťazec. Prikladám funkčné demo aj so zdrojovými kódmi.

Demo openssl_sign, a Stiahite si zdrojový kód (.zip 1,4 MB).

Tento článok zahŕňa témy:
openssl_sign, openssl_verify, RSA, algoritmus, SHA1,c#, čsob, platobné, metódy

Komentáre (10)

pridať komentár


V komentároch môžete používať BB kód .

Komentár č. 1autor: Tom7.12.2010, 13:52

zajímáve...hned to jdu vyzkoušet

Komentár č. 2autor: Michal23.3.2011, 12:33

Dobrý deň, presne túto vec teraz riešime u nás. Som veľmi rád že som našiel takýto článok. Akurát sa mi stále nedarí vyhotoviť úspešný podpis. Skúšam hľadať chybu na všetkých miestach a začínam byť zúfalý :-) Vo vašom zdrojáku používate 'pem' formát privátného kľúča uchovaný v reťazci. Ako ste ho získal? Keď si totižto vygenerujem PEM súbor z PFX, v tých ohraničujúcich tagoch mi chýba slovo RSA, tj. presné znenie textu ktorý sa mi podarilo vygenerovať je : -----BEGIN PRIVATE KEY----- . Nemôže byť problém v tom, že nejak nesprávne používam privátny kľúč ?

Komentár č. 3autor: Marek23.3.2011, 12:53

Banka k tomu poskytla Java aplikaciu na generovanie certifikatu, a ta rovno vyplula ten PEM v takej forme (GenCert.jar). Ono je to tak potrebne pre PHP implementaciu, takze preto to tak aj generovalo.

Ja som s tym inak bojoval 2 dni a tiez som bol zufaly, takze to k tomu asi patri :)

Komentár č. 4autor: Michal 23.3.2011, 15:31

Nie som si istý, či rozumiem tomu poslednému čo ste napísali. :-) Myslíte si že problém môže robiť i 'nesprávne' vygenerovaný PEM súbor ? (Generoval som ho z PFX originálu)

Komentár č. 5autor: Marek23.3.2011, 15:48

No ak ten PEM certifikat nie je spravneho typu tak urcite.
Ja som ten svoj generoval Java aplikaciou dodanou od banky.

Orcite by sa dal vygenerovat aj cez OpenSSL z PFX, ale neviem ako.

Komentár č. 6autor: peto (web)11.4.2012, 21:05

Ja som ten môj generoval aplikáciou JAVA dodanou od banky a všetko je OK

Komentár č. 7autor: Anton17.10.2014, 13:25

Da se to pouzit i bez openssl (pfx soubor)

public string SHASign(string txt, string password, string path)
{
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
X509Certificate2 cert = new X509Certificate2(path, password,X509KeyStorageFlags.MachineKeySet);
RSACryptoServiceProvider rsaCryptoIPT = (RSACryptoServiceProvider)cert.PrivateKey;
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] binData = encoder.GetBytes(txt);
byte[] binSignature = rsaCryptoIPT.SignData(binData, sha1);
return Convert.ToBase64String(binSignature);
}

public bool SHAValidateSign(string originalstring, string signature, string password, string path)
{
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
X509Certificate2 cert = new X509Certificate2(path, password, X509KeyStorageFlags.MachineKeySet);
RSACryptoServiceProvider rsaCryptoIPT = (RSACryptoServiceProvider)cert.PublicKey.Key;
ASCIIEncoding encoder = new ASCIIEncoding();
return rsaCryptoIPT.VerifyData(encoder.GetBytes(originalstring), CryptoConfig.MapNameToOID("SHA1"), Convert.FromBase64String(signature));
}

Komentár č. 8autor: Marek20.10.2014, 17:35

Anton, ďakujem.
Určite vyskúšam.

Komentár č. 9autor: Martin10.11.2014, 18:16

Dobry den, v prvom rade by som rad podakoval Antonovi za zdielanie uzitocneho kodu. Zaroven by som sa ale rad spytal na
parameter metody public bool SHAValidateSign(string originalstring, string signature, string password, string path).

Konkretne ide o parameter string signature. Odkial sa bere, aku hodnotu tam treba posielat ?

Komentár č. 10autor: farAo2.12.2014, 16:40

Nemá komunikaci asp.net s GP WebPay hotovou a k tomu ochoten jí za rozumný peníz prodat? Nabídku mi prosím pošlete na faraoo@mail.com

Poraďte sa s nami o službách, ktoré potrebujete. My vám pripravíme konkrétnu cenovú ponuku.

Kontaktujte nás

Chtěl bych vám poděkovat za vzornou spolupráci. S vytvořenými stránkami jsem osobně velmi spokojen a zejména jsem potěšen vaši rychlostí

Miroslav Červený
CIO .A.S.A. Česká republika