On the server, I have an PHP script (Laravel) that can generate RSA key pairs, flash them into the session, and return a base64 encoded public key, which will be used in my windows application to encrypt the password, and the key is created by calling the openssl_pkey_new function:
// get RSA key pairs
public function generateRSAKeyPairTest(Request $request)
{
$t = $this->microtime_float();
$res = openssl_pkey_new();
openssl_pkey_export($res, $privkeyraw);
$d= openssl_pkey_get_details($res);
$pubkeyraw = $d['key'];
$pubkey = base64_encode($pubkeyraw);
$privkey = base64_encode($privkeyraw);
$request->session()->flash('privkey', $privkey);
$request->session()->flash('pubkey', $pubkey);
$tdiff = $this->microtime_float() - $t;
$keypair = array('pubkey' => $pubkey,'diff' => $tdiff);
return response()->json($keypair);
}
// decode the encryted string
public function decryptRSATest(Request $request)
{
if ($request->session()->has('privkey'))
{
$privkey = $request->session()->get('privkey', 'default value');
$resPriv = openssl_pkey_get_private(base64_decode($privkey));
$encrypted_text_base64 = $request->encrypted_text;
$outval = '-';
$encrypted_text = base64_decode($encrypted_text_base64);
openssl_private_decrypt($encrypted_text, $outval, $resPriv);
return response()->json(
[
'decoded_text_from_clit'=>$outval
]
);
}
return response()->json(["error"=>"private key does not exist!"]);
}
then in my windows application (C#), I get the json from server and retrieve the public key
var data = Convert.FromBase64String(publicKeyStringBase64);
var publicKeyRaw = Encoding.UTF8.GetString(data);
var pkStr = publicKeyRaw.Replace("-----END PUBLIC KEY-----", "").Replace("-----BEGIN PUBLIC KEY-----", "");
var publicKey = Encoding.UTF8.GetBytes(pkStr);
the publicKeyRaw is like following (PKCS#8 format):
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwg6U1EET7OSbLO7UUZh 7p8ODYY4kXUd5S1Z/qexG5IqpNflrdQbpVh+8KWNi83oidAUjWEb050Rl3AuY/E6 7hYlEdUvI9pevmBpjjU1GktzQsDsbva3THHSpTZXPlctnFnuz0b5hVu1nUETmbGF fSbslZet3pbKcK5KGnJpm6v6OQGpvgQjyNWF16HjUD4/x1rAL2aDNOZZED+FNJcC hNmdK1A8nECk1JoTTdiK7r0EXMWxdVjEaSkAsvi7ywKi7ZESWwS1JmRuIJ5ZPiRx Fvur1tgaiomEZ+9oDpk1+bwDenrERYgBxw2L6Rw0CwuyinhwYfIbWkNmy4cAiZVx KwIDAQAB -----END PUBLIC KEY-----
I tried to use RSAParameters, but whether the Modulus is the raw byte array (data) or the array converted from the stripped string (publicKey), the encryptedText encrypted by using RSACryptoServiceProvider's Encrypt method cannot be decrypted by openssl_private_decrypt on the server.
var rsaInfo = new RSAParameters()
{
Exponent = new byte[] { 1, 0, 1 },
Modulus = data, // publicKey
};
var csp = new RSACryptoServiceProvider();
csp.ImportParameters(rsaInfo);
var password = "testing-passsword!";
var hash = csp.Encrypt(Encoding.UTF8.GetBytes(password), false);
var encryptedText = Convert.ToBase64String(hash);
I guess that RSACryptoServiceProvider does not encrypt the password correctly, so what is the correct way to use this key string (publicKeyRaw ) with the RSACryptoServiceProvider ?
[Update]
After doing a lot of searching work on google, the prolem becomes clear (just the same as what @James Reinstate Monica Polk mentions): the key generated by using openssl_pkey_new() is, by default, in PKCS#8 format, while RSACryptoServiceProvider only accepts the key in PKCS#1 v1.5 format. Such incompatibility caused this problem.
so, do you have any solutions for this?