📜 ⬆️ ⬇️

Open SSl and .NET - data signature

Introduction


Good day! By fate, I had to work with one operator who was very fond of encrypting his data :) It seems that the task seemed trivial and quite ordinary - the RSA algorithm is popular and familiar to everyone, the implementation of cryptography is in .NET - I wrote a couple of lines and nobody asked you he sees :) But I thought so only until I began to write these same pair of lines ...

Task


So, what I had to do was: sign (sign) requests from our side, and decrypt signed requests sent by the partner using the RSA algorithm.

A few words about the signature : there are 2 keys public and private. Subscriber A encrypts the private key with a message and sends it to subscriber B. Subscriber B, having received this message and having the public key (which subscriber A sent), can verify that this message was sent by subscriber A. In general , there is enough information about Rsa, so I’ll stop here.

Encryption tools


In my case, the “client” used the popular Open SSL program, which allows doing a lot of things with encryption, including signing data. The program works as follows: it accepts a file as input, a key and issues a signed message. Verification works in a similar way: it receives the encrypted file, the public key and, if successful, outputs a file with the decrypted message.
To implement RSA signature in .NET, there is a very convenient RSACryptoServiceProvider class that allows you to do encryption and signing. Everything would be fine, until it turned out that the concept of a signature on these implementations is very different ... :( I had to spend a single hour searching on the Internet, but I didn’t have any information. Although people saw complaints often about the incompatibility of implementations. The main point is that OpenSSL inserts the data itself (as encryption) into the signature, and .NET only signs it (logically). I found only 1 C # library , which contains the OpenSSL implementation, but it turned out to be paid. However, the main difference between the implementations is written there:
OpenSSL rsautl is very different. Here's what it does:
1. The input data is not hashed. It can be padded and signed. PKCS v1.5 padding is always used. The data is not ASN.1 encoded before padding.
2. The PKCS v1.5 padded data is RSA signed and the signature is returned.
Almost desperate and even writing a wrapper for OpenSSL, I stumbled upon one good link: the OPEN SSL NET project - i.e. a wrapper for OpenSSL, or rather the libraries it uses - libeay32.dll and ssleay32.dll . But, as it turned out, not everything was obvious there, but digging among C # classes was still easier than implementing the source code itself with C :) After talking with the author of the library, he wrote a wrapper class that contains signature and verification methods similar to OpenSSL.
')
Just in case, I’ll give an example of working with the OpenSSL utility so that those interested do not waste time on -help :)
Signature: openssl rsautl -inkey priv.key -in temp.txt -out temp.bin -sign ,
Verification: openssl rsautl -pubin -inkey pub.key -in temp2.bin -out result2.txt -verify
So, the code itself:

Emulator class RsaUtl OpenSSL


I think the comments to the code itself are superfluous. I included this class myself in the OpenSSL.NET assembly, but it can be used with the same success outside it. Successful work requires libraries libeay32.dll, ssleay32.dll (and if you use outside the assembly, then ManagedOpenSsl.dll). Briefly about the class: loads the keys in pem format and then signs / verifies the data. I made an overload so that the key could be specified as the path to the file, or simply byte [].

using System;
using System.Collections. Generic ;
using System.Text;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using OpenSSL;

namespace Rsautl
{
/// <summary>
/// Openssl -rsautl
/// </summary>
public static class Rsautl
{
private static RSA ReadPrivateKey( string path)
{
Stream s = File .Open(path, FileMode .Open);
byte [] pk = new byte [s.Length];
s.Read(pk, 0, pk.Length);
s.Close();
BIO b = new BIO(pk);
return RSA.FromPrivateKey(b);

}
private static RSA ReadPrivateKey( byte [] path)
{
BIO b = new BIO(path);
return RSA.FromPrivateKey(b);

}
private static RSA ReadPubKey( string path)
{
Stream s = File .Open(path, FileMode .Open);
byte [] pk = new byte [s.Length];
s.Read(pk, 0, pk.Length);
s.Close();
BIO b = new BIO(pk);
return RSA.FromPublicKey(b);
}
private static RSA ReadPubKey( byte [] path)
{
BIO b = new BIO(path);
return RSA.FromPublicKey(b);
}

#region
public static byte [] RsaUtlSignData( byte [] data, string privatekeypath)
{
RSA key = ReadPrivateKey(privatekeypath);
return key.PrivateEncrypt(data,RSA.Padding.PKCS1);
}
public static byte [] RsaUtlSignData( byte [] data, byte [] privatekey)
{
RSA key = ReadPrivateKey(privatekey);
return key.PrivateEncrypt(data, RSA.Padding.PKCS1);

}
#endregion

#region
public static byte [] RsaUtlVerifyData( byte [] sign, string pathtopublickey)
{
RSA key = ReadPubKey(pathtopublickey);
return key.PublicDecrypt(sign, RSA.Padding.PKCS1);
}
public static byte [] RsaUtlVerifyData( byte [] sign, byte [] publickey)
{
RSA key = ReadPubKey(publickey);
return key.PublicDecrypt(sign, RSA.Padding.PKCS1);
}
#endregion

}
}

* This source code was highlighted with Source Code Highlighter .


Conclusion


I hope this article will be useful to someone and save your valuable time. Just do not say that you can do it all in 1 minute - I don’t believe :) But if there is still a way to sign data in NET without third-party libraries, it’s compatible with OpenSSL please write !!!
PS please argue the evaluation of the article;)
PS2 if anyone is interested, I can write an article about how I struggled with OpenPGP =) There's a similar story ... :)

Source: https://habr.com/ru/post/68591/


All Articles