RSA integration between c# and php - c#

I want to send encrypted data to php as part of a c# project. The php page should decrypt the data and perform some operation on it ,then encrypt it again, and return it back to the c# application.
There is an issue with how the kyes look:
rsa private key:
uGUskwU/GVS1HjBVBa9ECPDRH04fH............
php private key:
-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDARufsW5Z9I+P96RdfDEq8r5XYaC ......
How can I integrate the two, or is there another class in C# I can use besides cryptography which would work?

Try using: http://phpseclib.sourceforge.net/
Generate keys:
openssl genrsa -out private.pem 1024
openssl rsa -in private.pem -out public.pem -outform PEM -pubout
Copy to php:
<?php
include('Crypt/RSA.php');
$privateKey="-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDr5KvAc6JX22BdpsfQbWam8rjkwJzTC954XQzhLOPeGiAGfkPm
CLYhBrmxZN6NxiseivpN9yzrRjYeccr+s3A/8q1EbdhmmM4+AxdNzATEsUxL//MS
VXCaoJhGOfXswokFT8HQod9M6VMmuyDaw9iEorLavV6J/nCmq2HIutcbbwIDAQAB
AoGBAMt2dgnN8zXSW2ELrIcDBapz6rQrylhigWXR5H0IKhb087CGEeyEkQsVcO8o
MKmaRrDWcKT00IKyEZXa0pszjFmD6f90H6TrV6BwZKEynAUVqaX4CCn6x9wgppMA
hWg3eYgoUME3Xgr1Iugb4rqtocEL7Vww/NoUgLXhzHH4RNz5AkEA+mZN2189Te3m
LmXFIJhV+GxrDmYrgJ0csjoEFHAxKJ52lsXTe1VODWbGWAv59jOrbUKe/aQaj4N1
IcTinF3jBQJBAPErTwBKvHznU9dC0eY+JRpwm4Xb9zCNqaG/Ir5N8Gc1U0YLJh9D
vRhtyT9+shwRPznklkc8DKwFaEU7HSiw9uMCQGLK9FLmG6jggN2zd3gpwlmWZRK0
StueoVDMRQnPTgXpp35LJOpXOMle0EiyyPdTYYJlM5d9JKGUyyT8qi/pdwUCQQCE
jp9vs6SCqsukh+/DM+lE7RwuqUbnAxZ39wzruP8oW2EYIMylZqArKzzwj3zqfHha
I9CN+u2kJ5y2YNWYJhytAkA53cDUSL9Wo9pq5hw1C1SWNcimteeQmfQ8f0SMegDW
fZ4rCjGczF82UpB12Cqo8SiK8xrCZAxfnSmSI248oCWe
-----END RSA PRIVATE KEY-----";
$publicKey="-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDr5KvAc6JX22BdpsfQbWam8rjk
wJzTC954XQzhLOPeGiAGfkPmCLYhBrmxZN6NxiseivpN9yzrRjYeccr+s3A/8q1E
bdhmmM4+AxdNzATEsUxL//MSVXCaoJhGOfXswokFT8HQod9M6VMmuyDaw9iEorLa
vV6J/nCmq2HIutcbbwIDAQAB
-----END PUBLIC KEY-----";
$rsa = new Crypt_RSA();
$rsa->loadKey($publicKey); // public key
$plaintext = 'I am a secret.. shhhhhh.';
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$ciphertext = $rsa->encrypt($plaintext);
$rsa->loadKey($privateKey); // private key
echo $rsa->decrypt($ciphertext);
?>
You can use different keys, but the php code must encrypt data using the C# public key and the C# code must use the php public key to encrypt data posted to the php code.
You can also have only two keys, one private and one public and use on both sides.
Take a look at this answer of doing this on the C# side: https://stackoverflow.com/a/1162519/2715306
And this: https://stackoverflow.com/a/251757/2715306

Related

X509 to Create JWT - "Cannot find the requested object"

I'll start by saying I know very little about cryptography. I know what public/private keys are in theory. I generated some using openSSL for Windows. My plan is to sign a JWT with the private key so it can be verified with the public key.
The lines I used to generate the keys are came from https://www.claudiobernasconi.ch/2016/04/17/creating-a-self-signed-x509-certificate-using-openssl-on-windows/
openssl genrsa 2048 > private.key
openssl req -new -x509 -nodes -sha1 -days 1000 -key private.key > public.cer
I opened the private key in notepad++ and copy/pasted the strings into a variable in C# (I tried removing line breaks, and keeping linebreaks with #"").
I try to create the x509 using the variable like so:
var x509 = new X509Certificate2( Convert.FromBase64String( privateKey ) );
However, I am getting a WindowsCryptographicException with the message "Cannot find the requested object".
I know what I want to do is possible, because we use that exact same line (with a different string) in our PROD code to read a JWT (I assume this string is my company's public key). If I pass that string into my x509 constructor, the cert generates successfully, but of course I can't sign the JWT with it because it knows it's public.
The x509 ctor also seems to be working for the author of this post: Trouble signing a JWT token with an x509 Certificate, but I can't get as far as him.
So, what am I doing wrong? What can't be found, and how do I "draw a map" to it?
==EDIT==
I thought there was enough of an example already, but I guess here you go:
using System;
using System.Security.Cryptography.X509Certificates;
namespace LocalTokenApi.JWT
{
public class JwtBuilder
{
public void GenerateJwt( string xmlUri )
{
var privateKey = #"
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDQrPEi4DwPJ65D
ZEybExHaslb2OZt+e/TRZAkO7LrlVf5aH7uiYYL42yGxhyBxQVbNDW8cAyD/r4o1
zRCCjBS1yk36YtZ+HzIc7X5c3YMmfC6k2r5GD6Ah9fkfhAbqzIiJo/GEJokCDkHS
tyniDDDnI6gteibuTRqS5qnA7YEhedqy5uOdb5TAKCLMCNJgkg9+lNTUPTg+D+Gj
94rSMJ9bpTEvU+sfta5UrDF2Owy15b9ExkELyJAWSTV/LcMrlhkZtkVQtNZM1xov
yNBPCu8+LsRnifjduS9MMh9z3RmnIE/MFl1XUnB/Ocf2HVQavP2U240kYrStVNz7
/twmPnUHAgMBAAECggEBAKw+Q9/ktM5Rk46+6FiMOg2JbSxaSpXxnReE+dEe5/nK
rGMZlFgpIuFkhwAxKD8zjoE82HyHvKIv8+YKuNj45VNUhF7rXF7IQyYLhmUC1nFa
yWl7wNi1pxjBHnu8D7WZVA5Ai2boI+jVedGDLIgQRgFTtkqrbB0A+bFNwcqkgBTv
MFYi8N5vJky3lnpivSY/hG7bOh9GacEDMqMy7aAe+15ppfHbzDcf5AUtHTwhtjc8
G/2VMdIUhozmz3b5XoSjuGeFSc/6CVsjKeLguRYr7Z4i0iaj89u60UPNwhxXTZlg
rrxfT7aZCgghSDLll/hH0Lqtwmd/ym9A2XRWxDabZtkCgYEA+Lt2P9CmoLun7/NN
i0IVnCaB4dpVaV7KgPtlWtE3oKB5wMhX18pJo5hB16UWfzBRRN3qL56iC1qJBAmW
pm/3ypcuzwm9PZrnPdb93cfWjW/GIMcK8oNUjpA2f/iLtZSO7iEua3Qtl1bJrJVv
MdVa+xdTViNR1TfhcJOnDmjH2mUCgYEA1sXaOYgi78S8m2LCyR5cJNTdW/7eBXVj
X48F1ZmpQGQ6+7258I43Gr2fHryAD9fidmi6YrRM+dDpk5FsIoVFK+Lqa4Oy79/y
oQt1HaByfvoBpDsCUY6yf/H4XhMUbZ/CF3tkceFvzBrrsAuuqh7OIsqe7hho9Sgd
/F8asP5exPsCgYA4wETtsISkPczGccPqlyxpEVwnFPLR9N/NaA6rFvtTOeots0hf
ovcETZQQSMmGQZb5WIy7Sr18S67hbfKijP+DiNUURguYh8RlFq2bsaHhaXRSPDfi
N1bOpFbbAfGWf4vRB18ZA0v3sMSZDQtu2lhE3ACWsb5VIMfeMMI4Bm47BQKBgQCP
/ljAB9D8lhepyj40HyHCI+FBg5ARctGsSLStr/c0z75n950Jdh/l0sozDkiB1sjj
gHWuJZoSR4nCwVYRku58bQekC8lVX/1JEeh0c5UwIqglFtcIHTb55x4Q3JPup5S2
r6j5XR7aZhYskriJIFwuIVEK6ty7uSjZgl3f2rtpLwKBgQC0BeuhdrQzrD8kg6cV
ZTvX12F5qJ1PFfbSpI9NwI5opqgCeGfUElEa32ig1v42taXNthWGGpFsUoSCoJG2
T2bDQ05TOItkg5/oVPJHS1ia26bxafTrXHtDoeuZ/G5oip2qULtQ62vUcazdsJ6x
zN6C1hsvJ4Kb3xPd2ZizjfDgAQ==";
var x509 = new X509Certificate2( Convert.FromBase64String( privateKey ) );
}
}
}
The data you provide to the constructor is not what the X509Certificate2 class expects. The X509Certificate2 expects the PKCS12 format.
In order to create data in the right format, the certificate including the private key as PKCS12, you missed one call to OpenSSL from the original source you linked to:
openssl pkcs12 -export -in public.cer -inkey private.key -out cert_key.p12
The data you have to pass to the X509Certificate2 constructor is then in the cert_key.p12 file. In case the private key is encrypted, you also have to specify the password as a second parameter to the X509Certificate2 constructor.

.net core get certificate private key to work with GRPC

I create a self sign certificate. Later I create a google GRPC server who needs a certificate and key file. I try to get the infos from a loaded .net certificate. I get the cert but I have problems with the key file. I dont get the correct key format from the stored cert.
That is only a shot example. Normally I want to store the cert in at the .net cert store and when the grpc service ic created I want to read the cert and key from the store. With that I will instantiate the service.
Cert creation:
openssl req -newkey rsa:4096 -x509 -sha256 -days 3650 -nodes -out myCert.crt -keyout myCert.key -config cert.conf
openssl pkcs12 -export -in myCert.crt -inkey myCert.key -out myCert.pfx -passin pass: -passout pass:
Then I load the cert as a .net certificate (normally I will get it from the store):
var cert = new X509Certificate2("myCert.pfx", "", X509KeyStorageFlags.Exportable);
// some stringbuild before to add -----BEGIN PRIVATE KEY-----
var privateKeyFromDotNetCert = Convert.ToBase64String(x509Certificate2.GetRSAPrivateKey().ExportRSAPrivateKey());
// for reference read the original key..only to shwo the problem
var serverkey = File.ReadAllText("myCert.key");
privateKeyFromDotNetCert is different to the original server key.
later I try to
var keypair = new KeyCertificatePair(cacert, serverkey);
var sslCredentials = new SslServerCredentials(new List<KeyCertificatePair> { keypair }, cacert, false);
with serverKey it works fine but not with the extracted key from the .net certificate. Is it possible to get the correct key from the .net certificate?
Cert creation from .net cert
With the first answer I tried:
StringBuilder builder = new StringBuilder();
builder.Append("-----BEGIN PRIVATE KEY-----");
builder.AppendLine(Convert.ToBase64String(certificate.GetRSAPrivateKey().ExportPkcs8PrivateKey(),Base64FormattingOptions.InsertLineBreaks));
builder.Append("-----END PRIVATE KEY-----");
privateKeyFromDotNetCert = builder.ToString();
This was working. privateKeyFromDotNetCert is not equal to serverkey. But accepted from the grpc service.
Your comment says you're prepending -----BEGIN PRIVATE KEY----- (and presumably appending -----END PRIVATE KEY-----), but the export method you chose (ExportRSAPrivateKey) doesn't match that format. Try ExportPkcs8PrivateKey, which exports in the PKCS#8 PrivateKeyInfo format, which matches the -----BEGIN PRIVATE KEY----- header. (ExportRSAPrivateKey produces a PKCS#1 RSAPrivateKey, which is -----BEGIN RSA PRIVATE KEY-----.)
You probably also want to use the Base64FormattingOptions.InsertLineBreaks option.

X509 Certificate format

When I do X509Certificate2 x509 = new X509Certificate2(certificateFile); what format does the certificate need to be in?
I have a private key:
-----BEGIN RSA PRIVATE KEY-----
......
-----END RSA PRIVATE KEY-----
and a certificate:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
..............
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=IL, ST=SS, L=...., O=....., OU=....., CN=...../emailAddress=.....
Validity
Not Before: Mar 19 14:45:09 2013 GMT
Not After : Mar 19 14:45:09 2014 GMT
Subject: C=IL, ST=SS, L=...., O=....., OU=....., CN=...../emailAddress=.....
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
...................
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
.........
X509v3 Authority Key Identifier:
keyid:..........
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha1WithRSAEncryption
.....
Yet I am able to load neither using the C# code above. What am I missing?
-----BEGIN RSA PRIVATE KEY----- is a header for an RSA Private Key in PKCS#1 format (unencrypted). This format is used in Private Key PEM files.
The .NET Framework does not offer any ready-made method to directly export a Private Key in this format so you have to implement it yourself.
This document can help you - there is an example of decoding a RSA Private Key. Encoding is just the reverse operation.

How can I add a private key to X509Certificate2 after I have already added the public key?

My steps are:
Create X509Certificate2 with public key:
X509Certificate2 clientCertificate = new X509Certificate2("public key certificate blob as byte[]");
How do I want to load the private key blob to clientCertificate?
It looks like you can not import RSA private key with just .net framework tools.
Check out this thread How to read a PEM RSA private key from .NET.
Just in case anyone like me and up looking at this old post when searching for how to generate X509Certificate2 from pem fil/private key:
The .Net 5.0 framework has a very simplified approach to this:
var certPem = File.ReadAllText("cert.pem");
var eccPem = File.ReadAllText("ecc.pem");
var cert = X509Certificate2.CreateFromPem(certPem, eccPem);
(source: https://www.scottbrady91.com/C-Sharp/PEM-Loading-in-dotnet-core-and-dotnet)
Also see: How to import PKCS#8 RSA privateKey (created by OpenSSL) in C#
It includes a link to Mono's source code which can read PKCS#8 / PEM files and return an RSA instance from it.

BouncyCastle create AsymmetricCipherKeyPair from existing keys?

I have two AssymetricAlgorithm RSA keys that I have pulled out of a certificate that was in my keystore. One is the Public Key and the other the Private. Is there a way of getting this keypair into a BouncyCastle AsymmetricCipherKeyPair? BouncyCastle's AsymmetricCipherKeyPair expects a public and private AsymmetricKeyParameter however I have no way of getting my Private key without it being an instance of AssymetricAlgorithm.
The answer to this lies here:
Get Private Key from BouncyCastle X509 Certificate? C#
I think this will help if key is marked as exportable
RSACryptoServiceProvider key = (RSACryptoServiceProvider)X509Certificate2object.PrivateKey;
RSAParameters rsaparam = key.ExportParameters(true);
AsymmetricCipherKeyPair keypair = DotNetUtilities.GetRsaKeyPair(rsaparam);

Categories